diff --git a/media/libaom/README_MCP b/media/libaom/README_MCP index 59e7c3d8c2..ad04810a30 100644 --- a/media/libaom/README_MCP +++ b/media/libaom/README_MCP @@ -1,6 +1,5 @@ This directory contains build files for the aom video -codec reference implementation. The actual library -source is in $TOPSRCDIR/third_party/aom/ +codec reference implementation. Any patches or additional configuration to be applied to the upstream source should be kept here in the media/libaom @@ -10,4 +9,4 @@ The upstream aom git repository is: https://aomedia.googlesource.com/aom -The git commit ID used was 1f0a4746aa8bfcce3fe7fbd2092aef8fe247aef4. +The version used was tagged 2.0.2. diff --git a/media/libaom/aom_version.h b/media/libaom/aom_version.h index b791ef64dd..92de763be8 100644 --- a/media/libaom/aom_version.h +++ b/media/libaom/aom_version.h @@ -1,7 +1,7 @@ -#define VERSION_MAJOR 0 -#define VERSION_MINOR 1 -#define VERSION_PATCH 0 +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_PATCH 2 #define VERSION_EXTRA "" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v0.1.0" -#define VERSION_STRING " v0.1.0" +#define VERSION_STRING_NOSP "v2.0.2" +#define VERSION_STRING " v2.0.2" diff --git a/media/libaom/config/aom_version.h b/media/libaom/config/aom_version.h index b791ef64dd..92de763be8 100644 --- a/media/libaom/config/aom_version.h +++ b/media/libaom/config/aom_version.h @@ -1,7 +1,7 @@ -#define VERSION_MAJOR 0 -#define VERSION_MINOR 1 -#define VERSION_PATCH 0 +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_PATCH 2 #define VERSION_EXTRA "" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v0.1.0" -#define VERSION_STRING " v0.1.0" +#define VERSION_STRING_NOSP "v2.0.2" +#define VERSION_STRING " v2.0.2" diff --git a/media/libaom/config/generic/config/aom_config.asm b/media/libaom/config/generic/config/aom_config.asm index f5886de150..af2521fa4c 100644 --- a/media/libaom/config/generic/config/aom_config.asm +++ b/media/libaom/config/generic/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT equ 0 diff --git a/media/libaom/config/generic/config/aom_config.h b/media/libaom/config/generic/config/aom_config.h index ed26dd70e4..6e300df375 100644 --- a/media/libaom/config/generic/config/aom_config.h +++ b/media/libaom/config/generic/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/linux/arm/config/aom_config.asm b/media/libaom/config/linux/arm/config/aom_config.asm index d7ec509711..a5d8cc9b99 100644 --- a/media/libaom/config/linux/arm/config/aom_config.asm +++ b/media/libaom/config/linux/arm/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ .equ CONFIG_SIZE_LIMIT, 0 .equ CONFIG_SPATIAL_RESAMPLING, 1 .equ CONFIG_SPEED_STATS, 0 -.equ CONFIG_STATIC, 1 .equ CONFIG_SUPERRES_IN_RECODE, 1 +.equ CONFIG_TUNE_VMAF, 0 .equ CONFIG_WEBM_IO, 0 .equ DECODE_HEIGHT_LIMIT, 0 .equ DECODE_WIDTH_LIMIT, 0 diff --git a/media/libaom/config/linux/arm/config/aom_config.h b/media/libaom/config/linux/arm/config/aom_config.h index 74da7b2149..5fc909a91c 100644 --- a/media/libaom/config/linux/arm/config/aom_config.h +++ b/media/libaom/config/linux/arm/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/linux/arm/config/av1_rtcd.h b/media/libaom/config/linux/arm/config/av1_rtcd.h index eb89431bca..7a346efd26 100644 --- a/media/libaom/config/linux/arm/config/av1_rtcd.h +++ b/media/libaom/config/linux/arm/config/av1_rtcd.h @@ -77,7 +77,8 @@ extern "C" { #endif void av1_apply_selfguided_restoration_c(const uint8_t *dat, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf, int bit_depth, int highbd); -#define av1_apply_selfguided_restoration av1_apply_selfguided_restoration_c +void av1_apply_selfguided_restoration_neon(const uint8_t *dat, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf, int bit_depth, int highbd); +RTCD_EXTERN void (*av1_apply_selfguided_restoration)(const uint8_t *dat, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf, int bit_depth, int highbd); void av1_build_compound_diffwtd_mask_c(uint8_t *mask, DIFFWTD_MASK_TYPE mask_type, const uint8_t *src0, int src0_stride, const uint8_t *src1, int src1_stride, int h, int w); #define av1_build_compound_diffwtd_mask av1_build_compound_diffwtd_mask_c @@ -321,7 +322,12 @@ RTCD_EXTERN void (*av1_round_shift_array)(int32_t *arr, int size, int bit); int av1_selfguided_restoration_c(const uint8_t *dgd8, int width, int height, int dgd_stride, int32_t *flt0, int32_t *flt1, int flt_stride, int sgr_params_idx, int bit_depth, int highbd); -#define av1_selfguided_restoration av1_selfguided_restoration_c +int av1_selfguided_restoration_neon(const uint8_t *dgd8, int width, int height, + int dgd_stride, int32_t *flt0, int32_t *flt1, int flt_stride, + int sgr_params_idx, int bit_depth, int highbd); +RTCD_EXTERN int (*av1_selfguided_restoration)(const uint8_t *dgd8, int width, int height, + int dgd_stride, int32_t *flt0, int32_t *flt1, int flt_stride, + int sgr_params_idx, int bit_depth, int highbd); void av1_upsample_intra_edge_c(uint8_t *p, int sz); #define av1_upsample_intra_edge av1_upsample_intra_edge_c @@ -401,6 +407,8 @@ static void setup_rtcd_internal(void) (void)flags; + av1_apply_selfguided_restoration = av1_apply_selfguided_restoration_c; + if (flags & HAS_NEON) av1_apply_selfguided_restoration = av1_apply_selfguided_restoration_neon; av1_build_compound_diffwtd_mask_d16 = av1_build_compound_diffwtd_mask_d16_c; if (flags & HAS_NEON) av1_build_compound_diffwtd_mask_d16 = av1_build_compound_diffwtd_mask_d16_neon; av1_convolve_2d_copy_sr = av1_convolve_2d_copy_sr_c; @@ -423,6 +431,8 @@ static void setup_rtcd_internal(void) if (flags & HAS_NEON) av1_inv_txfm_add = av1_inv_txfm_add_neon; av1_round_shift_array = av1_round_shift_array_c; if (flags & HAS_NEON) av1_round_shift_array = av1_round_shift_array_neon; + av1_selfguided_restoration = av1_selfguided_restoration_c; + if (flags & HAS_NEON) av1_selfguided_restoration = av1_selfguided_restoration_neon; av1_warp_affine = av1_warp_affine_c; if (flags & HAS_NEON) av1_warp_affine = av1_warp_affine_neon; av1_wiener_convolve_add_src = av1_wiener_convolve_add_src_c; diff --git a/media/libaom/config/linux/ia32/config/aom_config.asm b/media/libaom/config/linux/ia32/config/aom_config.asm index c36455b11b..591f86e6c9 100644 --- a/media/libaom/config/linux/ia32/config/aom_config.asm +++ b/media/libaom/config/linux/ia32/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 a90ca6d246..d2e651f19b 100644 --- a/media/libaom/config/linux/ia32/config/aom_config.h +++ b/media/libaom/config/linux/ia32/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/linux/x64/config/aom_config.asm b/media/libaom/config/linux/x64/config/aom_config.asm index 2c7c3b0ea1..9ce9b2090e 100644 --- a/media/libaom/config/linux/x64/config/aom_config.asm +++ b/media/libaom/config/linux/x64/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 5b36be1099..12997ea4dd 100644 --- a/media/libaom/config/linux/x64/config/aom_config.h +++ b/media/libaom/config/linux/x64/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/mac/x64/config/aom_config.asm b/media/libaom/config/mac/x64/config/aom_config.asm index 2c7c3b0ea1..9ce9b2090e 100644 --- a/media/libaom/config/mac/x64/config/aom_config.asm +++ b/media/libaom/config/mac/x64/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 5b36be1099..12997ea4dd 100644 --- a/media/libaom/config/mac/x64/config/aom_config.h +++ b/media/libaom/config/mac/x64/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/win/ia32/config/aom_config.asm b/media/libaom/config/win/ia32/config/aom_config.asm index 58f1067c72..baf05cb910 100644 --- a/media/libaom/config/win/ia32/config/aom_config.asm +++ b/media/libaom/config/win/ia32/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 90641518df..fc1271c743 100644 --- a/media/libaom/config/win/ia32/config/aom_config.h +++ b/media/libaom/config/win/ia32/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/win/mingw32/config/aom_config.asm b/media/libaom/config/win/mingw32/config/aom_config.asm index 58f1067c72..baf05cb910 100644 --- a/media/libaom/config/win/mingw32/config/aom_config.asm +++ b/media/libaom/config/win/mingw32/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 90641518df..fc1271c743 100644 --- a/media/libaom/config/win/mingw32/config/aom_config.h +++ b/media/libaom/config/win/mingw32/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/win/mingw64/config/aom_config.asm b/media/libaom/config/win/mingw64/config/aom_config.asm index 2c7c3b0ea1..9ce9b2090e 100644 --- a/media/libaom/config/win/mingw64/config/aom_config.asm +++ b/media/libaom/config/win/mingw64/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 5b36be1099..12997ea4dd 100644 --- a/media/libaom/config/win/mingw64/config/aom_config.h +++ b/media/libaom/config/win/mingw64/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/config/win/x64/config/aom_config.asm b/media/libaom/config/win/x64/config/aom_config.asm index 2c7c3b0ea1..9ce9b2090e 100644 --- a/media/libaom/config/win/x64/config/aom_config.asm +++ b/media/libaom/config/win/x64/config/aom_config.asm @@ -1,5 +1,5 @@ ; -; Copyright (c) 2019, Alliance for Open Media. All rights reserved +; Copyright (c) 2021, Alliance for Open Media. All rights reserved ; ; This source code is subject to the terms of the BSD 2 Clause License and ; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -54,8 +54,8 @@ CONFIG_SHARP_SETTINGS equ 0 CONFIG_SIZE_LIMIT equ 0 CONFIG_SPATIAL_RESAMPLING equ 1 CONFIG_SPEED_STATS equ 0 -CONFIG_STATIC equ 1 CONFIG_SUPERRES_IN_RECODE equ 1 +CONFIG_TUNE_VMAF equ 0 CONFIG_WEBM_IO equ 0 DECODE_HEIGHT_LIMIT equ 0 DECODE_WIDTH_LIMIT 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 5b36be1099..12997ea4dd 100644 --- a/media/libaom/config/win/x64/config/aom_config.h +++ b/media/libaom/config/win/x64/config/aom_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Alliance for Open Media. All rights reserved + * Copyright (c) 2021, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License @@ -56,8 +56,8 @@ #define CONFIG_SIZE_LIMIT 0 #define CONFIG_SPATIAL_RESAMPLING 1 #define CONFIG_SPEED_STATS 0 -#define CONFIG_STATIC 1 #define CONFIG_SUPERRES_IN_RECODE 1 +#define CONFIG_TUNE_VMAF 0 #define CONFIG_WEBM_IO 0 #define DECODE_HEIGHT_LIMIT 0 #define DECODE_WIDTH_LIMIT 0 diff --git a/media/libaom/generate_sources_mozbuild.py b/media/libaom/generate_sources_mozbuild.py index 180837b248..2f89c99488 100644 --- a/media/libaom/generate_sources_mozbuild.py +++ b/media/libaom/generate_sources_mozbuild.py @@ -9,7 +9,7 @@ import os import re import subprocess -AOM_DIR = '../../media/libaom/src' +AOM_DIR = '/media/libaom/src' def write_aom_config(system, arch, variables, cache_variables): # read template cmake file diff --git a/media/libaom/generate_sources_mozbuild.sh b/media/libaom/generate_sources_mozbuild.sh index 662eeb6077..d712d145d7 100755 --- a/media/libaom/generate_sources_mozbuild.sh +++ b/media/libaom/generate_sources_mozbuild.sh @@ -15,7 +15,7 @@ export LC_ALL=C BASE_DIR=$(pwd) -LIBAOM_SRC_DIR="../../media/libaom/src" +LIBAOM_SRC_DIR="/media/libaom/src" LIBAOM_CONFIG_DIR="config" # Print license header. diff --git a/media/libaom/sources.mozbuild b/media/libaom/sources.mozbuild index ff91ede846..e6ddf7b79d 100644 --- a/media/libaom/sources.mozbuild +++ b/media/libaom/sources.mozbuild @@ -2,543 +2,543 @@ files = { 'ARM_EXPORTS': [ - '../../media/libaom/src/aom/aom.h', - '../../media/libaom/src/aom/aom_codec.h', - '../../media/libaom/src/aom/aom_decoder.h', - '../../media/libaom/src/aom/aom_encoder.h', - '../../media/libaom/src/aom/aom_frame_buffer.h', - '../../media/libaom/src/aom/aom_image.h', - '../../media/libaom/src/aom/aom_integer.h', - '../../media/libaom/src/aom/aomcx.h', - '../../media/libaom/src/aom/aomdx.h', - '../../media/libaom/src/aom_mem/aom_mem.h', - '../../media/libaom/src/aom_ports/aom_timer.h', - '../../media/libaom/src/aom_ports/arm.h', - '../../media/libaom/src/aom_ports/bitops.h', - '../../media/libaom/src/aom_ports/mem.h', - '../../media/libaom/src/aom_ports/sanitizer.h', - '../../media/libaom/src/aom_ports/system_state.h', - '../../media/libaom/src/aom_scale/aom_scale.h', - '../../media/libaom/src/aom_scale/yv12config.h', + '/media/libaom/src/aom/aom.h', + '/media/libaom/src/aom/aom_codec.h', + '/media/libaom/src/aom/aom_decoder.h', + '/media/libaom/src/aom/aom_encoder.h', + '/media/libaom/src/aom/aom_frame_buffer.h', + '/media/libaom/src/aom/aom_image.h', + '/media/libaom/src/aom/aom_integer.h', + '/media/libaom/src/aom/aomcx.h', + '/media/libaom/src/aom/aomdx.h', + '/media/libaom/src/aom_mem/aom_mem.h', + '/media/libaom/src/aom_ports/aom_timer.h', + '/media/libaom/src/aom_ports/arm.h', + '/media/libaom/src/aom_ports/bitops.h', + '/media/libaom/src/aom_ports/mem.h', + '/media/libaom/src/aom_ports/sanitizer.h', + '/media/libaom/src/aom_ports/system_state.h', + '/media/libaom/src/aom_scale/aom_scale.h', + '/media/libaom/src/aom_scale/yv12config.h', ], 'ARM_SOURCES': [ - '../../media/libaom/src/aom/src/aom_codec.c', - '../../media/libaom/src/aom/src/aom_decoder.c', - '../../media/libaom/src/aom/src/aom_encoder.c', - '../../media/libaom/src/aom/src/aom_image.c', - '../../media/libaom/src/aom/src/aom_integer.c', - '../../media/libaom/src/aom_dsp/aom_convolve.c', - '../../media/libaom/src/aom_dsp/aom_dsp_rtcd.c', - '../../media/libaom/src/aom_dsp/arm/blend_a64_mask_neon.c', - '../../media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c', - '../../media/libaom/src/aom_dsp/arm/intrapred_neon.c', - '../../media/libaom/src/aom_dsp/arm/loopfilter_neon.c', - '../../media/libaom/src/aom_dsp/arm/subtract_neon.c', - '../../media/libaom/src/aom_dsp/avg.c', - '../../media/libaom/src/aom_dsp/binary_codes_reader.c', - '../../media/libaom/src/aom_dsp/bitreader_buffer.c', - '../../media/libaom/src/aom_dsp/bitwriter_buffer.c', - '../../media/libaom/src/aom_dsp/blend_a64_hmask.c', - '../../media/libaom/src/aom_dsp/blend_a64_mask.c', - '../../media/libaom/src/aom_dsp/blend_a64_vmask.c', - '../../media/libaom/src/aom_dsp/daalaboolreader.c', - '../../media/libaom/src/aom_dsp/entcode.c', - '../../media/libaom/src/aom_dsp/entdec.c', - '../../media/libaom/src/aom_dsp/fft.c', - '../../media/libaom/src/aom_dsp/grain_synthesis.c', - '../../media/libaom/src/aom_dsp/intrapred.c', - '../../media/libaom/src/aom_dsp/loopfilter.c', - '../../media/libaom/src/aom_dsp/subtract.c', - '../../media/libaom/src/aom_mem/aom_mem.c', - '../../media/libaom/src/aom_ports/arm_cpudetect.c', - '../../media/libaom/src/aom_scale/aom_scale_rtcd.c', - '../../media/libaom/src/aom_scale/generic/aom_scale.c', - '../../media/libaom/src/aom_scale/generic/gen_scalers.c', - '../../media/libaom/src/aom_scale/generic/yv12config.c', - '../../media/libaom/src/aom_scale/generic/yv12extend.c', - '../../media/libaom/src/aom_util/aom_thread.c', - '../../media/libaom/src/aom_util/debug_util.c', - '../../media/libaom/src/av1/av1_dx_iface.c', - '../../media/libaom/src/av1/common/alloccommon.c', - '../../media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c', - '../../media/libaom/src/av1/common/arm/av1_txfm_neon.c', - '../../media/libaom/src/av1/common/arm/blend_a64_hmask_neon.c', - '../../media/libaom/src/av1/common/arm/blend_a64_vmask_neon.c', - '../../media/libaom/src/av1/common/arm/cfl_neon.c', - '../../media/libaom/src/av1/common/arm/convolve_neon.c', - '../../media/libaom/src/av1/common/arm/jnt_convolve_neon.c', - '../../media/libaom/src/av1/common/arm/reconinter_neon.c', - '../../media/libaom/src/av1/common/arm/selfguided_neon.c', - '../../media/libaom/src/av1/common/arm/warp_plane_neon.c', - '../../media/libaom/src/av1/common/arm/wiener_convolve_neon.c', - '../../media/libaom/src/av1/common/av1_inv_txfm1d.c', - '../../media/libaom/src/av1/common/av1_inv_txfm2d.c', - '../../media/libaom/src/av1/common/av1_loopfilter.c', - '../../media/libaom/src/av1/common/av1_rtcd.c', - '../../media/libaom/src/av1/common/av1_txfm.c', - '../../media/libaom/src/av1/common/blockd.c', - '../../media/libaom/src/av1/common/cdef.c', - '../../media/libaom/src/av1/common/cdef_block.c', - '../../media/libaom/src/av1/common/cdef_block_neon.c', - '../../media/libaom/src/av1/common/cfl.c', - '../../media/libaom/src/av1/common/convolve.c', - '../../media/libaom/src/av1/common/debugmodes.c', - '../../media/libaom/src/av1/common/entropy.c', - '../../media/libaom/src/av1/common/entropymode.c', - '../../media/libaom/src/av1/common/entropymv.c', - '../../media/libaom/src/av1/common/frame_buffers.c', - '../../media/libaom/src/av1/common/idct.c', - '../../media/libaom/src/av1/common/mvref_common.c', - '../../media/libaom/src/av1/common/obu_util.c', - '../../media/libaom/src/av1/common/odintrin.c', - '../../media/libaom/src/av1/common/pred_common.c', - '../../media/libaom/src/av1/common/quant_common.c', - '../../media/libaom/src/av1/common/reconinter.c', - '../../media/libaom/src/av1/common/reconintra.c', - '../../media/libaom/src/av1/common/resize.c', - '../../media/libaom/src/av1/common/restoration.c', - '../../media/libaom/src/av1/common/scale.c', - '../../media/libaom/src/av1/common/scan.c', - '../../media/libaom/src/av1/common/seg_common.c', - '../../media/libaom/src/av1/common/thread_common.c', - '../../media/libaom/src/av1/common/tile_common.c', - '../../media/libaom/src/av1/common/timing.c', - '../../media/libaom/src/av1/common/txb_common.c', - '../../media/libaom/src/av1/common/warped_motion.c', - '../../media/libaom/src/av1/decoder/decodeframe.c', - '../../media/libaom/src/av1/decoder/decodemv.c', - '../../media/libaom/src/av1/decoder/decoder.c', - '../../media/libaom/src/av1/decoder/decodetxb.c', - '../../media/libaom/src/av1/decoder/detokenize.c', - '../../media/libaom/src/av1/decoder/obu.c', - '../../media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c', - '../../media/libaom/src/av1/encoder/arm/neon/quantize_neon.c', + '/media/libaom/src/aom/src/aom_codec.c', + '/media/libaom/src/aom/src/aom_decoder.c', + '/media/libaom/src/aom/src/aom_encoder.c', + '/media/libaom/src/aom/src/aom_image.c', + '/media/libaom/src/aom/src/aom_integer.c', + '/media/libaom/src/aom_dsp/aom_convolve.c', + '/media/libaom/src/aom_dsp/aom_dsp_rtcd.c', + '/media/libaom/src/aom_dsp/arm/blend_a64_mask_neon.c', + '/media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c', + '/media/libaom/src/aom_dsp/arm/intrapred_neon.c', + '/media/libaom/src/aom_dsp/arm/loopfilter_neon.c', + '/media/libaom/src/aom_dsp/arm/subtract_neon.c', + '/media/libaom/src/aom_dsp/avg.c', + '/media/libaom/src/aom_dsp/binary_codes_reader.c', + '/media/libaom/src/aom_dsp/bitreader.c', + '/media/libaom/src/aom_dsp/bitreader_buffer.c', + '/media/libaom/src/aom_dsp/bitwriter_buffer.c', + '/media/libaom/src/aom_dsp/blend_a64_hmask.c', + '/media/libaom/src/aom_dsp/blend_a64_mask.c', + '/media/libaom/src/aom_dsp/blend_a64_vmask.c', + '/media/libaom/src/aom_dsp/entcode.c', + '/media/libaom/src/aom_dsp/entdec.c', + '/media/libaom/src/aom_dsp/fft.c', + '/media/libaom/src/aom_dsp/grain_synthesis.c', + '/media/libaom/src/aom_dsp/intrapred.c', + '/media/libaom/src/aom_dsp/loopfilter.c', + '/media/libaom/src/aom_dsp/subtract.c', + '/media/libaom/src/aom_mem/aom_mem.c', + '/media/libaom/src/aom_ports/arm_cpudetect.c', + '/media/libaom/src/aom_scale/aom_scale_rtcd.c', + '/media/libaom/src/aom_scale/generic/aom_scale.c', + '/media/libaom/src/aom_scale/generic/gen_scalers.c', + '/media/libaom/src/aom_scale/generic/yv12config.c', + '/media/libaom/src/aom_scale/generic/yv12extend.c', + '/media/libaom/src/aom_util/aom_thread.c', + '/media/libaom/src/aom_util/debug_util.c', + '/media/libaom/src/av1/av1_dx_iface.c', + '/media/libaom/src/av1/common/alloccommon.c', + '/media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c', + '/media/libaom/src/av1/common/arm/av1_txfm_neon.c', + '/media/libaom/src/av1/common/arm/blend_a64_hmask_neon.c', + '/media/libaom/src/av1/common/arm/blend_a64_vmask_neon.c', + '/media/libaom/src/av1/common/arm/cfl_neon.c', + '/media/libaom/src/av1/common/arm/convolve_neon.c', + '/media/libaom/src/av1/common/arm/jnt_convolve_neon.c', + '/media/libaom/src/av1/common/arm/reconinter_neon.c', + '/media/libaom/src/av1/common/arm/selfguided_neon.c', + '/media/libaom/src/av1/common/arm/warp_plane_neon.c', + '/media/libaom/src/av1/common/arm/wiener_convolve_neon.c', + '/media/libaom/src/av1/common/av1_inv_txfm1d.c', + '/media/libaom/src/av1/common/av1_inv_txfm2d.c', + '/media/libaom/src/av1/common/av1_loopfilter.c', + '/media/libaom/src/av1/common/av1_rtcd.c', + '/media/libaom/src/av1/common/av1_txfm.c', + '/media/libaom/src/av1/common/blockd.c', + '/media/libaom/src/av1/common/cdef.c', + '/media/libaom/src/av1/common/cdef_block.c', + '/media/libaom/src/av1/common/cdef_block_neon.c', + '/media/libaom/src/av1/common/cfl.c', + '/media/libaom/src/av1/common/convolve.c', + '/media/libaom/src/av1/common/debugmodes.c', + '/media/libaom/src/av1/common/entropy.c', + '/media/libaom/src/av1/common/entropymode.c', + '/media/libaom/src/av1/common/entropymv.c', + '/media/libaom/src/av1/common/frame_buffers.c', + '/media/libaom/src/av1/common/idct.c', + '/media/libaom/src/av1/common/mvref_common.c', + '/media/libaom/src/av1/common/obu_util.c', + '/media/libaom/src/av1/common/odintrin.c', + '/media/libaom/src/av1/common/pred_common.c', + '/media/libaom/src/av1/common/quant_common.c', + '/media/libaom/src/av1/common/reconinter.c', + '/media/libaom/src/av1/common/reconintra.c', + '/media/libaom/src/av1/common/resize.c', + '/media/libaom/src/av1/common/restoration.c', + '/media/libaom/src/av1/common/scale.c', + '/media/libaom/src/av1/common/scan.c', + '/media/libaom/src/av1/common/seg_common.c', + '/media/libaom/src/av1/common/thread_common.c', + '/media/libaom/src/av1/common/tile_common.c', + '/media/libaom/src/av1/common/timing.c', + '/media/libaom/src/av1/common/txb_common.c', + '/media/libaom/src/av1/common/warped_motion.c', + '/media/libaom/src/av1/decoder/decodeframe.c', + '/media/libaom/src/av1/decoder/decodemv.c', + '/media/libaom/src/av1/decoder/decoder.c', + '/media/libaom/src/av1/decoder/decodetxb.c', + '/media/libaom/src/av1/decoder/detokenize.c', + '/media/libaom/src/av1/decoder/obu.c', + '/media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c', + '/media/libaom/src/av1/encoder/arm/neon/quantize_neon.c', ], 'GENERIC_EXPORTS': [ - '../../media/libaom/src/aom/aom.h', - '../../media/libaom/src/aom/aom_codec.h', - '../../media/libaom/src/aom/aom_decoder.h', - '../../media/libaom/src/aom/aom_encoder.h', - '../../media/libaom/src/aom/aom_frame_buffer.h', - '../../media/libaom/src/aom/aom_image.h', - '../../media/libaom/src/aom/aom_integer.h', - '../../media/libaom/src/aom/aomcx.h', - '../../media/libaom/src/aom/aomdx.h', - '../../media/libaom/src/aom_mem/aom_mem.h', - '../../media/libaom/src/aom_ports/aom_timer.h', - '../../media/libaom/src/aom_ports/bitops.h', - '../../media/libaom/src/aom_ports/mem.h', - '../../media/libaom/src/aom_ports/sanitizer.h', - '../../media/libaom/src/aom_ports/system_state.h', - '../../media/libaom/src/aom_scale/aom_scale.h', - '../../media/libaom/src/aom_scale/yv12config.h', + '/media/libaom/src/aom/aom.h', + '/media/libaom/src/aom/aom_codec.h', + '/media/libaom/src/aom/aom_decoder.h', + '/media/libaom/src/aom/aom_encoder.h', + '/media/libaom/src/aom/aom_frame_buffer.h', + '/media/libaom/src/aom/aom_image.h', + '/media/libaom/src/aom/aom_integer.h', + '/media/libaom/src/aom/aomcx.h', + '/media/libaom/src/aom/aomdx.h', + '/media/libaom/src/aom_mem/aom_mem.h', + '/media/libaom/src/aom_ports/aom_timer.h', + '/media/libaom/src/aom_ports/bitops.h', + '/media/libaom/src/aom_ports/mem.h', + '/media/libaom/src/aom_ports/sanitizer.h', + '/media/libaom/src/aom_ports/system_state.h', + '/media/libaom/src/aom_scale/aom_scale.h', + '/media/libaom/src/aom_scale/yv12config.h', ], 'GENERIC_SOURCES': [ - '../../media/libaom/src/aom/src/aom_codec.c', - '../../media/libaom/src/aom/src/aom_decoder.c', - '../../media/libaom/src/aom/src/aom_encoder.c', - '../../media/libaom/src/aom/src/aom_image.c', - '../../media/libaom/src/aom/src/aom_integer.c', - '../../media/libaom/src/aom_dsp/aom_convolve.c', - '../../media/libaom/src/aom_dsp/aom_dsp_rtcd.c', - '../../media/libaom/src/aom_dsp/avg.c', - '../../media/libaom/src/aom_dsp/binary_codes_reader.c', - '../../media/libaom/src/aom_dsp/bitreader_buffer.c', - '../../media/libaom/src/aom_dsp/bitwriter_buffer.c', - '../../media/libaom/src/aom_dsp/blend_a64_hmask.c', - '../../media/libaom/src/aom_dsp/blend_a64_mask.c', - '../../media/libaom/src/aom_dsp/blend_a64_vmask.c', - '../../media/libaom/src/aom_dsp/daalaboolreader.c', - '../../media/libaom/src/aom_dsp/entcode.c', - '../../media/libaom/src/aom_dsp/entdec.c', - '../../media/libaom/src/aom_dsp/fft.c', - '../../media/libaom/src/aom_dsp/grain_synthesis.c', - '../../media/libaom/src/aom_dsp/intrapred.c', - '../../media/libaom/src/aom_dsp/loopfilter.c', - '../../media/libaom/src/aom_dsp/subtract.c', - '../../media/libaom/src/aom_mem/aom_mem.c', - '../../media/libaom/src/aom_scale/aom_scale_rtcd.c', - '../../media/libaom/src/aom_scale/generic/aom_scale.c', - '../../media/libaom/src/aom_scale/generic/gen_scalers.c', - '../../media/libaom/src/aom_scale/generic/yv12config.c', - '../../media/libaom/src/aom_scale/generic/yv12extend.c', - '../../media/libaom/src/aom_util/aom_thread.c', - '../../media/libaom/src/aom_util/debug_util.c', - '../../media/libaom/src/av1/av1_dx_iface.c', - '../../media/libaom/src/av1/common/alloccommon.c', - '../../media/libaom/src/av1/common/av1_inv_txfm1d.c', - '../../media/libaom/src/av1/common/av1_inv_txfm2d.c', - '../../media/libaom/src/av1/common/av1_loopfilter.c', - '../../media/libaom/src/av1/common/av1_rtcd.c', - '../../media/libaom/src/av1/common/av1_txfm.c', - '../../media/libaom/src/av1/common/blockd.c', - '../../media/libaom/src/av1/common/cdef.c', - '../../media/libaom/src/av1/common/cdef_block.c', - '../../media/libaom/src/av1/common/cfl.c', - '../../media/libaom/src/av1/common/convolve.c', - '../../media/libaom/src/av1/common/debugmodes.c', - '../../media/libaom/src/av1/common/entropy.c', - '../../media/libaom/src/av1/common/entropymode.c', - '../../media/libaom/src/av1/common/entropymv.c', - '../../media/libaom/src/av1/common/frame_buffers.c', - '../../media/libaom/src/av1/common/idct.c', - '../../media/libaom/src/av1/common/mvref_common.c', - '../../media/libaom/src/av1/common/obu_util.c', - '../../media/libaom/src/av1/common/odintrin.c', - '../../media/libaom/src/av1/common/pred_common.c', - '../../media/libaom/src/av1/common/quant_common.c', - '../../media/libaom/src/av1/common/reconinter.c', - '../../media/libaom/src/av1/common/reconintra.c', - '../../media/libaom/src/av1/common/resize.c', - '../../media/libaom/src/av1/common/restoration.c', - '../../media/libaom/src/av1/common/scale.c', - '../../media/libaom/src/av1/common/scan.c', - '../../media/libaom/src/av1/common/seg_common.c', - '../../media/libaom/src/av1/common/thread_common.c', - '../../media/libaom/src/av1/common/tile_common.c', - '../../media/libaom/src/av1/common/timing.c', - '../../media/libaom/src/av1/common/txb_common.c', - '../../media/libaom/src/av1/common/warped_motion.c', - '../../media/libaom/src/av1/decoder/decodeframe.c', - '../../media/libaom/src/av1/decoder/decodemv.c', - '../../media/libaom/src/av1/decoder/decoder.c', - '../../media/libaom/src/av1/decoder/decodetxb.c', - '../../media/libaom/src/av1/decoder/detokenize.c', - '../../media/libaom/src/av1/decoder/obu.c', + '/media/libaom/src/aom/src/aom_codec.c', + '/media/libaom/src/aom/src/aom_decoder.c', + '/media/libaom/src/aom/src/aom_encoder.c', + '/media/libaom/src/aom/src/aom_image.c', + '/media/libaom/src/aom/src/aom_integer.c', + '/media/libaom/src/aom_dsp/aom_convolve.c', + '/media/libaom/src/aom_dsp/aom_dsp_rtcd.c', + '/media/libaom/src/aom_dsp/avg.c', + '/media/libaom/src/aom_dsp/binary_codes_reader.c', + '/media/libaom/src/aom_dsp/bitreader.c', + '/media/libaom/src/aom_dsp/bitreader_buffer.c', + '/media/libaom/src/aom_dsp/bitwriter_buffer.c', + '/media/libaom/src/aom_dsp/blend_a64_hmask.c', + '/media/libaom/src/aom_dsp/blend_a64_mask.c', + '/media/libaom/src/aom_dsp/blend_a64_vmask.c', + '/media/libaom/src/aom_dsp/entcode.c', + '/media/libaom/src/aom_dsp/entdec.c', + '/media/libaom/src/aom_dsp/fft.c', + '/media/libaom/src/aom_dsp/grain_synthesis.c', + '/media/libaom/src/aom_dsp/intrapred.c', + '/media/libaom/src/aom_dsp/loopfilter.c', + '/media/libaom/src/aom_dsp/subtract.c', + '/media/libaom/src/aom_mem/aom_mem.c', + '/media/libaom/src/aom_scale/aom_scale_rtcd.c', + '/media/libaom/src/aom_scale/generic/aom_scale.c', + '/media/libaom/src/aom_scale/generic/gen_scalers.c', + '/media/libaom/src/aom_scale/generic/yv12config.c', + '/media/libaom/src/aom_scale/generic/yv12extend.c', + '/media/libaom/src/aom_util/aom_thread.c', + '/media/libaom/src/aom_util/debug_util.c', + '/media/libaom/src/av1/av1_dx_iface.c', + '/media/libaom/src/av1/common/alloccommon.c', + '/media/libaom/src/av1/common/av1_inv_txfm1d.c', + '/media/libaom/src/av1/common/av1_inv_txfm2d.c', + '/media/libaom/src/av1/common/av1_loopfilter.c', + '/media/libaom/src/av1/common/av1_rtcd.c', + '/media/libaom/src/av1/common/av1_txfm.c', + '/media/libaom/src/av1/common/blockd.c', + '/media/libaom/src/av1/common/cdef.c', + '/media/libaom/src/av1/common/cdef_block.c', + '/media/libaom/src/av1/common/cfl.c', + '/media/libaom/src/av1/common/convolve.c', + '/media/libaom/src/av1/common/debugmodes.c', + '/media/libaom/src/av1/common/entropy.c', + '/media/libaom/src/av1/common/entropymode.c', + '/media/libaom/src/av1/common/entropymv.c', + '/media/libaom/src/av1/common/frame_buffers.c', + '/media/libaom/src/av1/common/idct.c', + '/media/libaom/src/av1/common/mvref_common.c', + '/media/libaom/src/av1/common/obu_util.c', + '/media/libaom/src/av1/common/odintrin.c', + '/media/libaom/src/av1/common/pred_common.c', + '/media/libaom/src/av1/common/quant_common.c', + '/media/libaom/src/av1/common/reconinter.c', + '/media/libaom/src/av1/common/reconintra.c', + '/media/libaom/src/av1/common/resize.c', + '/media/libaom/src/av1/common/restoration.c', + '/media/libaom/src/av1/common/scale.c', + '/media/libaom/src/av1/common/scan.c', + '/media/libaom/src/av1/common/seg_common.c', + '/media/libaom/src/av1/common/thread_common.c', + '/media/libaom/src/av1/common/tile_common.c', + '/media/libaom/src/av1/common/timing.c', + '/media/libaom/src/av1/common/txb_common.c', + '/media/libaom/src/av1/common/warped_motion.c', + '/media/libaom/src/av1/decoder/decodeframe.c', + '/media/libaom/src/av1/decoder/decodemv.c', + '/media/libaom/src/av1/decoder/decoder.c', + '/media/libaom/src/av1/decoder/decodetxb.c', + '/media/libaom/src/av1/decoder/detokenize.c', + '/media/libaom/src/av1/decoder/obu.c', ], 'IA32_EXPORTS': [ - '../../media/libaom/src/aom/aom.h', - '../../media/libaom/src/aom/aom_codec.h', - '../../media/libaom/src/aom/aom_decoder.h', - '../../media/libaom/src/aom/aom_encoder.h', - '../../media/libaom/src/aom/aom_frame_buffer.h', - '../../media/libaom/src/aom/aom_image.h', - '../../media/libaom/src/aom/aom_integer.h', - '../../media/libaom/src/aom/aomcx.h', - '../../media/libaom/src/aom/aomdx.h', - '../../media/libaom/src/aom_mem/aom_mem.h', - '../../media/libaom/src/aom_ports/aom_timer.h', - '../../media/libaom/src/aom_ports/bitops.h', - '../../media/libaom/src/aom_ports/mem.h', - '../../media/libaom/src/aom_ports/sanitizer.h', - '../../media/libaom/src/aom_ports/system_state.h', - '../../media/libaom/src/aom_scale/aom_scale.h', - '../../media/libaom/src/aom_scale/yv12config.h', + '/media/libaom/src/aom/aom.h', + '/media/libaom/src/aom/aom_codec.h', + '/media/libaom/src/aom/aom_decoder.h', + '/media/libaom/src/aom/aom_encoder.h', + '/media/libaom/src/aom/aom_frame_buffer.h', + '/media/libaom/src/aom/aom_image.h', + '/media/libaom/src/aom/aom_integer.h', + '/media/libaom/src/aom/aomcx.h', + '/media/libaom/src/aom/aomdx.h', + '/media/libaom/src/aom_mem/aom_mem.h', + '/media/libaom/src/aom_ports/aom_timer.h', + '/media/libaom/src/aom_ports/bitops.h', + '/media/libaom/src/aom_ports/mem.h', + '/media/libaom/src/aom_ports/sanitizer.h', + '/media/libaom/src/aom_ports/system_state.h', + '/media/libaom/src/aom_scale/aom_scale.h', + '/media/libaom/src/aom_scale/yv12config.h', ], 'IA32_SOURCES': [ - '../../media/libaom/src/aom/src/aom_codec.c', - '../../media/libaom/src/aom/src/aom_decoder.c', - '../../media/libaom/src/aom/src/aom_encoder.c', - '../../media/libaom/src/aom/src/aom_image.c', - '../../media/libaom/src/aom/src/aom_integer.c', - '../../media/libaom/src/aom_dsp/aom_convolve.c', - '../../media/libaom/src/aom_dsp/aom_dsp_rtcd.c', - '../../media/libaom/src/aom_dsp/avg.c', - '../../media/libaom/src/aom_dsp/binary_codes_reader.c', - '../../media/libaom/src/aom_dsp/bitreader_buffer.c', - '../../media/libaom/src/aom_dsp/bitwriter_buffer.c', - '../../media/libaom/src/aom_dsp/blend_a64_hmask.c', - '../../media/libaom/src/aom_dsp/blend_a64_mask.c', - '../../media/libaom/src/aom_dsp/blend_a64_vmask.c', - '../../media/libaom/src/aom_dsp/daalaboolreader.c', - '../../media/libaom/src/aom_dsp/entcode.c', - '../../media/libaom/src/aom_dsp/entdec.c', - '../../media/libaom/src/aom_dsp/fft.c', - '../../media/libaom/src/aom_dsp/grain_synthesis.c', - '../../media/libaom/src/aom_dsp/intrapred.c', - '../../media/libaom/src/aom_dsp/loopfilter.c', - '../../media/libaom/src/aom_dsp/subtract.c', - '../../media/libaom/src/aom_dsp/x86/aom_asm_stubs.c', - '../../media/libaom/src/aom_dsp/x86/aom_convolve_copy_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_high_subpixel_8t_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_high_subpixel_bilinear_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_avx2.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_ssse3.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_ssse3.asm', - '../../media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c', - '../../media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_hmask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_mask_avx2.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_mask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_vmask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/fft_avx2.c', - '../../media/libaom/src/aom_dsp/x86/fft_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_avx2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/highbd_intrapred_asm_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/highbd_intrapred_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_loopfilter_avx2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_loopfilter_sse2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_asm_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/intrapred_avx2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_sse2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/inv_wht_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/loopfilter_sse2.c', - '../../media/libaom/src/aom_mem/aom_mem.c', - '../../media/libaom/src/aom_ports/emms.asm', - '../../media/libaom/src/aom_ports/x86_abi_support.asm', - '../../media/libaom/src/aom_scale/aom_scale_rtcd.c', - '../../media/libaom/src/aom_scale/generic/aom_scale.c', - '../../media/libaom/src/aom_scale/generic/gen_scalers.c', - '../../media/libaom/src/aom_scale/generic/yv12config.c', - '../../media/libaom/src/aom_scale/generic/yv12extend.c', - '../../media/libaom/src/aom_util/aom_thread.c', - '../../media/libaom/src/aom_util/debug_util.c', - '../../media/libaom/src/av1/av1_dx_iface.c', - '../../media/libaom/src/av1/common/alloccommon.c', - '../../media/libaom/src/av1/common/av1_inv_txfm1d.c', - '../../media/libaom/src/av1/common/av1_inv_txfm2d.c', - '../../media/libaom/src/av1/common/av1_loopfilter.c', - '../../media/libaom/src/av1/common/av1_rtcd.c', - '../../media/libaom/src/av1/common/av1_txfm.c', - '../../media/libaom/src/av1/common/blockd.c', - '../../media/libaom/src/av1/common/cdef.c', - '../../media/libaom/src/av1/common/cdef_block.c', - '../../media/libaom/src/av1/common/cdef_block_avx2.c', - '../../media/libaom/src/av1/common/cdef_block_sse2.c', - '../../media/libaom/src/av1/common/cdef_block_sse4.c', - '../../media/libaom/src/av1/common/cdef_block_ssse3.c', - '../../media/libaom/src/av1/common/cfl.c', - '../../media/libaom/src/av1/common/convolve.c', - '../../media/libaom/src/av1/common/debugmodes.c', - '../../media/libaom/src/av1/common/entropy.c', - '../../media/libaom/src/av1/common/entropymode.c', - '../../media/libaom/src/av1/common/entropymv.c', - '../../media/libaom/src/av1/common/frame_buffers.c', - '../../media/libaom/src/av1/common/idct.c', - '../../media/libaom/src/av1/common/mvref_common.c', - '../../media/libaom/src/av1/common/obu_util.c', - '../../media/libaom/src/av1/common/odintrin.c', - '../../media/libaom/src/av1/common/pred_common.c', - '../../media/libaom/src/av1/common/quant_common.c', - '../../media/libaom/src/av1/common/reconinter.c', - '../../media/libaom/src/av1/common/reconintra.c', - '../../media/libaom/src/av1/common/resize.c', - '../../media/libaom/src/av1/common/restoration.c', - '../../media/libaom/src/av1/common/scale.c', - '../../media/libaom/src/av1/common/scan.c', - '../../media/libaom/src/av1/common/seg_common.c', - '../../media/libaom/src/av1/common/thread_common.c', - '../../media/libaom/src/av1/common/tile_common.c', - '../../media/libaom/src/av1/common/timing.c', - '../../media/libaom/src/av1/common/txb_common.c', - '../../media/libaom/src/av1/common/warped_motion.c', - '../../media/libaom/src/av1/common/x86/av1_convolve_horiz_rs_sse4.c', - '../../media/libaom/src/av1/common/x86/av1_convolve_scale_sse4.c', - '../../media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c', - '../../media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c', - '../../media/libaom/src/av1/common/x86/av1_txfm_sse4.c', - '../../media/libaom/src/av1/common/x86/cfl_avx2.c', - '../../media/libaom/src/av1/common/x86/cfl_sse2.c', - '../../media/libaom/src/av1/common/x86/cfl_ssse3.c', - '../../media/libaom/src/av1/common/x86/convolve_2d_avx2.c', - '../../media/libaom/src/av1/common/x86/convolve_2d_sse2.c', - '../../media/libaom/src/av1/common/x86/convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/convolve_sse2.c', - '../../media/libaom/src/av1/common/x86/filterintra_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_sse2.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_ssse3.c', - '../../media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_jnt_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_jnt_convolve_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_warp_plane_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_wiener_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_wiener_convolve_ssse3.c', - '../../media/libaom/src/av1/common/x86/intra_edge_sse4.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_sse2.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_ssse3.c', - '../../media/libaom/src/av1/common/x86/reconinter_avx2.c', - '../../media/libaom/src/av1/common/x86/reconinter_sse4.c', - '../../media/libaom/src/av1/common/x86/reconinter_ssse3.c', - '../../media/libaom/src/av1/common/x86/selfguided_avx2.c', - '../../media/libaom/src/av1/common/x86/selfguided_sse4.c', - '../../media/libaom/src/av1/common/x86/warp_plane_avx2.c', - '../../media/libaom/src/av1/common/x86/warp_plane_sse2.c', - '../../media/libaom/src/av1/common/x86/warp_plane_sse4.c', - '../../media/libaom/src/av1/common/x86/wiener_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/wiener_convolve_sse2.c', - '../../media/libaom/src/av1/decoder/decodeframe.c', - '../../media/libaom/src/av1/decoder/decodemv.c', - '../../media/libaom/src/av1/decoder/decoder.c', - '../../media/libaom/src/av1/decoder/decodetxb.c', - '../../media/libaom/src/av1/decoder/detokenize.c', - '../../media/libaom/src/av1/decoder/obu.c', + '/media/libaom/src/aom/src/aom_codec.c', + '/media/libaom/src/aom/src/aom_decoder.c', + '/media/libaom/src/aom/src/aom_encoder.c', + '/media/libaom/src/aom/src/aom_image.c', + '/media/libaom/src/aom/src/aom_integer.c', + '/media/libaom/src/aom_dsp/aom_convolve.c', + '/media/libaom/src/aom_dsp/aom_dsp_rtcd.c', + '/media/libaom/src/aom_dsp/avg.c', + '/media/libaom/src/aom_dsp/binary_codes_reader.c', + '/media/libaom/src/aom_dsp/bitreader.c', + '/media/libaom/src/aom_dsp/bitreader_buffer.c', + '/media/libaom/src/aom_dsp/bitwriter_buffer.c', + '/media/libaom/src/aom_dsp/blend_a64_hmask.c', + '/media/libaom/src/aom_dsp/blend_a64_mask.c', + '/media/libaom/src/aom_dsp/blend_a64_vmask.c', + '/media/libaom/src/aom_dsp/entcode.c', + '/media/libaom/src/aom_dsp/entdec.c', + '/media/libaom/src/aom_dsp/fft.c', + '/media/libaom/src/aom_dsp/grain_synthesis.c', + '/media/libaom/src/aom_dsp/intrapred.c', + '/media/libaom/src/aom_dsp/loopfilter.c', + '/media/libaom/src/aom_dsp/subtract.c', + '/media/libaom/src/aom_dsp/x86/aom_asm_stubs.c', + '/media/libaom/src/aom_dsp/x86/aom_convolve_copy_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_high_subpixel_8t_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_high_subpixel_bilinear_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_avx2.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_ssse3.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_ssse3.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_ssse3.asm', + '/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c', + '/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_hmask_sse4.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_mask_avx2.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_mask_sse4.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_vmask_sse4.c', + '/media/libaom/src/aom_dsp/x86/fft_avx2.c', + '/media/libaom/src/aom_dsp/x86/fft_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_avx2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_ssse3.c', + '/media/libaom/src/aom_dsp/x86/highbd_intrapred_asm_sse2.asm', + '/media/libaom/src/aom_dsp/x86/highbd_intrapred_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_loopfilter_avx2.c', + '/media/libaom/src/aom_dsp/x86/highbd_loopfilter_sse2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_asm_sse2.asm', + '/media/libaom/src/aom_dsp/x86/intrapred_avx2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_sse2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_ssse3.c', + '/media/libaom/src/aom_dsp/x86/inv_wht_sse2.asm', + '/media/libaom/src/aom_dsp/x86/loopfilter_sse2.c', + '/media/libaom/src/aom_mem/aom_mem.c', + '/media/libaom/src/aom_ports/emms.asm', + '/media/libaom/src/aom_ports/x86_abi_support.asm', + '/media/libaom/src/aom_scale/aom_scale_rtcd.c', + '/media/libaom/src/aom_scale/generic/aom_scale.c', + '/media/libaom/src/aom_scale/generic/gen_scalers.c', + '/media/libaom/src/aom_scale/generic/yv12config.c', + '/media/libaom/src/aom_scale/generic/yv12extend.c', + '/media/libaom/src/aom_util/aom_thread.c', + '/media/libaom/src/aom_util/debug_util.c', + '/media/libaom/src/av1/av1_dx_iface.c', + '/media/libaom/src/av1/common/alloccommon.c', + '/media/libaom/src/av1/common/av1_inv_txfm1d.c', + '/media/libaom/src/av1/common/av1_inv_txfm2d.c', + '/media/libaom/src/av1/common/av1_loopfilter.c', + '/media/libaom/src/av1/common/av1_rtcd.c', + '/media/libaom/src/av1/common/av1_txfm.c', + '/media/libaom/src/av1/common/blockd.c', + '/media/libaom/src/av1/common/cdef.c', + '/media/libaom/src/av1/common/cdef_block.c', + '/media/libaom/src/av1/common/cdef_block_avx2.c', + '/media/libaom/src/av1/common/cdef_block_sse2.c', + '/media/libaom/src/av1/common/cdef_block_sse4.c', + '/media/libaom/src/av1/common/cdef_block_ssse3.c', + '/media/libaom/src/av1/common/cfl.c', + '/media/libaom/src/av1/common/convolve.c', + '/media/libaom/src/av1/common/debugmodes.c', + '/media/libaom/src/av1/common/entropy.c', + '/media/libaom/src/av1/common/entropymode.c', + '/media/libaom/src/av1/common/entropymv.c', + '/media/libaom/src/av1/common/frame_buffers.c', + '/media/libaom/src/av1/common/idct.c', + '/media/libaom/src/av1/common/mvref_common.c', + '/media/libaom/src/av1/common/obu_util.c', + '/media/libaom/src/av1/common/odintrin.c', + '/media/libaom/src/av1/common/pred_common.c', + '/media/libaom/src/av1/common/quant_common.c', + '/media/libaom/src/av1/common/reconinter.c', + '/media/libaom/src/av1/common/reconintra.c', + '/media/libaom/src/av1/common/resize.c', + '/media/libaom/src/av1/common/restoration.c', + '/media/libaom/src/av1/common/scale.c', + '/media/libaom/src/av1/common/scan.c', + '/media/libaom/src/av1/common/seg_common.c', + '/media/libaom/src/av1/common/thread_common.c', + '/media/libaom/src/av1/common/tile_common.c', + '/media/libaom/src/av1/common/timing.c', + '/media/libaom/src/av1/common/txb_common.c', + '/media/libaom/src/av1/common/warped_motion.c', + '/media/libaom/src/av1/common/x86/av1_convolve_horiz_rs_sse4.c', + '/media/libaom/src/av1/common/x86/av1_convolve_scale_sse4.c', + '/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c', + '/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c', + '/media/libaom/src/av1/common/x86/av1_txfm_sse4.c', + '/media/libaom/src/av1/common/x86/cfl_avx2.c', + '/media/libaom/src/av1/common/x86/cfl_sse2.c', + '/media/libaom/src/av1/common/x86/cfl_ssse3.c', + '/media/libaom/src/av1/common/x86/convolve_2d_avx2.c', + '/media/libaom/src/av1/common/x86/convolve_2d_sse2.c', + '/media/libaom/src/av1/common/x86/convolve_avx2.c', + '/media/libaom/src/av1/common/x86/convolve_sse2.c', + '/media/libaom/src/av1/common/x86/filterintra_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_sse2.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_ssse3.c', + '/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_jnt_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_jnt_convolve_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_warp_plane_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_wiener_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_wiener_convolve_ssse3.c', + '/media/libaom/src/av1/common/x86/intra_edge_sse4.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_sse2.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_ssse3.c', + '/media/libaom/src/av1/common/x86/reconinter_avx2.c', + '/media/libaom/src/av1/common/x86/reconinter_sse4.c', + '/media/libaom/src/av1/common/x86/reconinter_ssse3.c', + '/media/libaom/src/av1/common/x86/selfguided_avx2.c', + '/media/libaom/src/av1/common/x86/selfguided_sse4.c', + '/media/libaom/src/av1/common/x86/warp_plane_avx2.c', + '/media/libaom/src/av1/common/x86/warp_plane_sse2.c', + '/media/libaom/src/av1/common/x86/warp_plane_sse4.c', + '/media/libaom/src/av1/common/x86/wiener_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/wiener_convolve_sse2.c', + '/media/libaom/src/av1/decoder/decodeframe.c', + '/media/libaom/src/av1/decoder/decodemv.c', + '/media/libaom/src/av1/decoder/decoder.c', + '/media/libaom/src/av1/decoder/decodetxb.c', + '/media/libaom/src/av1/decoder/detokenize.c', + '/media/libaom/src/av1/decoder/obu.c', ], 'X64_EXPORTS': [ - '../../media/libaom/src/aom/aom.h', - '../../media/libaom/src/aom/aom_codec.h', - '../../media/libaom/src/aom/aom_decoder.h', - '../../media/libaom/src/aom/aom_encoder.h', - '../../media/libaom/src/aom/aom_frame_buffer.h', - '../../media/libaom/src/aom/aom_image.h', - '../../media/libaom/src/aom/aom_integer.h', - '../../media/libaom/src/aom/aomcx.h', - '../../media/libaom/src/aom/aomdx.h', - '../../media/libaom/src/aom_mem/aom_mem.h', - '../../media/libaom/src/aom_ports/aom_timer.h', - '../../media/libaom/src/aom_ports/bitops.h', - '../../media/libaom/src/aom_ports/mem.h', - '../../media/libaom/src/aom_ports/sanitizer.h', - '../../media/libaom/src/aom_ports/system_state.h', - '../../media/libaom/src/aom_scale/aom_scale.h', - '../../media/libaom/src/aom_scale/yv12config.h', + '/media/libaom/src/aom/aom.h', + '/media/libaom/src/aom/aom_codec.h', + '/media/libaom/src/aom/aom_decoder.h', + '/media/libaom/src/aom/aom_encoder.h', + '/media/libaom/src/aom/aom_frame_buffer.h', + '/media/libaom/src/aom/aom_image.h', + '/media/libaom/src/aom/aom_integer.h', + '/media/libaom/src/aom/aomcx.h', + '/media/libaom/src/aom/aomdx.h', + '/media/libaom/src/aom_mem/aom_mem.h', + '/media/libaom/src/aom_ports/aom_timer.h', + '/media/libaom/src/aom_ports/bitops.h', + '/media/libaom/src/aom_ports/mem.h', + '/media/libaom/src/aom_ports/sanitizer.h', + '/media/libaom/src/aom_ports/system_state.h', + '/media/libaom/src/aom_scale/aom_scale.h', + '/media/libaom/src/aom_scale/yv12config.h', ], 'X64_SOURCES': [ - '../../media/libaom/src/aom/src/aom_codec.c', - '../../media/libaom/src/aom/src/aom_decoder.c', - '../../media/libaom/src/aom/src/aom_encoder.c', - '../../media/libaom/src/aom/src/aom_image.c', - '../../media/libaom/src/aom/src/aom_integer.c', - '../../media/libaom/src/aom_dsp/aom_convolve.c', - '../../media/libaom/src/aom_dsp/aom_dsp_rtcd.c', - '../../media/libaom/src/aom_dsp/avg.c', - '../../media/libaom/src/aom_dsp/binary_codes_reader.c', - '../../media/libaom/src/aom_dsp/bitreader_buffer.c', - '../../media/libaom/src/aom_dsp/bitwriter_buffer.c', - '../../media/libaom/src/aom_dsp/blend_a64_hmask.c', - '../../media/libaom/src/aom_dsp/blend_a64_mask.c', - '../../media/libaom/src/aom_dsp/blend_a64_vmask.c', - '../../media/libaom/src/aom_dsp/daalaboolreader.c', - '../../media/libaom/src/aom_dsp/entcode.c', - '../../media/libaom/src/aom_dsp/entdec.c', - '../../media/libaom/src/aom_dsp/fft.c', - '../../media/libaom/src/aom_dsp/grain_synthesis.c', - '../../media/libaom/src/aom_dsp/intrapred.c', - '../../media/libaom/src/aom_dsp/loopfilter.c', - '../../media/libaom/src/aom_dsp/subtract.c', - '../../media/libaom/src/aom_dsp/x86/aom_asm_stubs.c', - '../../media/libaom/src/aom_dsp/x86/aom_convolve_copy_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_high_subpixel_8t_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_high_subpixel_bilinear_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_avx2.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_8t_ssse3.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_ssse3.asm', - '../../media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c', - '../../media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_hmask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_mask_avx2.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_mask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/blend_a64_vmask_sse4.c', - '../../media/libaom/src/aom_dsp/x86/fft_avx2.c', - '../../media/libaom/src/aom_dsp/x86/fft_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_avx2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_convolve_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/highbd_intrapred_asm_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/highbd_intrapred_sse2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_loopfilter_avx2.c', - '../../media/libaom/src/aom_dsp/x86/highbd_loopfilter_sse2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_asm_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/intrapred_avx2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_sse2.c', - '../../media/libaom/src/aom_dsp/x86/intrapred_ssse3.c', - '../../media/libaom/src/aom_dsp/x86/inv_wht_sse2.asm', - '../../media/libaom/src/aom_dsp/x86/loopfilter_sse2.c', - '../../media/libaom/src/aom_mem/aom_mem.c', - '../../media/libaom/src/aom_ports/emms.asm', - '../../media/libaom/src/aom_scale/aom_scale_rtcd.c', - '../../media/libaom/src/aom_scale/generic/aom_scale.c', - '../../media/libaom/src/aom_scale/generic/gen_scalers.c', - '../../media/libaom/src/aom_scale/generic/yv12config.c', - '../../media/libaom/src/aom_scale/generic/yv12extend.c', - '../../media/libaom/src/aom_util/aom_thread.c', - '../../media/libaom/src/aom_util/debug_util.c', - '../../media/libaom/src/av1/av1_dx_iface.c', - '../../media/libaom/src/av1/common/alloccommon.c', - '../../media/libaom/src/av1/common/av1_inv_txfm1d.c', - '../../media/libaom/src/av1/common/av1_inv_txfm2d.c', - '../../media/libaom/src/av1/common/av1_loopfilter.c', - '../../media/libaom/src/av1/common/av1_rtcd.c', - '../../media/libaom/src/av1/common/av1_txfm.c', - '../../media/libaom/src/av1/common/blockd.c', - '../../media/libaom/src/av1/common/cdef.c', - '../../media/libaom/src/av1/common/cdef_block.c', - '../../media/libaom/src/av1/common/cdef_block_avx2.c', - '../../media/libaom/src/av1/common/cdef_block_sse2.c', - '../../media/libaom/src/av1/common/cdef_block_sse4.c', - '../../media/libaom/src/av1/common/cdef_block_ssse3.c', - '../../media/libaom/src/av1/common/cfl.c', - '../../media/libaom/src/av1/common/convolve.c', - '../../media/libaom/src/av1/common/debugmodes.c', - '../../media/libaom/src/av1/common/entropy.c', - '../../media/libaom/src/av1/common/entropymode.c', - '../../media/libaom/src/av1/common/entropymv.c', - '../../media/libaom/src/av1/common/frame_buffers.c', - '../../media/libaom/src/av1/common/idct.c', - '../../media/libaom/src/av1/common/mvref_common.c', - '../../media/libaom/src/av1/common/obu_util.c', - '../../media/libaom/src/av1/common/odintrin.c', - '../../media/libaom/src/av1/common/pred_common.c', - '../../media/libaom/src/av1/common/quant_common.c', - '../../media/libaom/src/av1/common/reconinter.c', - '../../media/libaom/src/av1/common/reconintra.c', - '../../media/libaom/src/av1/common/resize.c', - '../../media/libaom/src/av1/common/restoration.c', - '../../media/libaom/src/av1/common/scale.c', - '../../media/libaom/src/av1/common/scan.c', - '../../media/libaom/src/av1/common/seg_common.c', - '../../media/libaom/src/av1/common/thread_common.c', - '../../media/libaom/src/av1/common/tile_common.c', - '../../media/libaom/src/av1/common/timing.c', - '../../media/libaom/src/av1/common/txb_common.c', - '../../media/libaom/src/av1/common/warped_motion.c', - '../../media/libaom/src/av1/common/x86/av1_convolve_horiz_rs_sse4.c', - '../../media/libaom/src/av1/common/x86/av1_convolve_scale_sse4.c', - '../../media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c', - '../../media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c', - '../../media/libaom/src/av1/common/x86/av1_txfm_sse4.c', - '../../media/libaom/src/av1/common/x86/cfl_avx2.c', - '../../media/libaom/src/av1/common/x86/cfl_sse2.c', - '../../media/libaom/src/av1/common/x86/cfl_ssse3.c', - '../../media/libaom/src/av1/common/x86/convolve_2d_avx2.c', - '../../media/libaom/src/av1/common/x86/convolve_2d_sse2.c', - '../../media/libaom/src/av1/common/x86/convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/convolve_sse2.c', - '../../media/libaom/src/av1/common/x86/filterintra_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_sse2.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_convolve_2d_ssse3.c', - '../../media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_jnt_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_jnt_convolve_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_warp_plane_sse4.c', - '../../media/libaom/src/av1/common/x86/highbd_wiener_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/highbd_wiener_convolve_ssse3.c', - '../../media/libaom/src/av1/common/x86/intra_edge_sse4.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_sse2.c', - '../../media/libaom/src/av1/common/x86/jnt_convolve_ssse3.c', - '../../media/libaom/src/av1/common/x86/reconinter_avx2.c', - '../../media/libaom/src/av1/common/x86/reconinter_sse4.c', - '../../media/libaom/src/av1/common/x86/reconinter_ssse3.c', - '../../media/libaom/src/av1/common/x86/selfguided_avx2.c', - '../../media/libaom/src/av1/common/x86/selfguided_sse4.c', - '../../media/libaom/src/av1/common/x86/warp_plane_avx2.c', - '../../media/libaom/src/av1/common/x86/warp_plane_sse2.c', - '../../media/libaom/src/av1/common/x86/warp_plane_sse4.c', - '../../media/libaom/src/av1/common/x86/wiener_convolve_avx2.c', - '../../media/libaom/src/av1/common/x86/wiener_convolve_sse2.c', - '../../media/libaom/src/av1/decoder/decodeframe.c', - '../../media/libaom/src/av1/decoder/decodemv.c', - '../../media/libaom/src/av1/decoder/decoder.c', - '../../media/libaom/src/av1/decoder/decodetxb.c', - '../../media/libaom/src/av1/decoder/detokenize.c', - '../../media/libaom/src/av1/decoder/obu.c', + '/media/libaom/src/aom/src/aom_codec.c', + '/media/libaom/src/aom/src/aom_decoder.c', + '/media/libaom/src/aom/src/aom_encoder.c', + '/media/libaom/src/aom/src/aom_image.c', + '/media/libaom/src/aom/src/aom_integer.c', + '/media/libaom/src/aom_dsp/aom_convolve.c', + '/media/libaom/src/aom_dsp/aom_dsp_rtcd.c', + '/media/libaom/src/aom_dsp/avg.c', + '/media/libaom/src/aom_dsp/binary_codes_reader.c', + '/media/libaom/src/aom_dsp/bitreader.c', + '/media/libaom/src/aom_dsp/bitreader_buffer.c', + '/media/libaom/src/aom_dsp/bitwriter_buffer.c', + '/media/libaom/src/aom_dsp/blend_a64_hmask.c', + '/media/libaom/src/aom_dsp/blend_a64_mask.c', + '/media/libaom/src/aom_dsp/blend_a64_vmask.c', + '/media/libaom/src/aom_dsp/entcode.c', + '/media/libaom/src/aom_dsp/entdec.c', + '/media/libaom/src/aom_dsp/fft.c', + '/media/libaom/src/aom_dsp/grain_synthesis.c', + '/media/libaom/src/aom_dsp/intrapred.c', + '/media/libaom/src/aom_dsp/loopfilter.c', + '/media/libaom/src/aom_dsp/subtract.c', + '/media/libaom/src/aom_dsp/x86/aom_asm_stubs.c', + '/media/libaom/src/aom_dsp/x86/aom_convolve_copy_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_high_subpixel_8t_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_high_subpixel_bilinear_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_avx2.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_sse2.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_intrin_ssse3.c', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_8t_ssse3.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_sse2.asm', + '/media/libaom/src/aom_dsp/x86/aom_subpixel_bilinear_ssse3.asm', + '/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c', + '/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_hmask_sse4.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_mask_avx2.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_mask_sse4.c', + '/media/libaom/src/aom_dsp/x86/blend_a64_vmask_sse4.c', + '/media/libaom/src/aom_dsp/x86/fft_avx2.c', + '/media/libaom/src/aom_dsp/x86/fft_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_avx2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_convolve_ssse3.c', + '/media/libaom/src/aom_dsp/x86/highbd_intrapred_asm_sse2.asm', + '/media/libaom/src/aom_dsp/x86/highbd_intrapred_sse2.c', + '/media/libaom/src/aom_dsp/x86/highbd_loopfilter_avx2.c', + '/media/libaom/src/aom_dsp/x86/highbd_loopfilter_sse2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_asm_sse2.asm', + '/media/libaom/src/aom_dsp/x86/intrapred_avx2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_sse2.c', + '/media/libaom/src/aom_dsp/x86/intrapred_ssse3.c', + '/media/libaom/src/aom_dsp/x86/inv_wht_sse2.asm', + '/media/libaom/src/aom_dsp/x86/loopfilter_sse2.c', + '/media/libaom/src/aom_mem/aom_mem.c', + '/media/libaom/src/aom_ports/emms.asm', + '/media/libaom/src/aom_scale/aom_scale_rtcd.c', + '/media/libaom/src/aom_scale/generic/aom_scale.c', + '/media/libaom/src/aom_scale/generic/gen_scalers.c', + '/media/libaom/src/aom_scale/generic/yv12config.c', + '/media/libaom/src/aom_scale/generic/yv12extend.c', + '/media/libaom/src/aom_util/aom_thread.c', + '/media/libaom/src/aom_util/debug_util.c', + '/media/libaom/src/av1/av1_dx_iface.c', + '/media/libaom/src/av1/common/alloccommon.c', + '/media/libaom/src/av1/common/av1_inv_txfm1d.c', + '/media/libaom/src/av1/common/av1_inv_txfm2d.c', + '/media/libaom/src/av1/common/av1_loopfilter.c', + '/media/libaom/src/av1/common/av1_rtcd.c', + '/media/libaom/src/av1/common/av1_txfm.c', + '/media/libaom/src/av1/common/blockd.c', + '/media/libaom/src/av1/common/cdef.c', + '/media/libaom/src/av1/common/cdef_block.c', + '/media/libaom/src/av1/common/cdef_block_avx2.c', + '/media/libaom/src/av1/common/cdef_block_sse2.c', + '/media/libaom/src/av1/common/cdef_block_sse4.c', + '/media/libaom/src/av1/common/cdef_block_ssse3.c', + '/media/libaom/src/av1/common/cfl.c', + '/media/libaom/src/av1/common/convolve.c', + '/media/libaom/src/av1/common/debugmodes.c', + '/media/libaom/src/av1/common/entropy.c', + '/media/libaom/src/av1/common/entropymode.c', + '/media/libaom/src/av1/common/entropymv.c', + '/media/libaom/src/av1/common/frame_buffers.c', + '/media/libaom/src/av1/common/idct.c', + '/media/libaom/src/av1/common/mvref_common.c', + '/media/libaom/src/av1/common/obu_util.c', + '/media/libaom/src/av1/common/odintrin.c', + '/media/libaom/src/av1/common/pred_common.c', + '/media/libaom/src/av1/common/quant_common.c', + '/media/libaom/src/av1/common/reconinter.c', + '/media/libaom/src/av1/common/reconintra.c', + '/media/libaom/src/av1/common/resize.c', + '/media/libaom/src/av1/common/restoration.c', + '/media/libaom/src/av1/common/scale.c', + '/media/libaom/src/av1/common/scan.c', + '/media/libaom/src/av1/common/seg_common.c', + '/media/libaom/src/av1/common/thread_common.c', + '/media/libaom/src/av1/common/tile_common.c', + '/media/libaom/src/av1/common/timing.c', + '/media/libaom/src/av1/common/txb_common.c', + '/media/libaom/src/av1/common/warped_motion.c', + '/media/libaom/src/av1/common/x86/av1_convolve_horiz_rs_sse4.c', + '/media/libaom/src/av1/common/x86/av1_convolve_scale_sse4.c', + '/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c', + '/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c', + '/media/libaom/src/av1/common/x86/av1_txfm_sse4.c', + '/media/libaom/src/av1/common/x86/cfl_avx2.c', + '/media/libaom/src/av1/common/x86/cfl_sse2.c', + '/media/libaom/src/av1/common/x86/cfl_ssse3.c', + '/media/libaom/src/av1/common/x86/convolve_2d_avx2.c', + '/media/libaom/src/av1/common/x86/convolve_2d_sse2.c', + '/media/libaom/src/av1/common/x86/convolve_avx2.c', + '/media/libaom/src/av1/common/x86/convolve_sse2.c', + '/media/libaom/src/av1/common/x86/filterintra_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_sse2.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_convolve_2d_ssse3.c', + '/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_jnt_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_jnt_convolve_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_warp_plane_sse4.c', + '/media/libaom/src/av1/common/x86/highbd_wiener_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/highbd_wiener_convolve_ssse3.c', + '/media/libaom/src/av1/common/x86/intra_edge_sse4.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_sse2.c', + '/media/libaom/src/av1/common/x86/jnt_convolve_ssse3.c', + '/media/libaom/src/av1/common/x86/reconinter_avx2.c', + '/media/libaom/src/av1/common/x86/reconinter_sse4.c', + '/media/libaom/src/av1/common/x86/reconinter_ssse3.c', + '/media/libaom/src/av1/common/x86/selfguided_avx2.c', + '/media/libaom/src/av1/common/x86/selfguided_sse4.c', + '/media/libaom/src/av1/common/x86/warp_plane_avx2.c', + '/media/libaom/src/av1/common/x86/warp_plane_sse2.c', + '/media/libaom/src/av1/common/x86/warp_plane_sse4.c', + '/media/libaom/src/av1/common/x86/wiener_convolve_avx2.c', + '/media/libaom/src/av1/common/x86/wiener_convolve_sse2.c', + '/media/libaom/src/av1/decoder/decodeframe.c', + '/media/libaom/src/av1/decoder/decodemv.c', + '/media/libaom/src/av1/decoder/decoder.c', + '/media/libaom/src/av1/decoder/decodetxb.c', + '/media/libaom/src/av1/decoder/detokenize.c', + '/media/libaom/src/av1/decoder/obu.c', ], } diff --git a/media/libaom/src/.gitattributes b/media/libaom/src/.gitattributes new file mode 100644 index 0000000000..ffc6912a98 --- /dev/null +++ b/media/libaom/src/.gitattributes @@ -0,0 +1,18 @@ +*.[chs] filter=fixtabswsp +*.[ch]pp filter=fixtabswsp +*.[ch]xx filter=fixtabswsp +*.asm filter=fixtabswsp +*.php filter=fixtabswsp +*.pl filter=fixtabswsp +*.sh filter=fixtabswsp +*.txt filter=fixwsp +[Mm]akefile filter=fixwsp +*.mk filter=fixwsp +*.rc -crlf +*.ds[pw] -crlf +*.bat -crlf +*.mmp -crlf +*.dpj -crlf +*.pjt -crlf +*.vcp -crlf +*.inf -crlf diff --git a/media/libaom/src/.mailmap b/media/libaom/src/.mailmap index bbe4525b18..30fae4de78 100644 --- a/media/libaom/src/.mailmap +++ b/media/libaom/src/.mailmap @@ -3,32 +3,89 @@ Aℓex Converse Aℓex Converse Alexis Ballier Alpha Lam +Andrey Norkin +Angie Chiang +Arild Fuldseth +Arild Fuldseth +Bohan Li +Changjun Yang +Chi Yo Tsai +Chi Yo Tsai +Chm +Damon Shen +Daniele Castagna Deb Mukherjee +Elliott Karpilovsky +Emil Keyder Erik Niemeyer -Guillaume Martres +Frederic Barbier +Fyodor Kyslov +Grant Hsu +Guillaume Martres +Guillaume Martres +Guillaume Martres +Guillaume Martres Hangyu Kuang Hui Su +Iole Moccagatta Jacky Chen +James Zern +Jean-Marc Valin Jim Bankoski Johann Koenig Johann Koenig Johann Koenig +Johann Koenig John Koleszar Joshua Litt +Lokeshwar Reddy B +Logan Goldberg +Luc Trudeau +Luc Trudeau Marco Paniconi Marco Paniconi +Michael Bebenita +Michael Horowitz +Mingliang Chen +Monty Montgomery +Nathan E. Egge +Nathan E. Egge Pascal Massimino +Pascal Massimino Paul Wilkins +Peng Bin +Peng Bin +Peter de Rivaz Ralph Giles Ralph Giles +Remya Prakasan +Roger Zhou Ronald S. Bultje +Ryan Lei +Ryan Lei +Ryan Lei +Sachin Kumar Garg +Sai Deng Sami Pietilä Sarah Parker Tamar Levy Tamar Levy Tero Rintaluoma +Thomas Davies Thomas +Timothy B. Terriberry +Timothy B. Terriberry Timothy B. Terriberry Tim Terriberry Tom Finegan Tom Finegan +Tristan Matthews +Venkat Sanampudi +Wei-Ting Lin +Wei-Ting Lin +Wenyao Liu +Yaowu Xu Yaowu Xu Yaowu Xu +Yaowu Xu +Yaowu Xu +Zhipin Deng +Zoe Liu diff --git a/media/libaom/src/AUTHORS b/media/libaom/src/AUTHORS index 95c3c8bf2b..f61026fc03 100644 --- a/media/libaom/src/AUTHORS +++ b/media/libaom/src/AUTHORS @@ -1,13 +1,16 @@ # This file is automatically generated from the git commit history # by tools/gen_authors.sh. +Aamir Anis Aaron Watry +Aasaipriya Abo Talib Mahfoodh -Adam Xu Adrian Grange -Aℓex Converse Ahmad Sharif +Akshata Jadhav +Alexander Bokov Alexander Voronov +Aℓex Converse Alexis Ballier Alok Ahuja Alpha Lam @@ -16,39 +19,82 @@ Ami Fischman Andoni Morales Alastruey Andres Mejia Andrew Russell +Andrey Norkin Angie Chiang +Aniket Dhok +Ankur Saxena +Arild Fuldseth Aron Rosenberg Attila Nagy +Bohan Li +Brennan Shacklett Brion Vibber -changjun.yang +Bruno Berthier +Changjun Yang Charles 'Buck' Krasic -chm +Cheng Chen +Cherma Rajan A +Chi Yo Tsai +Chm Christian Duvivier +Cyril Concolato +Dake He +Damon Shen +Dandan Ding +Daniele Castagna Daniel Kang +Daniel Max Valenzuela +Danil Chapovalov +David Barker +David Major +David Michael Barr +David Turner Deb Mukherjee +Deepa K G +Deng +Di Chen Dim Temp Dmitry Kovalev +Dominic Symes Dragan Mrdjan Ed Baker +Edward Hervey Ehsan Akhgari +Elliott Karpilovsky +Emil Keyder Erik Niemeyer Fabio Pedretti +Fangwen Fu +Fergus Simpson +Frank Bossen Frank Galligan +Frederic Barbier Fredrik Söderquist Fritz Koenig +Fyodor Kyslov Gaute Strokkenes Geza Lore Ghislain MARY Giuseppe Scrivano Gordana Cmiljanovic -Guillaume Martres +Grant Hsu +Guillaume Martres Guillermo Ballester Valor +Hamsalekha S Hangyu Kuang Hanno Böck +Harish Mahendrakar Henrik Lundin +Hien Ho Hui Su +Ilie Halip +Ilya Brailovskiy +Imdad Sardharwalla +iole moccagatta +Ivan Krasin Ivan Maltz Jacek Caban +Jack Haughton Jacky Chen James Berry James Yu @@ -56,29 +102,42 @@ James Zern Jan Gerber Jan Kratochvil Janne Salonen -Jean-Marc Valin +Jayasanker J +Jean-Marc Valin +Jean-Yves Avenard Jeff Faust Jeff Muizelaar Jeff Petkau +Jerome Jiang Jia Jia Jian Zhou Jim Bankoski Jingning Han +Joe Young Joey Parrish -Johann Koenig Johann Koenig John Koleszar Johnny Klonaris John Stark +Jonathan Matthews Joshua Bleecher Snyder Joshua Litt Julia Robson Justin Clift Justin Lebar +Katsuhisa Yuasa KO Myung-Hun +Krishna Malladi +Kyle Siefring +Larisa Markeeva Lawrence Velázquez +Lester Lu +Linfeng Zhang +Logan Goldberg +Lokeshwar Reddy B Lou Quillio Luca Barbato +Luc Trudeau Makoto Kato Mans Rullgard Marco Paniconi @@ -86,40 +145,78 @@ Mark Mentovai Martin Ettl Martin Storsjo Matthew Heaney +Matthieu Vaudano +Mattias Hansson +Maxym Dmytrychenko +Michael Bebenita +Michael Horowitz Michael Kohler +Michelle Findlay-Olynyk Mike Frysinger Mike Hommey Mikhal Shemer Minghai Shang +Mingliang Chen +Mirko Bonadei +Monty Montgomery Morton Jonuschat -Nathan E. Egge +Mufaddal Chakera +Nathan E. Egge +Neil Birkbeck Nico Weber +Nithya V S +Ola Hugosson +Oleg Nalivayko Parag Salasakar Pascal Massimino Patrik Westin Paul Wilkins +Pavel Frolov Pavol Rusnak Paweł Hajdan +Peng Bin Pengchong Jin -Peter de Rivaz +Peter Boström Peter de Rivaz Philip Jägenstedt Priit Laes Rafael Ávila de Espíndola Rafaël Carré Ralph Giles +Ranjit Kumar Tulabandu +Ravi Chaudhary +Remya Prakasan +Remy Foray Rob Bradford +Robert-André Mauchin +RogerZhou +Rohit Athavale Ronald S. Bultje +Rostislav Pehlivanov +Ruiling Song Rui Ueyama +Rupert Swarbrick +Ryan Lei +Ryan Overbeck +Sachin Kumar Garg +Sai Deng Sami Pietilä +Sarah Parker Sasi Inguva +Satish Kumar Suman Scott Graham Scott LaVarnway +Sean DuBois Sean McGovern +Sean Purser-Haskell +Sebastien Alaiwan Sergey Kolomenkin Sergey Ulanov Shimon Doodkin Shunyao Li +SmilingWolf +Soo-Chul Han +Stanislav Vitvitskyy Stefan Holmer Steinar Midtskogen Suman Sunkara @@ -127,18 +224,37 @@ Taekhyun Kim Takanori MATSUURA Tamar Levy Tao Bai +Tarek AMARA Tero Rintaluoma Thijs Vermeir Thomas Daede -Thomas Davies -Thomas +Thomas Davies Thomas Tim Kopp Timothy B. Terriberry +Timo Witte +Todd Nguyen +Tom Anderson Tom Finegan -Tristan Matthews Tristan Matthews +Umang Saini +Urvang Joshi +Venkat Sanampudi +Victoria Zhislina Vignesh Venkatasubramanian +Vishesh +Wan-Teh Chang +Wei-Ting Lin +Wenyao Liu +Xing Jin +Xin Zhao +Yaowu Xu Yaowu Xu +Yi Luo Yongzhe Wang +Yue Chen Yunqing Wang -Zoe Liu +Yury Gitman +Yushin Cho +Zhijie Yang +zhipin deng +Zoe Liu diff --git a/media/libaom/src/CHANGELOG b/media/libaom/src/CHANGELOG index d84aa02499..11da097af2 100644 --- a/media/libaom/src/CHANGELOG +++ b/media/libaom/src/CHANGELOG @@ -1,3 +1,49 @@ +2021-02-09 v2.0.2 + This release includes several bug fixes. + + - Bug fixes: + Issue 2643: Modify the assertion in temporal filter intrinsics. + + Issue 2648: Fix unit test ThreadTestLarge.EncoderResultTest/49 + assertion failure. + + Issue 2869: Add -Wimplicit-function-declaration as C flag only. + + Issue 2878: Avoid memset in the av1_filter_intra_predictor module + functions. + + Issue 2903: Fix a typo bug in apply_temporal_filter_planewise. + + Call av1_setup_frame_size() when dropping a frame in the + encode_frame_to_data_rate() function in av1/encoder/encoder.c. + +2020-11-25 v2.0.1 + This release includes two bug fixes. + + - Bug fixes: + Issue 2723: Fix crash in chroma_check() when generating a monochrome + encoded stream in real-time mode. + + Issue 2833: Fix crash on some input when reduced still picture header is + used in real-time mode and speed >=7. + +2020-05-07 v2.0.0 "Applejack" + First official release of libaom. + This release includes new real-time mode and SVC support. + + - Upgrading: + AOM_SET_POSTPROC, AOM_CODEC_CAP_POSTPROC and AOM_CODEC_USE_POSTPROC are + removed. + + AOM_SET_DBG_* is removed. + + Multi-resolution encoding is removed. + + put_frame and put_slice callbacks are removed. + + - Enhancements: + Full-sweep document update for codec controls. + 2018-06-28 v1.0.0 AOMedia Codec Workgroup Approved version 1.0 diff --git a/media/libaom/src/CMakeLists.txt b/media/libaom/src/CMakeLists.txt index c0e44638df..84c8995a50 100644 --- a/media/libaom/src/CMakeLists.txt +++ b/media/libaom/src/CMakeLists.txt @@ -32,6 +32,11 @@ if("${AOM_ROOT}" STREQUAL "${AOM_CONFIG_DIR}") "And re-run CMake from the aom_build directory.") endif() +# Updating version info. +# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info +set(SO_VERSION 2) +set(SO_FILE_VERSION 2.0.2) + include("${AOM_ROOT}/build/cmake/aom_configure.cmake") include("${AOM_ROOT}/aom_dsp/aom_dsp.cmake") include("${AOM_ROOT}/aom_mem/aom_mem.cmake") @@ -190,6 +195,18 @@ add_custom_target(aom_version_check "${AOM_ROOT}/build/cmake/version.cmake" COMMENT "Updating version info if necessary." VERBATIM) + +if(BUILD_SHARED_LIBS AND NOT MSVC) + # Generate version file immediately for non-MSVC shared builds: The version + # string is needed for the aom target. + execute_process(COMMAND ${CMAKE_COMMAND} + -DAOM_CONFIG_DIR=${AOM_CONFIG_DIR} + -DAOM_ROOT=${AOM_ROOT} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DPERL_EXECUTABLE=${PERL_EXECUTABLE} -P + "${AOM_ROOT}/build/cmake/version.cmake") +endif() + add_dependencies(aom_version aom_version_check) # TODO(tomfinegan): Move rtcd target setup where it belongs for each rtcd @@ -211,14 +228,46 @@ if(ENABLE_EXAMPLES) add_library(aom_encoder_stats OBJECT ${AOM_ENCODER_STATS_SOURCES}) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_encoder_stats) endif() + add_library(aom ${AOM_SOURCES} $) +if(BUILD_SHARED_LIBS) + add_library(aom_static STATIC ${AOM_SOURCES} $) + set_target_properties(aom_static PROPERTIES OUTPUT_NAME aom) + + if(NOT MSVC) + # Extract version string and set VERSION/SOVERSION for the aom target. + extract_version_string("${AOM_CONFIG_DIR}/config/aom_version.h" + aom_version_triple) + + # Strip any trailing version information, if present. + string(FIND "${aom_version_triple}" "-" dash_pos) + if(NOT dash_pos EQUAL -1) + string(SUBSTRING "${aom_version_triple}" 0 ${dash_pos} aom_version_triple) + endif() + + # cmake-format: off + # VERSION is embedded in the .so file name. + # libaom.so -> libaom.so.SOVERSION + # libaom.so.SOVERSION -> libaom.so.VERSION + # libaom.so.VERSION + # cmake-format: on + set_target_properties(aom PROPERTIES SOVERSION ${SO_VERSION}) + set_target_properties(aom PROPERTIES VERSION ${SO_FILE_VERSION}) + endif() +endif() if(NOT MSVC AND NOT APPLE) target_link_libraries(aom ${AOM_LIB_LINK_TYPE} m) + if(BUILD_SHARED_LIBS) + target_link_libraries(aom_static ${AOM_LIB_LINK_TYPE} m) + endif() endif() # List of object and static library targets. set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_rtcd aom_mem aom_scale aom) +if(BUILD_SHARED_LIBS) + set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_static) +endif() # Setup dependencies. setup_aom_dsp_targets() @@ -382,6 +431,19 @@ if(CONFIG_AV1_ENCODER) # Add encoder examples and tools to the targets list. list(APPEND AOM_APP_TARGETS ${AOM_ENCODER_EXAMPLE_TARGETS} ${AOM_ENCODER_TOOL_TARGETS}) + + if(CONFIG_TUNE_VMAF) + find_library(VMAF libvmaf.a vmaf) + if(NOT VMAF) + message(FATAL_ERROR "VMAF library not found.") + endif() + message("-- Found VMAF library: " ${VMAF}) + set_target_properties(aom PROPERTIES LINKER_LANGUAGE CXX) + if(BUILD_SHARED_LIBS) + set_target_properties(aom_static PROPERTIES LINKER_LANGUAGE CXX) + endif() + target_link_libraries(aom PRIVATE ${VMAF}) + endif() endif() if(ENABLE_EXAMPLES) @@ -510,6 +572,9 @@ endif() if(HAVE_PTHREAD_H AND CONFIG_MULTITHREAD) find_package(Threads) target_link_libraries(aom ${AOM_LIB_LINK_TYPE} Threads::Threads) + if(BUILD_SHARED_LIBS) + target_link_libraries(aom_static ${AOM_LIB_LINK_TYPE} Threads::Threads) + endif() endif() if(XCODE) @@ -559,7 +624,6 @@ endif() if(BUILD_SHARED_LIBS) include("${AOM_ROOT}/build/cmake/exports.cmake") setup_exports_target() - set_target_properties(aom PROPERTIES SOVERSION 0) endif() # Handle user supplied compile and link flags last to ensure they're obeyed. diff --git a/media/libaom/src/README.md b/media/libaom/src/README.md index 6b58d35408..cf057ae6c4 100644 --- a/media/libaom/src/README.md +++ b/media/libaom/src/README.md @@ -14,6 +14,7 @@ - [Xcode builds](#xcode-builds) - [Emscripten builds](#emscripten-builds) - [Extra Build Flags](#extra-build-flags) + - [Build with VMAF support](#build-with-vmaf) 2. [Testing the library](#testing-the-av1-codec) - [Basics](#testing-basics) - [Unit tests](#1_unit-tests) @@ -47,7 +48,9 @@ 2. [Git](https://git-scm.com/). 3. [Perl](https://www.perl.org/). 4. For x86 targets, [yasm](http://yasm.tortall.net/), which is preferred, or a - recent version of [nasm](http://www.nasm.us/). + recent version of [nasm](http://www.nasm.us/). If you download yasm with + the intention to work with Visual Studio, please download win32.exe or + win64.exe and rename it into yasm.exe. DO NOT download or use vsyasm.exe. 5. Building the documentation requires [doxygen](http://doxygen.org). 6. Building the unit tests requires [Python](https://www.python.org/). 7. Emscripten builds require the portable @@ -211,12 +214,28 @@ compiler documentation to determine which, if any, are available. ### Microsoft Visual Studio builds Building the AV1 codec library in Microsoft Visual Studio is supported. Visual -Studio 2015 (14.0) or later is required. The following example demonstrates +Studio 2017 (15.0) or later is required. The following example demonstrates generating projects and a solution for the Microsoft IDE: ~~~ - # This does not require a bash shell; command.exe is fine. - $ cmake path/to/aom -G "Visual Studio 15 2017" + # This does not require a bash shell; Command Prompt (cmd.exe) is fine. + # This assumes the build host is a Windows x64 computer. + + # To build with Visual Studio 2019 for the x64 target: + $ cmake path/to/aom -G "Visual Studio 16 2019" + $ cmake --build . + + # To build with Visual Studio 2019 for the 32-bit x86 target: + $ cmake path/to/aom -G "Visual Studio 16 2019" -A Win32 + $ cmake --build . + + # To build with Visual Studio 2017 for the x64 target: + $ cmake path/to/aom -G "Visual Studio 15 2017" -T host=x64 -A x64 + $ cmake --build . + + # To build with Visual Studio 2017 for the 32-bit x86 target: + $ cmake path/to/aom -G "Visual Studio 15 2017" -T host=x64 + $ cmake --build . ~~~ NOTE: The build system targets Windows 7 or later by compiling files with @@ -293,6 +312,24 @@ These flags can be used, for example, to enable asserts in a release build: -DAOM_EXTRA_CXX_FLAGS=-UNDEBUG ~~~ +### Build with VMAF support + +After installing +[libvmaf.a](https://github.com/Netflix/vmaf/blob/master/resource/doc/libvmaf.md), +you can use it with the encoder: + +~~~ + $ cmake path/to/aom -DCONFIG_TUNE_VMAF=1 +~~~ + +Please note that the default VMAF model +("/usr/local/share/model/vmaf_v0.6.1.pkl") +will be used unless you set the following flag when running the encoder: + +~~~ + # --vmaf-model-path=path/to/model +~~~ + ## Testing the AV1 codec ### Testing basics diff --git a/media/libaom/src/Sample.cfg b/media/libaom/src/Sample.cfg new file mode 100644 index 0000000000..d5dbe66415 --- /dev/null +++ b/media/libaom/src/Sample.cfg @@ -0,0 +1,35 @@ +#sample config file +super_block_size = 128 # super block size. 0, 64 or 128 +max_partition_size = 128 # max partition size(8, 16, 32, 64, 128) +min_partition_size = 4 # min partition size(4, 8, 16, 32, 64) +disable_rect_partition_type = 0 # disable rectangle partition type +disable_ab_partition_type = 0 # disable AB partition type +disable_1to4_partition_type = 0 # disable 1 to 4 and 4 to 1 partition type +disable_intra_angle_delta = 0 # disable intra angle delta +disable_paeth_intra = 0 # disable paeth intra +disable_smooth_intra = 0 # disable intra smooth mode +disable_intra_edge_filter = 0 # disable intra edge filter +disable_filter_intra = 0 # disable filter intra +disable_intrabc = 0 # disable Intra Block Copy +disable_cfl = 0 # disable chroma from luma prediction +disable_palette = 0 # disable Palette +disable_flip_idtx = 0 # disable flip and identity transform +disable_tx_64x64 = 0 # disable 64x64 transform +reduced_tx_type_set = 0 # use reduced transform type set +reduced_reference_set = 0 # use reduced reference frame set +disable_obmc = 0 # disable OBMC +disable_warp_motion = 0 # disable Warped Motion +disable_global_motion = 0 # disable global motion +disable_ref_frame_mv = 0 # disable ref mv +disable_dual_filter = 0 # disable dual interpolation filter +disable_one_sided_comp = 0 # disable one sided compound mode +disable_masked_comp = 0 # disable masked compound prediction +disable_diff_wtd_comp = 0 # disable difference weighted compound mode +disable_inter_inter_wedge = 0 # disable inter/inter wedge comp +disable_dist_wtd_comp = 0 # disable distant weighted compound mode +disable_inter_intra_comp = 0 # disable inter/intra compound mode. +disable_inter_intra_wedge = 0 # disable inter/intra wedge comp +disable_smooth_inter_intra = 0 # disable smooth inter/intra +disable_cdef = 0 # disable CDEF filter +disable_lr = 0 # disable Loop Restoration Filter +disable_trellis_quant = 0 # disable trellis quantization \ No newline at end of file diff --git a/media/libaom/src/aom/aom.h b/media/libaom/src/aom/aom.h index b1cc1ecceb..c591dc9a43 100644 --- a/media/libaom/src/aom/aom.h +++ b/media/libaom/src/aom/aom.h @@ -43,64 +43,27 @@ extern "C" { * The set of macros define the control functions of AOM interface */ enum aom_com_control_id { - /*!\brief pass in an external frame into decoder to be used as reference frame + /* TODO(https://crbug.com/aomedia/2671): The encoder overlaps the range of + * these values for its control ids, see the NOTEs in aom/aomcx.h. These + * should be migrated to something like the AOM_DECODER_CTRL_ID_START range + * next time we're ready to break the ABI. */ - AOM_SET_POSTPROC = 3, /**< set the decoder's post processing settings */ - AOM_SET_DBG_COLOR_REF_FRAME = - 4, /**< set the reference frames to color for each macroblock */ - AOM_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */ - AOM_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */ - AOM_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */ - - /* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+) - * for its control ids. These should be migrated to something like the - * AOM_DECODER_CTRL_ID_START range next time we're ready to break the ABI. - */ - AV1_GET_REFERENCE = 128, /**< get a pointer to a reference frame */ - AV1_SET_REFERENCE = 129, /**< write a frame into a reference buffer */ - AV1_COPY_REFERENCE = - 130, /**< get a copy of reference frame from the decoder */ + AV1_GET_REFERENCE = 128, /**< get a pointer to a reference frame, + av1_ref_frame_t* parameter */ + AV1_SET_REFERENCE = 129, /**< write a frame into a reference buffer, + av1_ref_frame_t* parameter */ + AV1_COPY_REFERENCE = 130, /**< get a copy of reference frame from the decoderm + av1_ref_frame_t* parameter */ AOM_COMMON_CTRL_ID_MAX, - AV1_GET_NEW_FRAME_IMAGE = 192, /**< get a pointer to the new frame */ - AV1_COPY_NEW_FRAME_IMAGE = - 193, /**< copy the new frame to an external buffer */ + AV1_GET_NEW_FRAME_IMAGE = + 192, /**< get a pointer to the new frame, aom_image_t* parameter */ + AV1_COPY_NEW_FRAME_IMAGE = 193, /**< copy the new frame to an external buffer, + aom_image_t* parameter */ AOM_DECODER_CTRL_ID_START = 256 }; -/*!\brief post process flags - * - * The set of macros define AOM decoder post processing flags - */ -enum aom_postproc_level { - AOM_NOFILTERING = 0, - AOM_DEBLOCK = 1 << 0, - AOM_DEMACROBLOCK = 1 << 1, - AOM_ADDNOISE = 1 << 2, - AOM_DEBUG_TXT_FRAME_INFO = 1 << 3, /**< print frame information */ - AOM_DEBUG_TXT_MBLK_MODES = - 1 << 4, /**< print macro block modes over each macro block */ - AOM_DEBUG_TXT_DC_DIFF = 1 << 5, /**< print dc diff for each macro block */ - AOM_DEBUG_TXT_RATE_INFO = 1 << 6, /**< print video rate info (encoder only) */ - AOM_MFQE = 1 << 10 -}; - -/*!\brief post process flags - * - * This define a structure that describe the post processing settings. For - * the best objective measure (using the PSNR metric) set post_proc_flag - * to AOM_DEBLOCK and deblocking_level to 1. - */ - -typedef struct aom_postproc_cfg { - /*!\brief the types of post processing to be done, should be combination of - * "aom_postproc_level" */ - int post_proc_flag; - int deblocking_level; /**< the strength of deblocking, valid range [0, 16] */ - int noise_level; /**< the strength of additive noise, valid range [0, 16] */ -} aom_postproc_cfg_t; - /*!\brief AV1 specific reference frame data struct * * Define the data struct to access av1 reference frames. @@ -114,26 +77,25 @@ typedef struct av1_ref_frame { /*!\cond */ /*!\brief aom decoder control function parameter type * - * defines the data type for each of AOM decoder control function requires + * Defines the data type for each of AOM decoder control function requires. + * + * \note For each control ID "X", a macro-define of + * AOM_CTRL_X is provided. It is used at compile time to determine + * if the control ID is supported by the libaom library available, + * when the libaom version cannot be controlled. */ -AOM_CTRL_USE_TYPE(AOM_SET_POSTPROC, aom_postproc_cfg_t *) -#define AOM_CTRL_AOM_SET_POSTPROC -AOM_CTRL_USE_TYPE(AOM_SET_DBG_COLOR_REF_FRAME, int) -#define AOM_CTRL_AOM_SET_DBG_COLOR_REF_FRAME -AOM_CTRL_USE_TYPE(AOM_SET_DBG_COLOR_MB_MODES, int) -#define AOM_CTRL_AOM_SET_DBG_COLOR_MB_MODES -AOM_CTRL_USE_TYPE(AOM_SET_DBG_COLOR_B_MODES, int) -#define AOM_CTRL_AOM_SET_DBG_COLOR_B_MODES -AOM_CTRL_USE_TYPE(AOM_SET_DBG_DISPLAY_MV, int) -#define AOM_CTRL_AOM_SET_DBG_DISPLAY_MV AOM_CTRL_USE_TYPE(AV1_GET_REFERENCE, av1_ref_frame_t *) #define AOM_CTRL_AV1_GET_REFERENCE + AOM_CTRL_USE_TYPE(AV1_SET_REFERENCE, av1_ref_frame_t *) #define AOM_CTRL_AV1_SET_REFERENCE + AOM_CTRL_USE_TYPE(AV1_COPY_REFERENCE, av1_ref_frame_t *) #define AOM_CTRL_AV1_COPY_REFERENCE + AOM_CTRL_USE_TYPE(AV1_GET_NEW_FRAME_IMAGE, aom_image_t *) #define AOM_CTRL_AV1_GET_NEW_FRAME_IMAGE + AOM_CTRL_USE_TYPE(AV1_COPY_NEW_FRAME_IMAGE, aom_image_t *) #define AOM_CTRL_AV1_COPY_NEW_FRAME_IMAGE diff --git a/media/libaom/src/aom/aom_codec.h b/media/libaom/src/aom/aom_codec.h index 6773e07b35..75f6a1af22 100644 --- a/media/libaom/src/aom/aom_codec.h +++ b/media/libaom/src/aom/aom_codec.h @@ -95,7 +95,7 @@ extern "C" { * types, removing or reassigning enums, adding/removing/rearranging * fields to structures */ -#define AOM_CODEC_ABI_VERSION (3 + AOM_IMAGE_ABI_VERSION) /**<\hideinitializer*/ +#define AOM_CODEC_ABI_VERSION (5 + AOM_IMAGE_ABI_VERSION) /**<\hideinitializer*/ /*!\brief Algorithm return codes */ typedef enum { @@ -173,10 +173,25 @@ typedef long aom_codec_caps_t; */ typedef long aom_codec_flags_t; +/*!\brief Time Stamp Type + * + * An integer, which when multiplied by the stream's time base, provides + * the absolute time of a sample. + */ +typedef int64_t aom_codec_pts_t; + /*!\brief Codec interface structure. * * Contains function pointers and other data private to the codec - * implementation. This structure is opaque to the application. + * implementation. This structure is opaque to the application. Common + * functions used with this structure: + * - aom_codec_iface_name: get the name of the codec + * - aom_codec_get_caps: returns the capabilities of the codec (see + * aom_encoder.h for more details) + * - aom_codec_enc_config_default: generate the default config to use + * when initializing the encoder + * - aom_codec_dec_init, aom_codec_enc_init: initialize the codec context + * structure (see documentation on aom_codec_ctx for more information). */ typedef const struct aom_codec_iface aom_codec_iface_t; @@ -370,19 +385,24 @@ aom_codec_err_t aom_codec_destroy(aom_codec_ctx_t *ctx); */ aom_codec_caps_t aom_codec_get_caps(aom_codec_iface_t *iface); -/*!\brief Control algorithm +/*!\name Codec Control * - * This function is used to exchange algorithm specific data with the codec - * instance. This can be used to implement features specific to a particular - * algorithm. + * The aom_codec_control function exchanges algorithm specific data with the + * codec instance. Additionally, the macro AOM_CODEC_CONTROL_TYPECHECKED is + * provided, which will type-check the parameter against the control ID before + * calling aom_codec_control - note that this macro requires the control ID + * to be directly encoded in it, e.g., + * AOM_CODEC_CONTROL_TYPECHECKED(&ctx, AOME_SET_CPUUSED, 8). * - * This wrapper function dispatches the request to the helper function - * associated with the given ctrl_id. It tries to call this function - * transparently, but will return #AOM_CODEC_ERROR if the request could not - * be dispatched. + * The codec control IDs can be found in aom.h, aomcx.h, and aomdx.h + * (defined as aom_com_control_id, aome_enc_control_id, and aom_dec_control_id). + * @{ + */ +/*!\brief Algorithm Control * - * Note that this function should not be used directly. Call the - * #aom_codec_control wrapper macro instead. + * aom_codec_control takes a context, a control ID, and a third parameter + * (with varying type). If the context is non-null and an error occurs, + * ctx->err will be set to the same value as the return value. * * \param[in] ctx Pointer to this instance's context * \param[in] ctrl_id Algorithm specific control identifier @@ -394,85 +414,33 @@ aom_codec_caps_t aom_codec_get_caps(aom_codec_iface_t *iface); * \retval #AOM_CODEC_INVALID_PARAM * The data was not valid. */ -aom_codec_err_t aom_codec_control_(aom_codec_ctx_t *ctx, int ctrl_id, ...); -#if defined(AOM_DISABLE_CTRL_TYPECHECKS) && AOM_DISABLE_CTRL_TYPECHECKS -#define aom_codec_control(ctx, id, data) aom_codec_control_(ctx, id, data) -#define AOM_CTRL_USE_TYPE(id, typ) -#define AOM_CTRL_USE_TYPE_DEPRECATED(id, typ) -#define AOM_CTRL_VOID(id, typ) +aom_codec_err_t aom_codec_control(aom_codec_ctx_t *ctx, int ctrl_id, ...); -#else -/*!\brief aom_codec_control wrapper macro +/*!\brief aom_codec_control wrapper macro (adds type-checking, less flexible) * * This macro allows for type safe conversions across the variadic parameter - * to aom_codec_control_(). - * - * \internal - * It works by dispatching the call to the control function through a wrapper - * function named with the id parameter. + * to aom_codec_control(). However, it requires the explicit control ID + * be passed in (it cannot be passed in via a variable) -- otherwise a compiler + * error will occur. After the type checking, it calls aom_codec_control. */ -#define aom_codec_control(ctx, id, data) \ - aom_codec_control_##id(ctx, id, data) /**<\hideinitializer*/ +#define AOM_CODEC_CONTROL_TYPECHECKED(ctx, id, data) \ + aom_codec_control_typechecked_##id(ctx, id, data) /**<\hideinitializer*/ -/*!\brief aom_codec_control type definition macro +/*!\brief Creates typechecking mechanisms for aom_codec_control * - * This macro allows for type safe conversions across the variadic parameter - * to aom_codec_control_(). It defines the type of the argument for a given - * control identifier. - * - * \internal - * It defines a static function with - * the correctly typed arguments as a wrapper to the type-unsafe internal - * function. + * It defines a static function with the correctly typed arguments as a wrapper + * to the type-unsafe aom_codec_control function. It also creates a typedef + * for each type. */ -#define AOM_CTRL_USE_TYPE(id, typ) \ - static aom_codec_err_t aom_codec_control_##id(aom_codec_ctx_t *, int, typ) \ - AOM_UNUSED; \ - \ - static aom_codec_err_t aom_codec_control_##id(aom_codec_ctx_t *ctx, \ - int ctrl_id, typ data) { \ - return aom_codec_control_(ctx, ctrl_id, data); \ - } /**<\hideinitializer*/ - -/*!\brief aom_codec_control deprecated type definition macro - * - * Like #AOM_CTRL_USE_TYPE, but indicates that the specified control is - * deprecated and should not be used. Consult the documentation for your - * codec for more information. - * - * \internal - * It defines a static function with the correctly typed arguments as a - * wrapper to the type-unsafe internal function. - */ -#define AOM_CTRL_USE_TYPE_DEPRECATED(id, typ) \ - AOM_DECLSPEC_DEPRECATED static aom_codec_err_t aom_codec_control_##id( \ - aom_codec_ctx_t *, int, typ) AOM_DEPRECATED AOM_UNUSED; \ - \ - AOM_DECLSPEC_DEPRECATED static aom_codec_err_t aom_codec_control_##id( \ - aom_codec_ctx_t *ctx, int ctrl_id, typ data) { \ - return aom_codec_control_(ctx, ctrl_id, data); \ - } /**<\hideinitializer*/ - -/*!\brief aom_codec_control void type definition macro - * - * This macro allows for type safe conversions across the variadic parameter - * to aom_codec_control_(). It indicates that a given control identifier takes - * no argument. - * - * \internal - * It defines a static function without a data argument as a wrapper to the - * type-unsafe internal function. - */ -#define AOM_CTRL_VOID(id) \ - static aom_codec_err_t aom_codec_control_##id(aom_codec_ctx_t *, int) \ - AOM_UNUSED; \ - \ - static aom_codec_err_t aom_codec_control_##id(aom_codec_ctx_t *ctx, \ - int ctrl_id) { \ - return aom_codec_control_(ctx, ctrl_id); \ - } /**<\hideinitializer*/ - -#endif +#define AOM_CTRL_USE_TYPE(id, typ) \ + static aom_codec_err_t aom_codec_control_typechecked_##id( \ + aom_codec_ctx_t *, int, typ) AOM_UNUSED; \ + static aom_codec_err_t aom_codec_control_typechecked_##id( \ + aom_codec_ctx_t *ctx, int ctrl, typ data) { \ + return aom_codec_control(ctx, ctrl, data); \ + } /**<\hideinitializer*/ \ + typedef typ aom_codec_control_type_##id; +/*!@} end Codec Control group */ /*!\brief OBU types. */ typedef enum ATTRIBUTE_PACKED { diff --git a/media/libaom/src/aom/aom_decoder.h b/media/libaom/src/aom/aom_decoder.h index af20e98090..5ce7c7b103 100644 --- a/media/libaom/src/aom/aom_decoder.h +++ b/media/libaom/src/aom/aom_decoder.h @@ -42,7 +42,7 @@ extern "C" { * fields to structures */ #define AOM_DECODER_ABI_VERSION \ - (4 + AOM_CODEC_ABI_VERSION) /**<\hideinitializer*/ + (6 + AOM_CODEC_ABI_VERSION) /**<\hideinitializer*/ /*! \brief Decoder capabilities bitfield * @@ -52,9 +52,8 @@ extern "C" { * * The available flags are specified by AOM_CODEC_CAP_* defines. */ -#define AOM_CODEC_CAP_PUT_SLICE 0x10000 /**< Will issue put_slice callbacks */ -#define AOM_CODEC_CAP_PUT_FRAME 0x20000 /**< Will issue put_frame callbacks */ -#define AOM_CODEC_CAP_POSTPROC 0x40000 /**< Can postprocess decoded frame */ +/*!brief Can support external frame buffers */ +#define AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x200000 /*! \brief Initialization-time Feature Enabling * @@ -63,10 +62,6 @@ extern "C" { * * The available flags are specified by AOM_CODEC_USE_* defines. */ -/*!brief Can support external frame buffers */ -#define AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x200000 - -#define AOM_CODEC_USE_POSTPROC 0x10000 /**< Postprocess decoded frame */ /*!\brief Stream properties * @@ -107,8 +102,8 @@ typedef struct aom_codec_dec_cfg { * function directly, to ensure that the ABI version number parameter * is properly initialized. * - * If the library was configured with --disable-multithread, this call - * is not thread safe and should be guarded with a lock if being used + * If the library was configured with cmake -DCONFIG_MULTITHREAD=0, this + * call is not thread safe and should be guarded with a lock if being used * in a multithreaded context. * * \param[in] ctx Pointer to this instance's context. @@ -178,16 +173,12 @@ aom_codec_err_t aom_codec_get_stream_info(aom_codec_ctx_t *ctx, /*!\brief Decode data * - * Processes a buffer of coded data. If the processing results in a new - * decoded frame becoming available, PUT_SLICE and PUT_FRAME events may be - * generated, as appropriate. Encoded data \ref MUST be passed in DTS (decode - * time stamp) order. Frames produced will always be in PTS (presentation - * time stamp) order. + * Processes a buffer of coded data. Encoded data \ref MUST be passed in DTS + * (decode time stamp) order. Frames produced will always be in PTS + * (presentation time stamp) order. * * \param[in] ctx Pointer to this instance's context - * \param[in] data Pointer to this block of new coded data. If - * NULL, a AOM_CODEC_CB_PUT_FRAME event is posted - * for the previously decoded frame. + * \param[in] data Pointer to this block of new coded data. * \param[in] data_sz Size of the coded data, in bytes. * \param[in] user_priv Application specific data to associate with * this frame. @@ -218,95 +209,12 @@ aom_codec_err_t aom_codec_decode(aom_codec_ctx_t *ctx, const uint8_t *data, */ aom_image_t *aom_codec_get_frame(aom_codec_ctx_t *ctx, aom_codec_iter_t *iter); -/*!\defgroup cap_put_frame Frame-Based Decoding Functions - * - * The following functions are required to be implemented for all decoders - * that advertise the AOM_CODEC_CAP_PUT_FRAME capability. Calling these - * functions - * for codecs that don't advertise this capability will result in an error - * code being returned, usually AOM_CODEC_ERROR - * @{ - */ - -/*!\brief put frame callback prototype - * - * This callback is invoked by the decoder to notify the application of - * the availability of decoded image data. - */ -typedef void (*aom_codec_put_frame_cb_fn_t)(void *user_priv, - const aom_image_t *img); - -/*!\brief Register for notification of frame completion. - * - * Registers a given function to be called when a decoded frame is - * available. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cb Pointer to the callback function - * \param[in] user_priv User's private data - * - * \retval #AOM_CODEC_OK - * Callback successfully registered. - * \retval #AOM_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * posting slice completion. - */ -aom_codec_err_t aom_codec_register_put_frame_cb(aom_codec_ctx_t *ctx, - aom_codec_put_frame_cb_fn_t cb, - void *user_priv); - -/*!@} - end defgroup cap_put_frame */ - -/*!\defgroup cap_put_slice Slice-Based Decoding Functions - * - * The following functions are required to be implemented for all decoders - * that advertise the AOM_CODEC_CAP_PUT_SLICE capability. Calling these - * functions - * for codecs that don't advertise this capability will result in an error - * code being returned, usually AOM_CODEC_ERROR - * @{ - */ - -/*!\brief put slice callback prototype - * - * This callback is invoked by the decoder to notify the application of - * the availability of partially decoded image data. The - */ -typedef void (*aom_codec_put_slice_cb_fn_t)(void *user_priv, - const aom_image_t *img, - const aom_image_rect_t *valid, - const aom_image_rect_t *update); - -/*!\brief Register for notification of slice completion. - * - * Registers a given function to be called when a decoded slice is - * available. - * - * \param[in] ctx Pointer to this instance's context - * \param[in] cb Pointer to the callback function - * \param[in] user_priv User's private data - * - * \retval #AOM_CODEC_OK - * Callback successfully registered. - * \retval #AOM_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * posting slice completion. - */ -aom_codec_err_t aom_codec_register_put_slice_cb(aom_codec_ctx_t *ctx, - aom_codec_put_slice_cb_fn_t cb, - void *user_priv); - -/*!@} - end defgroup cap_put_slice*/ - /*!\defgroup cap_external_frame_buffer External Frame Buffer Functions * - * The following section is required to be implemented for all decoders + * The following function is required to be implemented for all decoders * that advertise the AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER capability. * Calling this function for codecs that don't advertise this capability - * will result in an error code being returned, usually AOM_CODEC_ERROR. - * - * \note - * Currently this only works with AV1. + * will result in an error code being returned, usually AOM_CODEC_INCAPABLE. * @{ */ @@ -328,13 +236,13 @@ aom_codec_err_t aom_codec_register_put_slice_cb(aom_codec_ctx_t *ctx, * \retval #AOM_CODEC_INVALID_PARAM * One or more of the callbacks were NULL. * \retval #AOM_CODEC_ERROR - * Decoder context not initialized, or algorithm not capable of - * using external frame buffers. + * Decoder context not initialized. + * \retval #AOM_CODEC_INCAPABLE + * Algorithm not capable of using external frame buffers. * * \note * When decoding AV1, the application may be required to pass in at least - * #AOM_MAXIMUM_WORK_BUFFERS external frame - * buffers. + * #AOM_MAXIMUM_WORK_BUFFERS external frame buffers. */ aom_codec_err_t aom_codec_set_frame_buffer_functions( aom_codec_ctx_t *ctx, aom_get_frame_buffer_cb_fn_t cb_get, diff --git a/media/libaom/src/aom/aom_encoder.h b/media/libaom/src/aom/aom_encoder.h index 9d02e8cc2a..a494c17a49 100644 --- a/media/libaom/src/aom/aom_encoder.h +++ b/media/libaom/src/aom/aom_encoder.h @@ -41,7 +41,7 @@ extern "C" { * fields to structures */ #define AOM_ENCODER_ABI_VERSION \ - (6 + AOM_CODEC_ABI_VERSION) /**<\hideinitializer*/ + (8 + AOM_CODEC_ABI_VERSION) /**<\hideinitializer*/ /*! \brief Encoder capabilities bitfield * @@ -78,13 +78,6 @@ typedef struct aom_fixed_buf { size_t sz; /**< Length of the buffer, in chars */ } aom_fixed_buf_t; /**< alias for struct aom_fixed_buf */ -/*!\brief Time Stamp Type - * - * An integer, which when multiplied by the stream's time base, provides - * the absolute time of a sample. - */ -typedef int64_t aom_codec_pts_t; - /*!\brief Compressed Frame Flags * * This type represents a bitfield containing information about a compressed @@ -209,6 +202,154 @@ enum aom_kf_mode { AOM_KF_DISABLED = 0 /**< Encoder does not place keyframes. */ }; +/*!\brief Encoder Config Options + * + * This type allows to enumerate and control flags defined for encoder control + * via config file at runtime. + */ +typedef struct cfg_options { + /*!\brief Indicate init by cfg file + * 0 or 1 + */ + unsigned int init_by_cfg_file; + /*!\brief Superblock size + * 0, 64 or 128 + */ + unsigned int super_block_size; + /*!\brief max partition size + * 8, 16, 32, 64, 128 + */ + unsigned int max_partition_size; + /*!\brief min partition size + * 8, 16, 32, 64, 128 + */ + unsigned int min_partition_size; + /*!\brief disable AB Shape partition type + * + */ + unsigned int disable_ab_partition_type; + /*!\brief disable rectangular partition type + * + */ + unsigned int disable_rect_partition_type; + /*!\brief disable 1:4/4:1 partition type + * + */ + unsigned int disable_1to4_partition_type; + /*!\brief disable flip and identity transform type + * + */ + unsigned int disable_flip_idtx; + /*!\brief disable CDEF filter + * + */ + unsigned int disable_cdef; + /*!\brief disable Loop Restoration Filter + * + */ + unsigned int disable_lr; + /*!\brief disable OBMC + * + */ + unsigned int disable_obmc; + /*!\brief disable Warped Motion + * + */ + unsigned int disable_warp_motion; + /*!\brief disable global motion + * + */ + unsigned int disable_global_motion; + /*!\brief disable dist weighted compound + * + */ + unsigned int disable_dist_wtd_comp; + /*!\brief disable diff weighted compound + * + */ + unsigned int disable_diff_wtd_comp; + /*!\brief disable inter/intra compound + * + */ + unsigned int disable_inter_intra_comp; + /*!\brief disable masked compound + * + */ + unsigned int disable_masked_comp; + /*!\brief disable one sided compound + * + */ + unsigned int disable_one_sided_comp; + /*!\brief disable Palette + * + */ + unsigned int disable_palette; + /*!\brief disable Intra Block Copy + * + */ + unsigned int disable_intrabc; + /*!\brief disable chroma from luma + * + */ + unsigned int disable_cfl; + /*!\brief disable intra smooth mode + * + */ + unsigned int disable_smooth_intra; + /*!\brief disable filter intra + * + */ + unsigned int disable_filter_intra; + /*!\brief disable dual filter + * + */ + unsigned int disable_dual_filter; + /*!\brief disable intra angle delta + * + */ + unsigned int disable_intra_angle_delta; + /*!\brief disable intra edge filter + * + */ + unsigned int disable_intra_edge_filter; + /*!\brief disable 64x64 transform + * + */ + unsigned int disable_tx_64x64; + /*!\brief disable smooth inter/intra + * + */ + unsigned int disable_smooth_inter_intra; + /*!\brief disable inter/inter wedge comp + * + */ + unsigned int disable_inter_inter_wedge; + /*!\brief disable inter/intra wedge comp + * + */ + unsigned int disable_inter_intra_wedge; + /*!\brief disable paeth intra + * + */ + unsigned int disable_paeth_intra; + /*!\brief disable trellis quantization + * + */ + unsigned int disable_trellis_quant; + /*!\brief disable ref frame MV + * + */ + unsigned int disable_ref_frame_mv; + /*!\brief use reduced reference frame set + * + */ + unsigned int reduced_reference_set; + /*!\brief use reduced transform type set + * + */ + unsigned int reduced_tx_type_set; +} cfg_options_t; + /*!\brief Encoded Frame Flags * * This type indicates a bitfield to be passed to aom_codec_encode(), defining @@ -723,6 +864,47 @@ typedef struct aom_codec_enc_cfg { * The number of heights specified is given by tile_height_count */ int tile_heights[MAX_TILE_HEIGHTS]; + + /*!\brief Whether encoder should use fixed QP offsets. + * + * If a value of 1 is provided, encoder will use fixed QP offsets for frames + * at different levels of the pyramid. + * - If 'fixed_qp_offsets' is also provided, encoder will use the given + * offsets + * - If not, encoder will select the fixed offsets based on the cq-level + * provided. + * If a value of 0 is provided and fixed_qp_offset are not provided, encoder + * will NOT use fixed QP offsets. + * Note: This option is only relevant for --end-usage=q. + */ + unsigned int use_fixed_qp_offsets; + +/*!\brief Number of fixed QP offsets + * + * This defines the number of elements in the fixed_qp_offsets array. + */ +#define FIXED_QP_OFFSET_COUNT 5 + + /*!\brief Array of fixed QP offsets + * + * This array specifies fixed QP offsets (range: 0 to 63) for frames at + * different levels of the pyramid. It is a comma-separated list of 5 values: + * - QP offset for keyframe + * - QP offset for ALTREF frame + * - QP offset for 1st level internal ARF + * - QP offset for 2nd level internal ARF + * - QP offset for 3rd level internal ARF + * Notes: + * - QP offset for leaf level frames is not explicitly specified. These frames + * use the worst quality allowed (--cq-level). + * - This option is only relevant for --end-usage=q. + */ + int fixed_qp_offsets[FIXED_QP_OFFSET_COUNT]; + + /*!\brief Options defined per config file + * + */ + cfg_options_t encoder_cfg; } aom_codec_enc_cfg_t; /**< alias for struct aom_codec_enc_cfg */ /*!\brief Initialize an encoder instance @@ -759,41 +941,9 @@ aom_codec_err_t aom_codec_enc_init_ver(aom_codec_ctx_t *ctx, #define aom_codec_enc_init(ctx, iface, cfg, flags) \ aom_codec_enc_init_ver(ctx, iface, cfg, flags, AOM_ENCODER_ABI_VERSION) -/*!\brief Initialize multi-encoder instance +/*!\brief Get the default configuration for a usage. * - * Initializes multi-encoder context using the given interface. - * Applications should call the aom_codec_enc_init_multi convenience macro - * instead of this function directly, to ensure that the ABI version number - * parameter is properly initialized. - * - * \param[in] ctx Pointer to this instance's context. - * \param[in] iface Pointer to the algorithm interface to use. - * \param[in] cfg Configuration to use, if known. - * \param[in] num_enc Total number of encoders. - * \param[in] flags Bitfield of AOM_CODEC_USE_* flags - * \param[in] dsf Pointer to down-sampling factors. - * \param[in] ver ABI version number. Must be set to - * AOM_ENCODER_ABI_VERSION - * \retval #AOM_CODEC_OK - * The decoder algorithm initialized. - * \retval #AOM_CODEC_MEM_ERROR - * Memory allocation failed. - */ -aom_codec_err_t aom_codec_enc_init_multi_ver( - aom_codec_ctx_t *ctx, aom_codec_iface_t *iface, aom_codec_enc_cfg_t *cfg, - int num_enc, aom_codec_flags_t flags, aom_rational_t *dsf, int ver); - -/*!\brief Convenience macro for aom_codec_enc_init_multi_ver() - * - * Ensures the ABI version parameter is properly set. - */ -#define aom_codec_enc_init_multi(ctx, iface, cfg, num_enc, flags, dsf) \ - aom_codec_enc_init_multi_ver(ctx, iface, cfg, num_enc, flags, dsf, \ - AOM_ENCODER_ABI_VERSION) - -/*!\brief Get a default configuration - * - * Initializes a encoder configuration structure with default values. Supports + * Initializes an encoder configuration structure with default values. Supports * the notion of "usages" so that an algorithm may offer different default * settings depending on the user's intended goal. This function \ref SHOULD * be called by all applications to initialize the configuration structure @@ -801,7 +951,9 @@ aom_codec_err_t aom_codec_enc_init_multi_ver( * * \param[in] iface Pointer to the algorithm interface to use. * \param[out] cfg Configuration buffer to populate. - * \param[in] reserved Must set to 0. + * \param[in] usage Algorithm specific usage value. For AV1, must be + * set to AOM_USAGE_GOOD_QUALITY (0) or + * AOM_USAGE_REALTIME (1). * * \retval #AOM_CODEC_OK * The configuration was populated. @@ -812,7 +964,7 @@ aom_codec_err_t aom_codec_enc_init_multi_ver( */ aom_codec_err_t aom_codec_enc_config_default(aom_codec_iface_t *iface, aom_codec_enc_cfg_t *cfg, - unsigned int reserved); + unsigned int usage); /*!\brief Set or change configuration * diff --git a/media/libaom/src/aom/aom_image.h b/media/libaom/src/aom/aom_image.h index d07d485df4..bb6973f9c3 100644 --- a/media/libaom/src/aom/aom_image.h +++ b/media/libaom/src/aom/aom_image.h @@ -30,7 +30,7 @@ extern "C" { * types, removing or reassigning enums, adding/removing/rearranging * fields to structures */ -#define AOM_IMAGE_ABI_VERSION (6) /**<\hideinitializer*/ +#define AOM_IMAGE_ABI_VERSION (9) /**<\hideinitializer*/ #define AOM_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */ #define AOM_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */ @@ -137,14 +137,34 @@ typedef enum aom_chroma_sample_position { AOM_CSP_RESERVED = 3 /**< Reserved value */ } aom_chroma_sample_position_t; /**< alias for enum aom_transfer_function */ +/*!\brief List of insert flags for Metadata + * + * These flags control how the library treats metadata during encode. + * + * While encoding, when metadata is added to an aom_image via + * aom_img_add_metadata(), the flag passed along with the metadata will + * determine where the metadata OBU will be placed in the encoded OBU stream. + * Metadata will be emitted into the output stream within the next temporal unit + * if it satisfies the specified insertion flag. + * + * During decoding, when the library encounters a metadata OBU, it is always + * flagged as AOM_MIF_ANY_FRAME and emitted with the next output aom_image. + */ +typedef enum aom_metadata_insert_flags { + AOM_MIF_NON_KEY_FRAME = 0, /**< Adds metadata if it's not keyframe */ + AOM_MIF_KEY_FRAME = 1, /**< Adds metadata only if it's a keyframe */ + AOM_MIF_ANY_FRAME = 2 /**< Adds metadata to any type of frame */ +} aom_metadata_insert_flags_t; + /*!\brief Array of aom_metadata structs for an image. */ typedef struct aom_metadata_array aom_metadata_array_t; /*!\brief Metadata payload. */ typedef struct aom_metadata { - uint8_t type; /**< Metadata type */ - uint8_t *payload; /**< Metadata payload data */ - size_t sz; /**< Metadata payload size */ + uint32_t type; /**< Metadata type */ + uint8_t *payload; /**< Metadata payload data */ + size_t sz; /**< Metadata payload size */ + aom_metadata_insert_flags_t insert_flag; /**< Metadata insertion flag */ } aom_metadata_t; /**\brief Image Descriptor */ @@ -204,14 +224,6 @@ typedef struct aom_image { void *fb_priv; /**< Frame buffer data associated with the image. */ } aom_image_t; /**< alias for struct aom_image */ -/**\brief Representation of a rectangle on a surface */ -typedef struct aom_image_rect { - unsigned int x; /**< leftmost column */ - unsigned int y; /**< topmost row */ - unsigned int w; /**< width */ - unsigned int h; /**< height */ -} aom_image_rect_t; /**< alias for struct aom_image_rect */ - /*!\brief Open a descriptor, allocating storage for the underlying image * * Returns a descriptor for storing an image of the given format. The @@ -341,39 +353,67 @@ int aom_img_plane_height(const aom_image_t *img, int plane); * * Adds metadata to aom_image_t. * Function makes a copy of the provided data parameter. + * Metadata insertion point is controlled by insert_flag. * - * \param[in] img Image descriptor - * \param[in] type Metadata type - * \param[in] data Metadata contents - * \param[in] sz Metadata contents size + * \param[in] img Image descriptor + * \param[in] type Metadata type + * \param[in] data Metadata contents + * \param[in] sz Metadata contents size + * \param[in] insert_flag Metadata insert flag */ -int aom_img_add_metadata(aom_image_t *img, uint8_t type, uint8_t *data, - size_t sz); +int aom_img_add_metadata(aom_image_t *img, uint32_t type, const uint8_t *data, + size_t sz, aom_metadata_insert_flags_t insert_flag); + +/*!\brief Return a metadata payload stored within the image metadata array. + * + * Gets the metadata (aom_metadata_t) at the indicated index in the image + * metadata array. + * + * \param[in] img Pointer to image descriptor to get metadata from + * \param[in] index Metadata index to get from metadata array + * + * \return Returns a const pointer to the selected metadata, if img and/or index + * is invalid, it returns NULL. + */ +const aom_metadata_t *aom_img_get_metadata(const aom_image_t *img, + size_t index); + +/*!\brief Return the number of metadata blocks within the image. + * + * Gets the number of metadata blocks contained within the provided image + * metadata array. + * + * \param[in] img Pointer to image descriptor to get metadata number + * from. + * + * \return Returns the size of the metadata array. If img or metadata is NULL, + * it returns 0. + */ +size_t aom_img_num_metadata(const aom_image_t *img); /*!\brief Remove metadata from image. * * Removes all metadata in image metadata list and sets metadata list pointer * to NULL. - * Returns the number of deleted metadata structs. * * \param[in] img Image descriptor */ -size_t aom_img_remove_metadata(aom_image_t *img); +void aom_img_remove_metadata(aom_image_t *img); /*!\brief Allocate memory for aom_metadata struct. * - * Allocates memory for aom_metadata struct and sets its type. Optionally - * allocates storage for the metadata payload and copies the payload data - * into the aom_metadata struct: - * - When sz is > 0 and data is NULL, allocates metadata payload buffer of sz. - * - When sz is > 0 and data is non-NULL, a metadata payload buffer of sz - * is allocated and sz bytes are copied from data into the payload buffer. + * Allocates storage for the metadata payload, sets its type and copies the + * payload data into the aom_metadata struct. A metadata payload buffer of size + * sz is allocated and sz bytes are copied from data into the payload buffer. * - * \param[in] type Metadata type - * \param[in] data Metadata data pointer - * \param[in] sz Metadata size + * \param[in] type Metadata type + * \param[in] data Metadata data pointer + * \param[in] sz Metadata size + * \param[in] insert_flag Metadata insert flag */ -aom_metadata_t *aom_img_metadata_alloc(uint8_t type, uint8_t *data, size_t sz); +aom_metadata_t *aom_img_metadata_alloc(uint32_t type, const uint8_t *data, + size_t sz, + aom_metadata_insert_flags_t insert_flag); /*!\brief Free metadata struct. * @@ -381,7 +421,7 @@ aom_metadata_t *aom_img_metadata_alloc(uint8_t type, uint8_t *data, size_t sz); * * \param[in] metadata Metadata struct pointer */ -int aom_img_metadata_free(aom_metadata_t *metadata); +void aom_img_metadata_free(aom_metadata_t *metadata); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/aom/aom_integer.h b/media/libaom/src/aom/aom_integer.h index 90263bd4f2..113671e820 100644 --- a/media/libaom/src/aom/aom_integer.h +++ b/media/libaom/src/aom/aom_integer.h @@ -19,7 +19,6 @@ #define AOM_INLINE __inline #else #define AOM_FORCE_INLINE __inline__ __attribute__((always_inline)) -// TODO(jbb): Allow a way to force inline off for older compilers. #define AOM_INLINE inline #endif @@ -72,8 +71,6 @@ typedef size_t uintptr_t; #define INT32_MIN (-2147483647 - 1) #endif -#define NELEMENTS(x) (int)(sizeof(x) / sizeof(x[0])) - #if defined(__cplusplus) extern "C" { #endif // __cplusplus diff --git a/media/libaom/src/aom/aomcx.h b/media/libaom/src/aom/aomcx.h index d614bd7969..051d33e7bf 100644 --- a/media/libaom/src/aom/aomcx.h +++ b/media/libaom/src/aom/aomcx.h @@ -148,85 +148,114 @@ extern aom_codec_iface_t *aom_codec_av1_cx(void); * This set of macros define the control functions available for AVx * encoder interface. * - * \sa #aom_codec_control + * \sa #aom_codec_control(aom_codec_ctx_t *ctx, int ctrl_id, ...) */ enum aome_enc_control_id { - /*!\brief Codec control function to set which reference frame encoder can use. + /*!\brief Codec control function to set which reference frame encoder can use, + * int parameter. */ AOME_USE_REFERENCE = 7, - /*!\brief Codec control function to pass an ROI map to encoder. + /*!\brief Codec control function to pass an ROI map to encoder, aom_roi_map_t* + * parameter. */ AOME_SET_ROI_MAP = 8, - /*!\brief Codec control function to pass an Active map to encoder. + /*!\brief Codec control function to pass an Active map to encoder, + * aom_active_map_t* parameter. */ - AOME_SET_ACTIVEMAP, + AOME_SET_ACTIVEMAP = 9, - /*!\brief Codec control function to set encoder scaling mode. + /* NOTE: enum 10 unused */ + + /*!\brief Codec control function to set encoder scaling mode, + * aom_scaling_mode_t* parameter. */ AOME_SET_SCALEMODE = 11, - /*!\brief Codec control function to set encoder spatial layer id. + /*!\brief Codec control function to set encoder spatial layer id, unsigned int + * parameter. */ AOME_SET_SPATIAL_LAYER_ID = 12, - /*!\brief Codec control function to set encoder internal speed settings. + /*!\brief Codec control function to set encoder internal speed settings, + * int parameter * * Changes in this value influences the complexity of algorithms used in * encoding process, values greater than 0 will increase encoder speed at * the expense of quality. * - * \note Valid range: 0..8 + * Valid range: 0..8. 0 runs the slowest, and 8 runs the fastest; + * quality improves as speed decreases (since more compression + * possibilities are explored). */ AOME_SET_CPUUSED = 13, - /*!\brief Codec control function to enable automatic set and use alf frames. + /*!\brief Codec control function to enable automatic set and use alf frames, + * unsigned int parameter + * + * - 0 = disable + * - 1 = enable (default) */ - AOME_SET_ENABLEAUTOALTREF, + AOME_SET_ENABLEAUTOALTREF = 14, - /*!\brief Codec control function to set sharpness. + /* NOTE: enum 15 unused */ + + /*!\brief Codec control function to set sharpness, unsigned int parameter. */ - AOME_SET_SHARPNESS = AOME_SET_ENABLEAUTOALTREF + 2, + AOME_SET_SHARPNESS = AOME_SET_ENABLEAUTOALTREF + 2, // 16 - /*!\brief Codec control function to set the threshold for MBs treated static. + /*!\brief Codec control function to set the threshold for MBs treated static, + * unsigned int parameter */ - AOME_SET_STATIC_THRESHOLD, + AOME_SET_STATIC_THRESHOLD = 17, - /*!\brief Codec control function to get last quantizer chosen by the encoder. + /* NOTE: enum 18 unused */ + + /*!\brief Codec control function to get last quantizer chosen by the encoder, + * int* parameter * * Return value uses internal quantizer scale defined by the codec. */ - AOME_GET_LAST_QUANTIZER = AOME_SET_STATIC_THRESHOLD + 2, + AOME_GET_LAST_QUANTIZER = AOME_SET_STATIC_THRESHOLD + 2, // 19 - /*!\brief Codec control function to get last quantizer chosen by the encoder. + /*!\brief Codec control function to get last quantizer chosen by the encoder, + * int* parameter * * Return value uses the 0..63 scale as used by the rc_*_quantizer config * parameters. */ - AOME_GET_LAST_QUANTIZER_64, + AOME_GET_LAST_QUANTIZER_64 = 20, - /*!\brief Codec control function to set the max no of frames to create arf. + /*!\brief Codec control function to set the max no of frames to create arf, + * unsigned int parameter */ - AOME_SET_ARNR_MAXFRAMES, + AOME_SET_ARNR_MAXFRAMES = 21, - /*!\brief Codec control function to set the filter strength for the arf. + /*!\brief Codec control function to set the filter strength for the arf, + * unsigned int parameter */ - AOME_SET_ARNR_STRENGTH, + AOME_SET_ARNR_STRENGTH = 22, - /*!\brief Codec control function to set visual tuning. + /* NOTE: enum 23 unused */ + + /*!\brief Codec control function to set visual tuning, aom_tune_metric (int) + * parameter */ - AOME_SET_TUNING = AOME_SET_ARNR_STRENGTH + 2, + AOME_SET_TUNING = AOME_SET_ARNR_STRENGTH + 2, // 24 - /*!\brief Codec control function to set constrained / constant quality level. + /*!\brief Codec control function to set constrained / constant quality level, + * unsigned int parameter + * + * Valid range: 0..63 * * \attention For this value to be used aom_codec_enc_cfg_t::rc_end_usage * must be set to #AOM_CQ or #AOM_Q. - * \note Valid range: 0..63 */ - AOME_SET_CQ_LEVEL, + AOME_SET_CQ_LEVEL = 25, - /*!\brief Codec control function to set Max data rate for Intra frames. + /*!\brief Codec control function to set max data rate for intra frames, + * unsigned int parameter * * This value controls additional clamping on the maximum size of a * keyframe. It is expressed as a percentage of the average @@ -237,13 +266,15 @@ enum aome_enc_control_id { * For example, to allocate no more than 4.5 frames worth of bitrate * to a keyframe, set this to 450. */ - AOME_SET_MAX_INTRA_BITRATE_PCT, + AOME_SET_MAX_INTRA_BITRATE_PCT = 26, - /*!\brief Codec control function to set number of spatial layers. + /*!\brief Codec control function to set number of spatial layers, int + * parameter */ - AOME_SET_NUMBER_SPATIAL_LAYERS, + AOME_SET_NUMBER_SPATIAL_LAYERS = 27, - /*!\brief Codec control function to set max data rate for Inter frames. + /*!\brief Codec control function to set max data rate for inter frames, + * unsigned int parameter * * This value controls additional clamping on the maximum size of an * inter frame. It is expressed as a percentage of the average @@ -254,9 +285,10 @@ enum aome_enc_control_id { * For example, to allow no more than 4.5 frames worth of bitrate * to an inter frame, set this to 450. */ - AV1E_SET_MAX_INTER_BITRATE_PCT = AOME_SET_MAX_INTRA_BITRATE_PCT + 2, + AV1E_SET_MAX_INTER_BITRATE_PCT = AOME_SET_MAX_INTRA_BITRATE_PCT + 2, // 28 - /*!\brief Boost percentage for Golden Frame in CBR mode. + /*!\brief Boost percentage for Golden Frame in CBR mode, unsigned int + * parameter * * This value controls the amount of boost given to Golden Frame in * CBR mode. It is expressed as a percentage of the average @@ -267,74 +299,85 @@ enum aome_enc_control_id { * For example, to allow 100% more bits, i.e, 2X, in a golden frame * than average frame, set this to 100. */ - AV1E_SET_GF_CBR_BOOST_PCT, + AV1E_SET_GF_CBR_BOOST_PCT = 29, - /*!\brief Codec control function to set lossless encoding mode. + /* NOTE: enum 30 unused */ + + /*!\brief Codec control function to set lossless encoding mode, unsigned int + * parameter * * AV1 can operate in lossless encoding mode, in which the bitstream * produced will be able to decode and reconstruct a perfect copy of - * input source. This control function provides a mean to switch encoder - * into lossless coding mode(1) or normal coding mode(0) that may be lossy. - * 0 = lossy coding mode - * 1 = lossless coding mode + * input source. * - * By default, encoder operates in normal coding mode (maybe lossy). + * - 0 = normal coding mode, may be lossy (default) + * - 1 = lossless coding mode */ - AV1E_SET_LOSSLESS = AV1E_SET_GF_CBR_BOOST_PCT + 2, + AV1E_SET_LOSSLESS = AV1E_SET_GF_CBR_BOOST_PCT + 2, // 31 - /** control function to enable the row based multi-threading of encoder. A - * value that is equal to 1 indicates that row based multi-threading is - * enabled. + /*!\brief Codec control function to enable the row based multi-threading + * of the encoder, unsigned int parameter + * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ROW_MT, + AV1E_SET_ROW_MT = 32, - /*!\brief Codec control function to set number of tile columns. + /*!\brief Codec control function to set number of tile columns. unsigned int + * parameter * * In encoding and decoding, AV1 allows an input image frame be partitioned * into separate vertical tile columns, which can be encoded or decoded * independently. This enables easy implementation of parallel encoding and * decoding. The parameter for this control describes the number of tile * columns (in log2 units), which has a valid range of [0, 6]: - * 0 = 1 tile column - * 1 = 2 tile columns - * 2 = 4 tile columns - * ..... - * n = 2**n tile columns - * + * \verbatim + 0 = 1 tile column + 1 = 2 tile columns + 2 = 4 tile columns + ..... + n = 2**n tile columns + \endverbatim * By default, the value is 0, i.e. one single column tile for entire image. */ - AV1E_SET_TILE_COLUMNS, + AV1E_SET_TILE_COLUMNS = 33, - /*!\brief Codec control function to set number of tile rows. + /*!\brief Codec control function to set number of tile rows, unsigned int + * parameter * * In encoding and decoding, AV1 allows an input image frame be partitioned * into separate horizontal tile rows, which can be encoded or decoded * independently. The parameter for this control describes the number of tile * rows (in log2 units), which has a valid range of [0, 6]: - * 0 = 1 tile row - * 1 = 2 tile rows - * 2 = 4 tile rows - * ..... - * n = 2**n tile rows - * + * \verbatim + 0 = 1 tile row + 1 = 2 tile rows + 2 = 4 tile rows + ..... + n = 2**n tile rows + \endverbatim * By default, the value is 0, i.e. one single row tile for entire image. */ - AV1E_SET_TILE_ROWS, + AV1E_SET_TILE_ROWS = 34, /*!\brief Codec control function to enable RDO modulated by frame temporal - * dependency. + * dependency, unsigned int parameter * - * By default, this feature is off. + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_TPL_MODEL, + AV1E_SET_ENABLE_TPL_MODEL = 35, - /*!\brief Codec control function to enable temporal filtering on key frame. + /*!\brief Codec control function to enable temporal filtering on key frame, + * unsigned int parameter * - * By default, this feature is on. + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_KEYFRAME_FILTERING, + AV1E_SET_ENABLE_KEYFRAME_FILTERING = 36, - /*!\brief Codec control function to enable frame parallel decoding feature. + /*!\brief Codec control function to enable frame parallel decoding feature, + * unsigned int parameter * * AV1 has a bitstream feature to reduce decoding dependency between frames * by turning off backward update of probability context used in encoding @@ -342,304 +385,301 @@ enum aome_enc_control_id { * video frames in the decoder. This control function provides a mean to * turn this feature on or off for bitstreams produced by encoder. * - * By default, this feature is off. + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_FRAME_PARALLEL_DECODING, + AV1E_SET_FRAME_PARALLEL_DECODING = 37, - /*!\brief Codec control function to enable error_resilient_mode + /*!\brief Codec control function to enable error_resilient_mode, int parameter * * AV1 has a bitstream feature to guarantee parseability of a frame * by turning on the error_resilient_decoding mode, even though the * reference buffers are unreliable or not received. * - * By default, this feature is off. + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_ERROR_RESILIENT_MODE, + AV1E_SET_ERROR_RESILIENT_MODE = 38, - /*!\brief Codec control function to enable s_frame_mode + /*!\brief Codec control function to enable s_frame_mode, int parameter * * AV1 has a bitstream feature to designate certain frames as S-frames, * from where we can switch to a different stream, * even though the reference buffers may not be exactly identical. * - * By default, this feature is off. + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_S_FRAME_MODE, + AV1E_SET_S_FRAME_MODE = 39, - /*!\brief Codec control function to set adaptive quantization mode. + /*!\brief Codec control function to set adaptive quantization mode, unsigned + * int parameter * * AV1 has a segment based feature that allows encoder to adaptively change * quantization parameter for each segment within a frame to improve the * subjective quality. This control makes encoder operate in one of the * several AQ_modes supported. * - * By default, encoder operates with AQ_Mode 0(adaptive quantization off). + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_AQ_MODE, + AV1E_SET_AQ_MODE = 40, - /*!\brief Codec control function to enable/disable periodic Q boost. + /*!\brief Codec control function to enable/disable periodic Q boost, unsigned + * int parameter * * One AV1 encoder speed feature is to enable quality boost by lowering * frame level Q periodically. This control function provides a mean to * turn on/off this feature. - * 0 = off - * 1 = on * - * By default, the encoder is allowed to use this feature for appropriate - * encoding modes. + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_FRAME_PERIODIC_BOOST, + AV1E_SET_FRAME_PERIODIC_BOOST = 41, - /*!\brief Codec control function to set noise sensitivity. + /*!\brief Codec control function to set noise sensitivity, unsigned int + * parameter * - * 0: off, 1: On(YOnly) + * - 0 = disable (default) + * - 1 = enable (Y only) */ - AV1E_SET_NOISE_SENSITIVITY, + AV1E_SET_NOISE_SENSITIVITY = 42, - /*!\brief Codec control function to set content type. - * \note Valid parameter range: - * AOM_CONTENT_DEFAULT = Regular video content (Default) - * AOM_CONTENT_SCREEN = Screen capture content - */ - AV1E_SET_TUNE_CONTENT, - - /*!\brief Codec control function to set CDF update mode. + /*!\brief Codec control function to set content type, aom_tune_content + * parameter * - * 0: no update 1: update on every frame - * 2: selectively update + * - AOM_CONTENT_DEFAULT = Regular video content (default) + * - AOM_CONTENT_SCREEN = Screen capture content */ - AV1E_SET_CDF_UPDATE_MODE, + AV1E_SET_TUNE_CONTENT = 43, - /*!\brief Codec control function to set color space info. - * \note Valid ranges: 0..23, default is "Unspecified". - * 0 = For future use - * 1 = BT.709 - * 2 = Unspecified - * 3 = For future use - * 4 = BT.470 System M (historical) - * 5 = BT.470 System B, G (historical) - * 6 = BT.601 - * 7 = SMPTE 240 - * 8 = Generic film (color filters using illuminant C) - * 9 = BT.2020, BT.2100 - * 10 = SMPTE 428 (CIE 1921 XYZ) - * 11 = SMPTE RP 431-2 - * 12 = SMPTE EG 432-1 - * 13 = For future use (values 13 - 21) - * 22 = EBU Tech. 3213-E - * 23 = For future use + /*!\brief Codec control function to set CDF update mode, unsigned int + * parameter * + * - 0: no update + * - 1: update on every frame (default) + * - 2: selectively update */ - AV1E_SET_COLOR_PRIMARIES, + AV1E_SET_CDF_UPDATE_MODE = 44, - /*!\brief Codec control function to set transfer function info. - * \note Valid ranges: 0..19, default is "Unspecified". - * 0 = For future use - * 1 = BT.709 - * 2 = Unspecified - * 3 = For future use - * 4 = BT.470 System M (historical) - * 5 = BT.470 System B, G (historical) - * 6 = BT.601 - * 7 = SMPTE 240 M - * 8 = Linear - * 9 = Logarithmic (100 : 1 range) - * 10 = Logarithmic (100 * Sqrt(10) : 1 range) - * 11 = IEC 61966-2-4 - * 12 = BT.1361 - * 13 = sRGB or sYCC - * 14 = BT.2020 10-bit systems - * 15 = BT.2020 12-bit systems - * 16 = SMPTE ST 2084, ITU BT.2100 PQ - * 17 = SMPTE ST 428 - * 18 = BT.2100 HLG, ARIB STD-B67 - * 19 = For future use + /*!\brief Codec control function to set color space info, int parameter * + * - 0 = For future use + * - 1 = BT.709 + * - 2 = Unspecified (default) + * - 3 = For future use + * - 4 = BT.470 System M (historical) + * - 5 = BT.470 System B, G (historical) + * - 6 = BT.601 + * - 7 = SMPTE 240 + * - 8 = Generic film (color filters using illuminant C) + * - 9 = BT.2020, BT.2100 + * - 10 = SMPTE 428 (CIE 1921 XYZ) + * - 11 = SMPTE RP 431-2 + * - 12 = SMPTE EG 432-1 + * - 13..21 = For future use + * - 22 = EBU Tech. 3213-E + * - 23 = For future use */ - AV1E_SET_TRANSFER_CHARACTERISTICS, + AV1E_SET_COLOR_PRIMARIES = 45, - /*!\brief Codec control function to set transfer function info. - * \note Valid ranges: 0..15, default is "Unspecified". - * 0 = Identity matrix - * 1 = BT.709 - * 2 = Unspecified - * 3 = For future use - * 4 = US FCC 73.628 - * 5 = BT.470 System B, G (historical) - * 6 = BT.601 - * 7 = SMPTE 240 M - * 8 = YCgCo - * 9 = BT.2020 non-constant luminance, BT.2100 YCbCr - * 10 = BT.2020 constant luminance - * 11 = SMPTE ST 2085 YDzDx - * 12 = Chromaticity-derived non-constant luminance - * 13 = Chromaticity-derived constant luminance - * 14 = BT.2100 ICtCp - * 15 = For future use + /*!\brief Codec control function to set transfer function info, int parameter * + * - 0 = For future use + * - 1 = BT.709 + * - 2 = Unspecified (default) + * - 3 = For future use + * - 4 = BT.470 System M (historical) + * - 5 = BT.470 System B, G (historical) + * - 6 = BT.601 + * - 7 = SMPTE 240 M + * - 8 = Linear + * - 9 = Logarithmic (100 : 1 range) + * - 10 = Logarithmic (100 * Sqrt(10) : 1 range) + * - 11 = IEC 61966-2-4 + * - 12 = BT.1361 + * - 13 = sRGB or sYCC + * - 14 = BT.2020 10-bit systems + * - 15 = BT.2020 12-bit systems + * - 16 = SMPTE ST 2084, ITU BT.2100 PQ + * - 17 = SMPTE ST 428 + * - 18 = BT.2100 HLG, ARIB STD-B67 + * - 19 = For future use */ - AV1E_SET_MATRIX_COEFFICIENTS, + AV1E_SET_TRANSFER_CHARACTERISTICS = 46, - /*!\brief Codec control function to set chroma 4:2:0 sample position info. - * \note Valid ranges: 0..3, default is "UNKNOWN". - * 0 = UNKNOWN, - * 1 = VERTICAL - * 2 = COLOCATED - * 3 = RESERVED + /*!\brief Codec control function to set transfer function info, int parameter + * + * - 0 = Identity matrix + * - 1 = BT.709 + * - 2 = Unspecified (default) + * - 3 = For future use + * - 4 = US FCC 73.628 + * - 5 = BT.470 System B, G (historical) + * - 6 = BT.601 + * - 7 = SMPTE 240 M + * - 8 = YCgCo + * - 9 = BT.2020 non-constant luminance, BT.2100 YCbCr + * - 10 = BT.2020 constant luminance + * - 11 = SMPTE ST 2085 YDzDx + * - 12 = Chromaticity-derived non-constant luminance + * - 13 = Chromaticity-derived constant luminance + * - 14 = BT.2100 ICtCp + * - 15 = For future use */ - AV1E_SET_CHROMA_SAMPLE_POSITION, + AV1E_SET_MATRIX_COEFFICIENTS = 47, - /*!\brief Codec control function to set minimum interval between GF/ARF frames + /*!\brief Codec control function to set chroma 4:2:0 sample position info, + * aom_chroma_sample_position_t parameter + * + * AOM_CSP_UNKNOWN is default + */ + AV1E_SET_CHROMA_SAMPLE_POSITION = 48, + + /*!\brief Codec control function to set minimum interval between GF/ARF + * frames, unsigned int parameter * * By default the value is set as 4. */ - AV1E_SET_MIN_GF_INTERVAL, + AV1E_SET_MIN_GF_INTERVAL = 49, - /*!\brief Codec control function to set minimum interval between GF/ARF frames + /*!\brief Codec control function to set minimum interval between GF/ARF + * frames, unsigned int parameter * * By default the value is set as 16. */ - AV1E_SET_MAX_GF_INTERVAL, + AV1E_SET_MAX_GF_INTERVAL = 50, - /*!\brief Codec control function to get an Active map back from the encoder. + /*!\brief Codec control function to get an active map back from the encoder, + aom_active_map_t* parameter */ - AV1E_GET_ACTIVEMAP, + AV1E_GET_ACTIVEMAP = 51, - /*!\brief Codec control function to set color range bit. - * \note Valid ranges: 0..1, default is 0 - * 0 = Limited range (16..235 or HBD equivalent) - * 1 = Full range (0..255 or HBD equivalent) + /*!\brief Codec control function to set color range bit, int parameter + * + * - 0 = Limited range, 16..235 or HBD equivalent (default) + * - 1 = Full range, 0..255 or HBD equivalent */ - AV1E_SET_COLOR_RANGE, + AV1E_SET_COLOR_RANGE = 52, - /*!\brief Codec control function to set intended rendering image size. + /*!\brief Codec control function to set intended rendering image size, + * int32_t[2] parameter * * By default, this is identical to the image size in pixels. */ - AV1E_SET_RENDER_SIZE, + AV1E_SET_RENDER_SIZE = 53, /*!\brief Control to set target sequence level index for a certain operating - * point(OP). + * point(OP), int parameter * 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 24(keep level stats only for level monitoring) 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. + * - AB: OP index. + * - xy: Target level index for the OP. Can be values 0~23(corresponding to + * level 2.0 ~ 7.3) or 24(keep level stats only for level monitoring) 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_SEQ_LEVEL_IDX, + AV1E_SET_TARGET_SEQ_LEVEL_IDX = 54, /*!\brief Codec control function to get sequence level index for each - * operating point. There can be at most 32 operating points. The results will - * be written into a provided integer array of sufficient size. + * operating point. int* parameter. There can be at most 32 operating points. + * The results will be written into a provided integer array of sufficient + * size. */ - AV1E_GET_SEQ_LEVEL_IDX, + AV1E_GET_SEQ_LEVEL_IDX = 55, - /*!\brief Codec control function to set intended superblock size. + /*!\brief Codec control function to set intended superblock size, unsigned int + * parameter * * By default, the superblock size is determined separately for each * frame by the encoder. - * - * Experiment: EXT_PARTITION */ - AV1E_SET_SUPERBLOCK_SIZE, + AV1E_SET_SUPERBLOCK_SIZE = 56, - /*!\brief Codec control function to enable automatic set and use - * bwd-pred frames. + /*!\brief Codec control function to enable automatic set and use of + * bwd-pred frames, unsigned int parameter * + * - 0 = disable (default) + * - 1 = enable */ - AOME_SET_ENABLEAUTOBWDREF, + AOME_SET_ENABLEAUTOBWDREF = 57, - /*!\brief Codec control function to encode with CDEF. + /*!\brief Codec control function to encode with CDEF, unsigned int parameter * * CDEF is the constrained directional enhancement filter which is an * in-loop filter aiming to remove coding artifacts - * 0 = do not apply CDEF - * 1 = apply CDEF * - * By default, the encoder applies CDEF. - * - * Experiment: AOM_CDEF + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_CDEF, + AV1E_SET_ENABLE_CDEF = 58, - /*!\brief Codec control function to encode with Loop Restoration Filter. - * - * 0 = do not apply Restoration Filter - * 1 = apply Restoration Filter - * - * By default, the encoder applies Restoration Filter. + /*!\brief Codec control function to encode with Loop Restoration Filter, + * unsigned int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_RESTORATION, + AV1E_SET_ENABLE_RESTORATION = 59, - /*!\brief Codec control function to force video mode - * - * 0 = do not force video mode - * 1 = force video mode even for a single frame - * - * By default, the encoder does not force video and allows still picture. + /*!\brief Codec control function to force video mode, unsigned int parameter * + * - 0 = do not force video mode (default) + * - 1 = force video mode even for a single frame */ - AV1E_SET_FORCE_VIDEO_MODE, + AV1E_SET_FORCE_VIDEO_MODE = 60, - /*!\brief Codec control function to predict with OBMC mode. - * - * 0 = do not allow OBMC mode - * 1 = allow OBMC mode - * - * By default, the encoder allows OBMC prediction mode. + /*!\brief Codec control function to predict with OBMC mode, unsigned int + * parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_OBMC, + AV1E_SET_ENABLE_OBMC = 61, - /*!\brief Codec control function to encode without trellis quantization. - * - * 0 = apply trellis quantization - * 1 = do not apply trellis quantization - * 2 = disable trellis quantization in rd search - * 3 = disable trellis quantization in estimate yrd - * - * By default, the encoder applies optimization on quantized - * coefficients. + /*!\brief Codec control function to encode without trellis quantization, + * unsigned int parameter * + * - 0 = apply trellis quantization (default) + * - 1 = do not apply trellis quantization + * - 2 = disable trellis quantization in rd search + * - 3 = disable trellis quantization in estimate yrd */ - AV1E_SET_DISABLE_TRELLIS_QUANT, + AV1E_SET_DISABLE_TRELLIS_QUANT = 62, - /*!\brief Codec control function to encode with quantisation matrices. + /*!\brief Codec control function to encode with quantisation matrices, + * unsigned int parameter * * AOM can operate with default quantisation matrices dependent on * quantisation level and block type. - * 0 = do not use quantisation matrices - * 1 = use quantisation matrices * - * By default, the encoder operates without quantisation matrices. - * - * Experiment: AOM_QM + * - 0 = disable (default) + * - 1 = enable */ + AV1E_SET_ENABLE_QM = 63, - AV1E_SET_ENABLE_QM, - - /*!\brief Codec control function to set the min quant matrix flatness. + /*!\brief Codec control function to set the min quant matrix flatness, + * unsigned int parameter * * AOM can operate with different ranges of quantisation matrices. * As quantisation levels increase, the matrices get flatter. This * control sets the minimum level of flatness from which the matrices * are determined. * - * By default, the encoder sets this minimum at half the available - * range. - * - * Experiment: AOM_QM + * By default, the encoder sets this minimum at half the available + * range. */ - AV1E_SET_QM_MIN, + AV1E_SET_QM_MIN = 64, - /*!\brief Codec control function to set the max quant matrix flatness. + /*!\brief Codec control function to set the max quant matrix flatness, + * unsigned int parameter * * AOM can operate with different ranges of quantisation matrices. * As quantisation levels increase, the matrices get flatter. This @@ -647,524 +687,575 @@ enum aome_enc_control_id { * * By default, the encoder sets this maximum at the top of the * available range. - * - * Experiment: AOM_QM */ - AV1E_SET_QM_MAX, + AV1E_SET_QM_MAX = 65, - /*!\brief Codec control function to set the min quant matrix flatness. + /*!\brief Codec control function to set the min quant matrix flatness, + * unsigned int parameter * * AOM can operate with different ranges of quantisation matrices. * As quantisation levels increase, the matrices get flatter. This * control sets the flatness for luma (Y). * - * By default, the encoder sets this minimum at half the available - * range. - * - * Experiment: AOM_QM + * By default, the encoder sets this minimum at half the available + * range. */ - AV1E_SET_QM_Y, + AV1E_SET_QM_Y = 66, - /*!\brief Codec control function to set the min quant matrix flatness. + /*!\brief Codec control function to set the min quant matrix flatness, + * unsigned int parameter * * AOM can operate with different ranges of quantisation matrices. * As quantisation levels increase, the matrices get flatter. This * control sets the flatness for chroma (U). * - * By default, the encoder sets this minimum at half the available - * range. - * - * Experiment: AOM_QM + * By default, the encoder sets this minimum at half the available + * range. */ - AV1E_SET_QM_U, + AV1E_SET_QM_U = 67, - /*!\brief Codec control function to set the min quant matrix flatness. + /*!\brief Codec control function to set the min quant matrix flatness, + * unsigned int parameter * * AOM can operate with different ranges of quantisation matrices. * As quantisation levels increase, the matrices get flatter. This * control sets the flatness for chrome (V). * - * By default, the encoder sets this minimum at half the available - * range. - * - * Experiment: AOM_QM + * By default, the encoder sets this minimum at half the available + * range. */ - AV1E_SET_QM_V, + AV1E_SET_QM_V = 68, - /*!\brief Codec control function to encode with dist_8x8. - * - * The dist_8x8 is enabled automatically for model tuning parameters that - * require measuring distortion at the 8x8 level. This control also allows - * measuring distortion at the 8x8 level for other tuning options - * (e.g., PSNR), for testing purposes. - * 0 = do not use dist_8x8 - * 1 = use dist_8x8 - * - * By default, the encoder does not use dist_8x8 - * - * Experiment: DIST_8X8 - */ - AV1E_SET_ENABLE_DIST_8X8, + /* NOTE: enum 69 unused */ - /*!\brief Codec control function to set a maximum number of tile groups. + /*!\brief Codec control function to set a maximum number of tile groups, + * unsigned int parameter * * This will set the maximum number of tile groups. This will be * overridden if an MTU size is set. The default value is 1. - * - * Experiment: TILE_GROUPS */ - AV1E_SET_NUM_TG, + AV1E_SET_NUM_TG = 70, - /*!\brief Codec control function to set an MTU size for a tile group. + /*!\brief Codec control function to set an MTU size for a tile group, unsigned + * int parameter * * This will set the maximum number of bytes in a tile group. This can be * exceeded only if a single tile is larger than this amount. * * By default, the value is 0, in which case a fixed number of tile groups * is used. - * - * Experiment: TILE_GROUPS */ - AV1E_SET_MTU, + AV1E_SET_MTU = 71, - /*!\brief Codec control function to set the number of symbols in an ANS data - * window. + /* NOTE: enum 72 unused */ + + /*!\brief Codec control function to enable/disable rectangular partitions, int + * parameter * - * The number of ANS symbols (both boolean and non-booleans alphabets) in an - * ANS data window is set to 1 << value. - * - * \note Valid range: [8, 23] - * - * Experiment: ANS + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ANS_WINDOW_SIZE_LOG2, + AV1E_SET_ENABLE_RECT_PARTITIONS = 73, - /*!\brief Codec control function to enable/disable rectangular partitions. - * - * This will enable or disable usage of rectangular partitions. The default - * value is 1. + /*!\brief Codec control function to enable/disable AB partitions, int + * parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_RECT_PARTITIONS, + AV1E_SET_ENABLE_AB_PARTITIONS = 74, - /*!\brief Codec control function to enable/disable AB partitions. - * - * This will enable or disable usage of AB partitions. The default - * value is 1. + /*!\brief Codec control function to enable/disable 1:4 and 4:1 partitions, int + * parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_AB_PARTITIONS, + AV1E_SET_ENABLE_1TO4_PARTITIONS = 75, - /*!\brief Codec control function to enable/disable 1:4 and 4:1 partitions. + /*!\brief Codec control function to set min partition size, int parameter * - * 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. * + * Valid values: [4, 8, 16, 32, 64, 128]. The default value is 4 for + * 4x4. */ - AV1E_SET_MIN_PARTITION_SIZE, + AV1E_SET_MIN_PARTITION_SIZE = 76, - /*!\brief Codec control function to set max partition size. + /*!\brief Codec control function to set max partition size, int parameter * - * 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. + * + * Valid values:[4, 8, 16, 32, 64, 128] The default value is 128 for + * 128x128. */ - AV1E_SET_MAX_PARTITION_SIZE, + AV1E_SET_MAX_PARTITION_SIZE = 77, /*!\brief Codec control function to turn on / off intra edge filter - * at sequence level. - * - * This will enable or disable usage of intra-edge filtering. The default - * value is 1. + * at sequence level, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_INTRA_EDGE_FILTER, + AV1E_SET_ENABLE_INTRA_EDGE_FILTER = 78, - /*!\brief Codec control function to turn on / off frame order hint for a - * few tools: - * - * joint compound mode - * motion field motion vector + /*!\brief Codec control function to turn on / off frame order hint (int + * parameter). Affects: joint compound mode, motion field motion vector, * ref frame sign bias * - * The default value is 1. - * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_ORDER_HINT, + AV1E_SET_ENABLE_ORDER_HINT = 79, - /*!\brief Codec control function to turn on / off 64-length transforms. + /*!\brief Codec control function to turn on / off 64-length transforms, int + * parameter * * This will enable or disable usage of length 64 transforms in any - * direction. The default value is 1. + * direction. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_TX64, + AV1E_SET_ENABLE_TX64 = 80, /*!\brief Codec control function to turn on / off flip and identity - * transforms. + * transforms, int parameter * * 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. + * types in any direction. If enabled, this includes: + * - FLIPADST_DCT + * - DCT_FLIPADST + * - FLIPADST_FLIPADST + * - ADST_FLIPADST + * - FLIPADST_ADST + * - IDTX + * - V_DCT + * - H_DCT + * - V_ADST + * - H_ADST + * - V_FLIPADST + * - H_FLIPADST * - * 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. + * Valid values: + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_TX_SIZE_SEARCH_METHOD, + AV1E_SET_ENABLE_FLIP_IDTX = 81, + + /* Note: enum value 82 unused */ /*!\brief Codec control function to turn on / off dist-wtd compound mode - * at sequence level. + * at sequence level, int parameter * - * This will enable or disable distance-weighted compound mode. The default - * value is 1. If AV1E_SET_ENABLE_ORDER_HINT is 0, then this flag is forced + * This will enable or disable distance-weighted compound mode. + * \attention If AV1E_SET_ENABLE_ORDER_HINT is 0, then this flag is forced * to 0. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_DIST_WTD_COMP, + AV1E_SET_ENABLE_DIST_WTD_COMP = 83, /*!\brief Codec control function to turn on / off ref frame mvs (mfmv) usage - * at sequence level. + * at sequence level, int parameter * - * This will enable or disable usage of MFMV. The default value is 1. - * If AV1E_SET_ENABLE_ORDER_HINT is 0, then this flag is forced to 0. + * \attention If AV1E_SET_ENABLE_ORDER_HINT is 0, then this flag is forced + * to 0. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_REF_FRAME_MVS, + AV1E_SET_ENABLE_REF_FRAME_MVS = 84, /*!\brief Codec control function to set temporal mv prediction - * enabling/disabling at frame level. + * enabling/disabling at frame level, int parameter * - * This will enable or disable temporal mv predicton. The default value is 1. - * If AV1E_SET_ENABLE_REF_FRAME_MVS is 0, then this flag is forced to 0. + * \attention If AV1E_SET_ENABLE_REF_FRAME_MVS is 0, then this flag is + * forced to 0. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ALLOW_REF_FRAME_MVS, + AV1E_SET_ALLOW_REF_FRAME_MVS = 85, - /*!\brief Codec control function to turn on / off dual filter usage - * for a sequence. - * - * This will enable or disable use of dual interpolation filter. - * The default value is 1. + /*!\brief Codec control function to turn on / off dual interpolation filter + * for a sequence, int parameter * + * - 0 = disable + * - 1 = enable */ - AV1E_SET_ENABLE_DUAL_FILTER, + AV1E_SET_ENABLE_DUAL_FILTER = 86, /*!\brief Codec control function to turn on / off delta quantization in chroma - * planes usage for a sequence. - * - * This will enable or disable use of chroma deltaq. - * The default value is 0. + * planes usage for a sequence, int parameter * + * - 0 = disable (default) + * - 1 = enable */ - AV1E_SET_ENABLE_CHROMA_DELTAQ, + AV1E_SET_ENABLE_CHROMA_DELTAQ = 87, /*!\brief Codec control function to turn on / off masked compound usage - * for a sequence. - * - * This will enable or disable usage of wedge and diff-wtd compound - * modes. The default value is 1. + * (wedge and diff-wtd compound modes) for a sequence, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_MASKED_COMP, + AV1E_SET_ENABLE_MASKED_COMP = 88, /*!\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. + * for a sequence, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_ONESIDED_COMP, + AV1E_SET_ENABLE_ONESIDED_COMP = 89, /*!\brief Codec control function to turn on / off interintra compound - * for a sequence. - * - * This will enable or disable usage of inter-intra compound modes. - * The default value is 1. + * for a sequence, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_INTERINTRA_COMP, + AV1E_SET_ENABLE_INTERINTRA_COMP = 90, /*!\brief Codec control function to turn on / off smooth inter-intra - * mode for a sequence. - * - * This will enable or disable usage of smooth inter-intra mode. - * The default value is 1. + * mode for a sequence, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_SMOOTH_INTERINTRA, + AV1E_SET_ENABLE_SMOOTH_INTERINTRA = 91, /*!\brief Codec control function to turn on / off difference weighted - * compound. - * - * This will enable or disable usage of difference weighted compound. - * The default value is 1. + * compound, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_DIFF_WTD_COMP, + AV1E_SET_ENABLE_DIFF_WTD_COMP = 92, /*!\brief Codec control function to turn on / off interinter wedge - * compound. - * - * This will enable or disable usage of interinter wedge compound. - * The default value is 1. + * compound, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_INTERINTER_WEDGE, + AV1E_SET_ENABLE_INTERINTER_WEDGE = 93, /*!\brief Codec control function to turn on / off interintra wedge - * compound. - * - * This will enable or disable usage of interintra wedge compound. - * The default value is 1. + * compound, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_INTERINTRA_WEDGE, + AV1E_SET_ENABLE_INTERINTRA_WEDGE = 94, /*!\brief Codec control function to turn on / off global motion usage - * for a sequence. - * - * This will enable or disable usage of global motion. The default value is 1. + * for a sequence, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_GLOBAL_MOTION, + AV1E_SET_ENABLE_GLOBAL_MOTION = 95, /*!\brief Codec control function to turn on / off warped motion usage - * at sequence level. - * - * This will enable or disable usage of warped motion. The default value is 1. + * at sequence level, int parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_WARPED_MOTION, + AV1E_SET_ENABLE_WARPED_MOTION = 96, /*!\brief Codec control function to turn on / off warped motion usage - * at frame level. + * at frame level, int parameter * - * This will enable or disable usage of warped motion. The default value is 1. - * If AV1E_SET_ENABLE_WARPED_MOTION is 0, then this flag is forced to 0. + * \attention If AV1E_SET_ENABLE_WARPED_MOTION is 0, then this flag is + * forced to 0. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ALLOW_WARPED_MOTION, + AV1E_SET_ALLOW_WARPED_MOTION = 97, /*!\brief Codec control function to turn on / off filter intra usage at - * sequence level. + * sequence level, int parameter * - * This will enable or disable usage of filter intra. The default value is 1. - * If AV1E_SET_ENABLE_FILTER_INTRA is 0, then this flag is forced to 0. + * \attention If AV1E_SET_ENABLE_FILTER_INTRA is 0, then this flag is + * forced to 0. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_FILTER_INTRA, + AV1E_SET_ENABLE_FILTER_INTRA = 98, - /*!\brief Codec control function to turn on / off smooth intra modes usage. + /*!\brief Codec control function to turn on / off smooth intra modes usage, + * int parameter * * This will enable or disable usage of smooth, smooth_h and smooth_v intra - * modes. The default value is 1. + * modes. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_SMOOTH_INTRA, + AV1E_SET_ENABLE_SMOOTH_INTRA = 99, - /*!\brief Codec control function to turn on / off Paeth intra mode usage. - * - * This will enable or disable usage of Paeth intra mode. The default value - * is 1. + /*!\brief Codec control function to turn on / off Paeth intra mode usage, int + * parameter * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_PAETH_INTRA, + AV1E_SET_ENABLE_PAETH_INTRA = 100, - /*!\brief Codec control function to turn on / off CFL uv intra mode usage. + /*!\brief Codec control function to turn on / off CFL uv intra mode usage, int + * parameter * - * This will enable or disable usage of chroma-from-luma intra mode. The - * default value is 1. + * This will enable or disable usage of chroma-from-luma intra mode. * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_CFL_INTRA, + AV1E_SET_ENABLE_CFL_INTRA = 101, - /*!\brief Codec control function to turn on / off frame superresolution. + /*!\brief Codec control function to turn on / off frame superresolution, int + * parameter * - * This will enable or disable frame superresolution. The default value is 1 - * If AV1E_SET_ENABLE_SUPERRES is 0, then this flag is forced to 0. + * \attention If AV1E_SET_ENABLE_SUPERRES is 0, then this flag is forced to 0. + * + * - 0 = disable + * - 1 = enable (default) */ - AV1E_SET_ENABLE_SUPERRES, + AV1E_SET_ENABLE_SUPERRES = 102, /*!\brief Codec control function to turn on / off overlay frames for - * fitlered ALTREF frames. + * filtered ALTREF frames, int parameter * * This will enable or disable coding of overlay frames for filtered ALTREF * frames. When set to 0, overlay frames are not used but show existing frame * is used to display the filtered ALTREF frame as is. As a result the decoded * frame rate remains the same as the display frame rate. The default is 1. */ - AV1E_SET_ENABLE_OVERLAY, + AV1E_SET_ENABLE_OVERLAY = 103, - /*!\brief Codec control function to turn on/off palette mode */ - AV1E_SET_ENABLE_PALETTE, + /*!\brief Codec control function to turn on/off palette mode, int parameter */ + AV1E_SET_ENABLE_PALETTE = 104, - /*!\brief Codec control function to turn on/off intra block copy mode */ - AV1E_SET_ENABLE_INTRABC, + /*!\brief Codec control function to turn on/off intra block copy mode, int + parameter */ + AV1E_SET_ENABLE_INTRABC = 105, - /*!\brief Codec control function to turn on/off intra angle delta */ - AV1E_SET_ENABLE_ANGLE_DELTA, + /*!\brief Codec control function to turn on/off intra angle delta, int + parameter */ + AV1E_SET_ENABLE_ANGLE_DELTA = 106, - /*!\brief Codec control function to set the delta q mode + /*!\brief Codec control function to set the delta q mode, unsigned int + * parameter * * AV1 supports a delta q mode feature, that allows modulating q per - * superblock. This control makes encoder operate in one of several - * DELTA_Q_modes supported: - * 0: Not Supported - * 1: Use modulation to maximize objective quality - * 2: Use modulation to maximize perceptual quality + * superblock. * - * By default, encoder operates with DELTAQ_Mode 0(deltaq signaling off). + * - 0 = deltaq signaling off + * - 1 = use modulation to maximize objective quality (default) + * - 2 = use modulation to maximize perceptual quality */ - AV1E_SET_DELTAQ_MODE, + AV1E_SET_DELTAQ_MODE = 107, /*!\brief Codec control function to turn on/off loopfilter modulation - * when delta q modulation is enabled. Note AV1 only supports loopfilter - * modulation when delta q modulation is enabled as well. + * when delta q modulation is enabled, unsigned int parameter. + * + * \attention AV1 only supports loopfilter modulation when delta q + * modulation is enabled as well. */ - AV1E_SET_DELTALF_MODE, + AV1E_SET_DELTALF_MODE = 108, - /*!\brief Codec control function to set the single tile decoding mode to 0 or - * 1. + /*!\brief Codec control function to set the single tile decoding mode, + * unsigned int parameter * - * 0 means that the single tile decoding is off, and 1 means that the single - * tile decoding is on. + * \attention Only applicable if large scale tiling is on. * - * Experiment: EXT_TILE + * - 0 = single tile decoding is off + * - 1 = single tile decoding is on (default) */ - AV1E_SET_SINGLE_TILE_DECODING, + AV1E_SET_SINGLE_TILE_DECODING = 109, - /*!\brief Codec control function to enable the extreme motion vector unit test - * in AV1. Please note that this is only used in motion vector unit test. + /*!\brief Codec control function to enable the extreme motion vector unit + * test, unsigned int parameter * - * 0 : off, 1 : MAX_EXTREME_MV, 2 : MIN_EXTREME_MV + * - 0 = off + * - 1 = MAX_EXTREME_MV + * - 2 = MIN_EXTREME_MV + * + * \note This is only used in motion vector unit test. */ - AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, + AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST = 110, /*!\brief Codec control function to signal picture timing info in the - * bitstream. \note Valid ranges: 0..1, default is "UNKNOWN". 0 = UNKNOWN, 1 = - * EQUAL + * bitstream, aom_timing_info_type_t parameter. Default is + * AOM_TIMING_UNSPECIFIED. */ - AV1E_SET_TIMING_INFO_TYPE, + AV1E_SET_TIMING_INFO_TYPE = 111, /*!\brief Codec control function to add film grain parameters (one of several - * preset types) info in the bitstream. - * \note Valid ranges: 0..11, default is "0". 0 = UNKNOWN, - * 1..16 = different test vectors for grain + * preset types) info in the bitstream, int parameter + * + Valid range: 0..16, 0 is unknown, 1..16 are test vectors */ - AV1E_SET_FILM_GRAIN_TEST_VECTOR, + AV1E_SET_FILM_GRAIN_TEST_VECTOR = 112, - /*!\brief Codec control function to set the path to the film grain parameters + /*!\brief Codec control function to set the path to the film grain parameters, + * const char* parameter */ - AV1E_SET_FILM_GRAIN_TABLE, + AV1E_SET_FILM_GRAIN_TABLE = 113, - /*!\brief Sets the noise level */ - AV1E_SET_DENOISE_NOISE_LEVEL, + /*!\brief Sets the noise level, int parameter */ + AV1E_SET_DENOISE_NOISE_LEVEL = 114, - /*!\brief Sets the denoisers block size */ - AV1E_SET_DENOISE_BLOCK_SIZE, + /*!\brief Sets the denoisers block size, unsigned int parameter */ + AV1E_SET_DENOISE_BLOCK_SIZE = 115, - /*!\brief Sets the chroma subsampling x value */ - AV1E_SET_CHROMA_SUBSAMPLING_X, + /*!\brief Sets the chroma subsampling x value, unsigned int parameter */ + AV1E_SET_CHROMA_SUBSAMPLING_X = 116, - /*!\brief Sets the chroma subsampling y value */ - AV1E_SET_CHROMA_SUBSAMPLING_Y, + /*!\brief Sets the chroma subsampling y value, unsigned int parameter */ + AV1E_SET_CHROMA_SUBSAMPLING_Y = 117, - /*!\brief Control to use a reduced tx type set */ - AV1E_SET_REDUCED_TX_TYPE_SET, + /*!\brief Control to use a reduced tx type set, int parameter */ + AV1E_SET_REDUCED_TX_TYPE_SET = 118, - /*!\brief Control to use dct only for intra modes */ - AV1E_SET_INTRA_DCT_ONLY, + /*!\brief Control to use dct only for intra modes, int parameter */ + AV1E_SET_INTRA_DCT_ONLY = 119, - /*!\brief Control to use dct only for inter modes */ - AV1E_SET_INTER_DCT_ONLY, + /*!\brief Control to use dct only for inter modes, int parameter */ + AV1E_SET_INTER_DCT_ONLY = 120, - /*!\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: 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 + /*!\brief Control to use default tx type only for intra modes, int parameter */ - AV1E_SET_COEFF_COST_UPD_FREQ, + AV1E_SET_INTRA_DEFAULT_TX_ONLY = 121, - /*!\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 use adaptive quantize_b, int parameter */ + AV1E_SET_QUANT_B_ADAPT = 122, - /*!\brief Control to set frequency of the cost updates for motion vectors - * Possible values are: - * 0: Update at SB level (default) - * 1: Update at SB row level in tile - * 2: Update at tile level + /*!\brief Control to select maximum height for the GF group pyramid structure, + * unsigned int parameter + * + * Valid range: 0..4 */ - AV1E_SET_MV_COST_UPD_FREQ, + AV1E_SET_GF_MAX_PYRAMID_HEIGHT = 123, + + /*!\brief Control to select maximum reference frames allowed per frame, int + * parameter + * + * Valid range: 3..7 + */ + AV1E_SET_MAX_REFERENCE_FRAMES = 124, + + /*!\brief Control to use reduced set of single and compound references, int + parameter */ + AV1E_SET_REDUCED_REFERENCE_SET = 125, + + /* NOTE: enums 126-139 unused */ + /* NOTE: Need a gap in enum values to avoud conflict with 128, 129, 130 */ + + /*!\brief Control to set frequency of the cost updates for coefficients, + * unsigned int parameter + * + * - 0 = update at SB level (default) + * - 1 = update at SB row level in tile + * - 2 = update at tile level + * - 3 = turn off + */ + AV1E_SET_COEFF_COST_UPD_FREQ = 140, + + /*!\brief Control to set frequency of the cost updates for mode, unsigned int + * parameter + * + * - 0 = update at SB level (default) + * - 1 = update at SB row level in tile + * - 2 = update at tile level + * - 3 = turn off + */ + AV1E_SET_MODE_COST_UPD_FREQ = 141, + + /*!\brief Control to set frequency of the cost updates for motion vectors, + * unsigned int parameter + * + * - 0 = update at SB level (default) + * - 1 = update at SB row level in tile + * - 2 = update at tile level + * - 3 = turn off + */ + AV1E_SET_MV_COST_UPD_FREQ = 142, /*!\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. + * possible operating points conforms to, unsigned int parameter + * + * - 0 = main tier (default) + * - 1 = high tier */ - AV1E_SET_TIER_MASK, + AV1E_SET_TIER_MASK = 143, - /*!\brief Control to set minimum compression ratio. + /*!\brief Control to set minimum compression ratio, unsigned int parameter * Take integer values. If non-zero, encoder will try to keep the compression * ratio of each frame to be higher than the given value divided by 100. * E.g. 850 means minimum compression ratio of 8.5. */ - AV1E_SET_MIN_CR, + AV1E_SET_MIN_CR = 144, - /*!\brief Codec control function to set the layer id. + /* NOTE: enums 145-149 unused */ + + /*!\brief Codec control function to set the layer id, aom_svc_layer_id_t* + * parameter */ AV1E_SET_SVC_LAYER_ID = 150, - /*!\brief Codec control function to set SVC paramaeters. + /*!\brief Codec control function to set SVC paramaeters, aom_svc_params_t* + * parameter */ AV1E_SET_SVC_PARAMS = 151, /*!\brief Codec control function to set reference frame config: * the ref_idx and the refresh flags for each buffer slot. + * aom_svc_ref_frame_config_t* parameter */ - AV1E_SET_SVC_REF_FRAME_CONFIG = 152 + AV1E_SET_SVC_REF_FRAME_CONFIG = 152, + + /*!\brief Codec control function to set the path to the VMAF model used when + * tuning the encoder for VMAF, const char* parameter + */ + AV1E_SET_VMAF_MODEL_PATH = 153, + + /*!\brief Codec control function to enable EXT_TILE_DEBUG in AV1 encoder, + * unsigned int parameter + * + * - 0 = disable (default) + * - 1 = enable + * + * \note This is only used in lightfield example test. + */ + AV1E_ENABLE_EXT_TILE_DEBUG = 154, + + /*!\brief Codec control function to enable the superblock multipass unit test + * in AV1 to ensure that the encoder does not leak state between different + * passes. unsigned int parameter. + * + * - 0 = disable (default) + * - 1 = enable + * + * \note This is only used in sb_multipass unit test. + */ + AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST = 155, + + /*!\brief Control to select minimum height for the GF group pyramid structure, + * unsigned int parameter + * + * Valid values: 0..4 + */ + AV1E_SET_GF_MIN_PYRAMID_HEIGHT = 156, }; /*!\brief aom 1-D scaling mode @@ -1248,10 +1339,12 @@ typedef enum { * */ typedef enum { - AOM_TUNE_PSNR, - AOM_TUNE_SSIM, - AOM_TUNE_CDEF_DIST, - AOM_TUNE_DAALA_DIST + AOM_TUNE_PSNR = 0, + AOM_TUNE_SSIM = 1, + /* NOTE: enums 2 and 3 unused */ + AOM_TUNE_VMAF_WITH_PREPROCESSING = 4, + AOM_TUNE_VMAF_WITHOUT_PREPROCESSING = 5, + AOM_TUNE_VMAF_MAX_GAIN = 6 } aom_tune_metric; #define AOM_MAX_LAYERS 32 /**< Max number of layers */ @@ -1282,6 +1375,7 @@ typedef struct aom_svc_params { typedef struct aom_svc_ref_frame_config { // 7 references: LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), // GOLDEN_FRAME(3), BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). + int reference[7]; /**< Reference flag for each of the 7 references. */ /*! Buffer slot index for each of 7 references. */ int ref_idx[7]; int refresh[8]; /**< Refresh flag for each of the 8 slots. */ @@ -1290,17 +1384,24 @@ typedef struct aom_svc_ref_frame_config { /*!\cond */ /*!\brief Encoder control function parameter type * - * Defines the data types that AOME/AV1E control functions take. Note that - * additional common controls are defined in aom.h + * Defines the data types that AOME/AV1E control functions take. * + * \note Additional common controls are defined in aom.h. + * + * \note For each control ID "X", a macro-define of + * AOM_CTRL_X is provided. It is used at compile time to determine + * if the control ID is supported by the libaom library available, + * when the libaom version cannot be controlled. */ - AOM_CTRL_USE_TYPE(AOME_USE_REFERENCE, int) #define AOM_CTRL_AOME_USE_REFERENCE + AOM_CTRL_USE_TYPE(AOME_SET_ROI_MAP, aom_roi_map_t *) #define AOM_CTRL_AOME_SET_ROI_MAP + AOM_CTRL_USE_TYPE(AOME_SET_ACTIVEMAP, aom_active_map_t *) #define AOM_CTRL_AOME_SET_ACTIVEMAP + AOM_CTRL_USE_TYPE(AOME_SET_SCALEMODE, aom_scaling_mode_t *) #define AOM_CTRL_AOME_SET_SCALEMODE @@ -1309,6 +1410,7 @@ AOM_CTRL_USE_TYPE(AOME_SET_SPATIAL_LAYER_ID, unsigned int) AOM_CTRL_USE_TYPE(AOME_SET_CPUUSED, int) #define AOM_CTRL_AOME_SET_CPUUSED + AOM_CTRL_USE_TYPE(AOME_SET_ENABLEAUTOALTREF, unsigned int) #define AOM_CTRL_AOME_SET_ENABLEAUTOALTREF @@ -1317,15 +1419,19 @@ AOM_CTRL_USE_TYPE(AOME_SET_ENABLEAUTOBWDREF, unsigned int) AOM_CTRL_USE_TYPE(AOME_SET_SHARPNESS, unsigned int) #define AOM_CTRL_AOME_SET_SHARPNESS + AOM_CTRL_USE_TYPE(AOME_SET_STATIC_THRESHOLD, unsigned int) #define AOM_CTRL_AOME_SET_STATIC_THRESHOLD AOM_CTRL_USE_TYPE(AOME_SET_ARNR_MAXFRAMES, unsigned int) #define AOM_CTRL_AOME_SET_ARNR_MAXFRAMES + AOM_CTRL_USE_TYPE(AOME_SET_ARNR_STRENGTH, unsigned int) #define AOM_CTRL_AOME_SET_ARNR_STRENGTH + AOM_CTRL_USE_TYPE(AOME_SET_TUNING, int) /* aom_tune_metric */ #define AOM_CTRL_AOME_SET_TUNING + AOM_CTRL_USE_TYPE(AOME_SET_CQ_LEVEL, unsigned int) #define AOM_CTRL_AOME_SET_CQ_LEVEL @@ -1334,6 +1440,7 @@ AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, unsigned 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, unsigned int) #define AOM_CTRL_AV1E_SET_TILE_ROWS @@ -1345,11 +1452,13 @@ AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_KEYFRAME_FILTERING, unsigned int) AOM_CTRL_USE_TYPE(AOME_GET_LAST_QUANTIZER, int *) #define AOM_CTRL_AOME_GET_LAST_QUANTIZER + AOM_CTRL_USE_TYPE(AOME_GET_LAST_QUANTIZER_64, int *) #define AOM_CTRL_AOME_GET_LAST_QUANTIZER_64 AOM_CTRL_USE_TYPE(AOME_SET_MAX_INTRA_BITRATE_PCT, unsigned int) #define AOM_CTRL_AOME_SET_MAX_INTRA_BITRATE_PCT + AOM_CTRL_USE_TYPE(AOME_SET_MAX_INTER_BITRATE_PCT, unsigned int) #define AOM_CTRL_AOME_SET_MAX_INTER_BITRATE_PCT @@ -1400,6 +1509,7 @@ AOM_CTRL_USE_TYPE(AV1E_SET_QM_V, unsigned int) AOM_CTRL_USE_TYPE(AV1E_SET_NUM_TG, unsigned int) #define AOM_CTRL_AV1E_SET_NUM_TG + AOM_CTRL_USE_TYPE(AV1E_SET_MTU, unsigned int) #define AOM_CTRL_AV1E_SET_MTU @@ -1430,9 +1540,6 @@ AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ORDER_HINT, int) AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TX64, int) #define AOM_CTRL_AV1E_SET_ENABLE_TX64 -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 @@ -1574,6 +1681,12 @@ 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_ENABLE_EXT_TILE_DEBUG, unsigned int) +#define AOM_CTRL_AV1E_ENABLE_EXT_TILE_DEBUG + +AOM_CTRL_USE_TYPE(AV1E_SET_VMAF_MODEL_PATH, const char *) +#define AOM_CTRL_AV1E_SET_VMAF_MODEL_PATH + AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TEST_VECTOR, int) #define AOM_CTRL_AV1E_SET_FILM_GRAIN_TEST_VECTOR @@ -1583,10 +1696,10 @@ AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TABLE, const char *) AOM_CTRL_USE_TYPE(AV1E_SET_CDF_UPDATE_MODE, unsigned int) #define AOM_CTRL_AV1E_SET_CDF_UPDATE_MODE -AOM_CTRL_USE_TYPE(AV1E_SET_DENOISE_NOISE_LEVEL, int); +AOM_CTRL_USE_TYPE(AV1E_SET_DENOISE_NOISE_LEVEL, int) #define AOM_CTRL_AV1E_SET_DENOISE_NOISE_LEVEL -AOM_CTRL_USE_TYPE(AV1E_SET_DENOISE_BLOCK_SIZE, unsigned int); +AOM_CTRL_USE_TYPE(AV1E_SET_DENOISE_BLOCK_SIZE, unsigned int) #define AOM_CTRL_AV1E_SET_DENOISE_BLOCK_SIZE AOM_CTRL_USE_TYPE(AV1E_SET_CHROMA_SUBSAMPLING_X, unsigned int) @@ -1610,6 +1723,9 @@ AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DEFAULT_TX_ONLY, int) 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_MIN_PYRAMID_HEIGHT, unsigned int) +#define AOM_CTRL_AV1E_SET_GF_MIN_PYRAMID_HEIGHT + AOM_CTRL_USE_TYPE(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, unsigned int) #define AOM_CTRL_AV1E_SET_GF_MAX_PYRAMID_HEIGHT @@ -1646,6 +1762,9 @@ AOM_CTRL_USE_TYPE(AV1E_SET_SVC_PARAMS, aom_svc_params_t *) AOM_CTRL_USE_TYPE(AV1E_SET_SVC_REF_FRAME_CONFIG, aom_svc_ref_frame_config_t *) #define AOME_CTRL_AV1E_SET_SVC_REF_FRAME_CONFIG +AOM_CTRL_USE_TYPE(AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST, unsigned int) +#define AOM_CTRL_AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST + /*!\endcond */ /*! @} - end defgroup aom_encoder */ #ifdef __cplusplus diff --git a/media/libaom/src/aom/aomdx.h b/media/libaom/src/aom/aomdx.h index c71eaf90d6..8cd5de3959 100644 --- a/media/libaom/src/aom/aomdx.h +++ b/media/libaom/src/aom/aomdx.h @@ -106,149 +106,195 @@ typedef struct av1_ext_ref_frame { * This set of macros define the control functions available for the AOM * decoder interface. * - * \sa #aom_codec_control + * \sa #aom_codec_control(aom_codec_ctx_t *ctx, int ctrl_id, ...) */ enum aom_dec_control_id { - /** control function to get info on which reference frames were updated - * by the last decode + /*!\brief Codec control function to get info on which reference frames were + * updated by the last decode, int* parameter */ AOMD_GET_LAST_REF_UPDATES = AOM_DECODER_CTRL_ID_START, - /** check if the indicated frame is corrupted */ + /*!\brief Codec control function to check if the indicated frame is + corrupted, int* parameter + */ AOMD_GET_FRAME_CORRUPTED, - /** control function to get info on which reference frames were used - * by the last decode + /*!\brief Codec control function to get info on which reference frames were + * used by the last decode, int* parameter */ AOMD_GET_LAST_REF_USED, - /** control function to get the dimensions that the current frame is decoded - * at. This may be different to the intended display size for the frame as - * specified in the wrapper or frame header (see AV1D_GET_DISPLAY_SIZE). */ + /*!\brief Codec control function to get the dimensions that the current + * frame is decoded at, int* parameter. This may be different to the + * intended display size for the frame as specified in the wrapper or frame + * header (see AV1D_GET_DISPLAY_SIZE). + */ AV1D_GET_FRAME_SIZE, - /** control function to get the current frame's intended display dimensions - * (as specified in the wrapper or frame header). This may be different to - * the decoded dimensions of this frame (see AV1D_GET_FRAME_SIZE). */ + /*!\brief Codec control function to get the current frame's intended display + * dimensions (as specified in the wrapper or frame header), int* parameter. + * This may be different to the decoded dimensions of this frame (see + * AV1D_GET_FRAME_SIZE). + */ AV1D_GET_DISPLAY_SIZE, - /** control function to get the bit depth of the stream. */ + /*!\brief Codec control function to get the bit depth of the stream, + * unsigned int* parameter + */ AV1D_GET_BIT_DEPTH, - /** control function to get the image format of the stream. */ + /*!\brief Codec control function to get the image format of the stream, + * aom_img_fmt_t* parameter + */ AV1D_GET_IMG_FORMAT, - /** control function to get the size of the tile. */ + /*!\brief Codec control function to get the size of the tile, unsigned int + parameter */ AV1D_GET_TILE_SIZE, - /** control function to get the tile count in a tile list. */ + /*!\brief Codec control function to get the tile count in a tile list, int* + * parameter + */ AV1D_GET_TILE_COUNT, - /** control function to set the byte alignment of the planes in the reference - * buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets + /*!\brief Codec control function to set the byte alignment of the planes in + * the reference buffers, int parameter + * + * Valid values are power of 2, from 32 to 1024. A value of 0 sets * legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly * follows Y plane, and V plane directly follows U plane. Default value is 0. */ AV1_SET_BYTE_ALIGNMENT, - /** control function to invert the decoding order to from right to left. The - * function is used in a test to confirm the decoding independence of tile + /*!\brief Codec control function to invert the decoding order to from right to + * left, int parameter + * + * The function is used in a test to confirm the decoding independence of tile * columns. The function may be used in application where this order - * of decoding is desired. + * of decoding is desired. int parameter * * TODO(yaowu): Rework the unit test that uses this control, and in a future * release, this test-only control shall be removed. */ AV1_INVERT_TILE_DECODE_ORDER, - /** control function to set the skip loop filter flag. Valid values are - * integers. The decoder will skip the loop filter when its value is set to - * nonzero. If the loop filter is skipped the decoder may accumulate decode - * artifacts. The default value is 0. + /*!\brief Codec control function to set the skip loop filter flag, int + * parameter + * + * Valid values are integers. The decoder will skip the loop filter + * when its value is set to nonzero. If the loop filter is skipped the + * decoder may accumulate decode artifacts. The default value is 0. */ AV1_SET_SKIP_LOOP_FILTER, - /** control function to retrieve a pointer to the Accounting struct. When - * compiled without --enable-accounting, this returns AOM_CODEC_INCAPABLE. + /*!\brief Codec control function to retrieve a pointer to the Accounting + * struct, takes Accounting** as parameter + * * If called before a frame has been decoded, this returns AOM_CODEC_ERROR. * The caller should ensure that AOM_CODEC_OK is returned before attempting * to dereference the Accounting pointer. + * + * \attention When compiled without --enable-accounting, this returns + * AOM_CODEC_INCAPABLE. */ AV1_GET_ACCOUNTING, - /** control function to get last decoded frame quantizer. Returned value uses - * internal quantizer scale defined by the codec. + /*!\brief Codec control function to get last decoded frame quantizer, + * int* parameter + * + * Returned value uses internal quantizer scale defined by the codec. */ AOMD_GET_LAST_QUANTIZER, - /** control function to set the range of tile decoding. A value that is - * greater and equal to zero indicates only the specific row/column is - * decoded. A value that is -1 indicates the whole row/column is decoded. - * A special case is both values are -1 that means the whole frame is - * decoded. + /*!\brief Codec control function to set the range of tile decoding, int + * parameter + * + * A value that is greater and equal to zero indicates only the specific + * row/column is decoded. A value that is -1 indicates the whole row/column + * is decoded. A special case is both values are -1 that means the whole + * frame is decoded. */ AV1_SET_DECODE_TILE_ROW, AV1_SET_DECODE_TILE_COL, - /** control function to set the tile coding mode. A value that is equal to - * zero indicates the tiles are coded in normal tile mode. A value that is - * 1 indicates the tiles are coded in large-scale tile mode. + + /*!\brief Codec control function to set the tile coding mode, int parameter + * + * - 0 = tiles are coded in normal tile mode + * - 1 = tiles are coded in large-scale tile mode */ AV1_SET_TILE_MODE, - /** control function to get the frame header information of an encoded frame - * in the bitstream. This provides a way to access a frame's header data. + + /*!\brief Codec control function to get the frame header information of an + * encoded frame, unsigned int* parameter */ AV1D_GET_FRAME_HEADER_INFO, - /** control function to get the start address and size of a tile in the coded - * bitstream. This provides a way to access a specific tile's bitstream data. + + /*!\brief Codec control function to get the start address and size of a + * tile in the coded bitstream, aom_tile_data* parameter. */ AV1D_GET_TILE_DATA, - /** control function to set the external references' pointers in the decoder. - * This is used while decoding the tile list OBU in large-scale tile coding - * mode. + + /*!\brief Codec control function to set the external references' pointers in + * the decoder, av1_ext_ref_frame_t* parameter. + * + * This is used while decoding the tile list OBU in large-scale tile coding + * mode. */ AV1D_SET_EXT_REF_PTR, - /** control function to enable the ext-tile software debug and testing code in - * the decoder. + + /*!\brief Codec control function to enable the ext-tile software debug and + * testing code in the decoder, unsigned int parameter */ AV1D_EXT_TILE_DEBUG, - /** control function to enable the row based multi-threading of decoding. A - * value that is equal to 1 indicates that row based multi-threading is - * enabled. + /*!\brief Codec control function to enable the row based multi-threading of + * decoding, unsigned int parameter + * + * - 0 = disabled + * - 1 = enabled (default) */ AV1D_SET_ROW_MT, - /** control function to indicate whether bitstream is in Annex-B format. */ + /*!\brief Codec control function to indicate whether bitstream is in + * Annex-B format, unsigned int parameter + */ AV1D_SET_IS_ANNEXB, - /** control function to indicate which operating point to use. A scalable - * stream may define multiple operating points, each of which defines a - * set of temporal and spatial layers to be processed. The operating point - * index may take a value between 0 and operating_points_cnt_minus_1 (which - * is at most 31). + /*!\brief Codec control function to indicate which operating point to use, + * int parameter + * + * A scalable stream may define multiple operating points, each of which + * defines a set of temporal and spatial layers to be processed. The + * operating point index may take a value between 0 and + * operating_points_cnt_minus_1 (which is at most 31). */ AV1D_SET_OPERATING_POINT, - /** control function to indicate whether to output one frame per temporal - * unit (the default), or one frame per spatial layer. - * In a scalable stream, each temporal unit corresponds to a single "frame" - * of video, and within a temporal unit there may be multiple spatial layers - * with different versions of that frame. - * For video playback, only the highest-quality version (within the - * selected operating point) is needed, but for some use cases it is useful - * to have access to multiple versions of a frame when they are available. + /*!\brief Codec control function to indicate whether to output one frame per + * temporal unit (the default), or one frame per spatial layer. int parameter + * + * In a scalable stream, each temporal unit corresponds to a single "frame" + * of video, and within a temporal unit there may be multiple spatial layers + * with different versions of that frame. + * For video playback, only the highest-quality version (within the + * selected operating point) is needed, but for some use cases it is useful + * to have access to multiple versions of a frame when they are available. */ AV1D_SET_OUTPUT_ALL_LAYERS, - /** control function to set an aom_inspect_cb callback that is invoked each - * time a frame is decoded. When compiled without --enable-inspection, this + /*!\brief Codec control function to set an aom_inspect_cb callback that is + * invoked each time a frame is decoded, aom_inspect_init* parameter + * + * \attention When compiled without --enable-inspection, this * returns AOM_CODEC_INCAPABLE. */ AV1_SET_INSPECTION_CALLBACK, - /** control function to set the skip film grain flag. Valid values are - * integers. The decoder will skip the film grain when its value is set to - * nonzero. The default value is 0. + /*!\brief Codec control function to set the skip film grain flag, int + * parameter + * + * Valid values are integers. The decoder will skip the film grain when its + * value is set to nonzero. The default value is 0. */ AV1D_SET_SKIP_FILM_GRAIN, @@ -258,59 +304,87 @@ enum aom_dec_control_id { /*!\cond */ /*!\brief AOM decoder control function parameter type * - * Defines the data types that AOMD control functions take. Note that - * additional common controls are defined in aom.h + * Defines the data types that AOMD control functions take. * + * \note Additional common controls are defined in aom.h. + * + * \note For each control ID "X", a macro-define of + * AOM_CTRL_X is provided. It is used at compile time to determine + * if the control ID is supported by the libaom library available, + * when the libaom version cannot be controlled. */ - AOM_CTRL_USE_TYPE(AOMD_GET_LAST_REF_UPDATES, int *) #define AOM_CTRL_AOMD_GET_LAST_REF_UPDATES + AOM_CTRL_USE_TYPE(AOMD_GET_FRAME_CORRUPTED, int *) #define AOM_CTRL_AOMD_GET_FRAME_CORRUPTED + AOM_CTRL_USE_TYPE(AOMD_GET_LAST_REF_USED, int *) #define AOM_CTRL_AOMD_GET_LAST_REF_USED + AOM_CTRL_USE_TYPE(AOMD_GET_LAST_QUANTIZER, int *) #define AOM_CTRL_AOMD_GET_LAST_QUANTIZER + AOM_CTRL_USE_TYPE(AV1D_GET_DISPLAY_SIZE, int *) #define AOM_CTRL_AV1D_GET_DISPLAY_SIZE + AOM_CTRL_USE_TYPE(AV1D_GET_BIT_DEPTH, unsigned int *) #define AOM_CTRL_AV1D_GET_BIT_DEPTH + AOM_CTRL_USE_TYPE(AV1D_GET_IMG_FORMAT, aom_img_fmt_t *) #define AOM_CTRL_AV1D_GET_IMG_FORMAT + AOM_CTRL_USE_TYPE(AV1D_GET_TILE_SIZE, unsigned int *) #define AOM_CTRL_AV1D_GET_TILE_SIZE + AOM_CTRL_USE_TYPE(AV1D_GET_TILE_COUNT, unsigned int *) #define AOM_CTRL_AV1D_GET_TILE_COUNT + AOM_CTRL_USE_TYPE(AV1D_GET_FRAME_SIZE, int *) #define AOM_CTRL_AV1D_GET_FRAME_SIZE + AOM_CTRL_USE_TYPE(AV1_INVERT_TILE_DECODE_ORDER, int) #define AOM_CTRL_AV1_INVERT_TILE_DECODE_ORDER + AOM_CTRL_USE_TYPE(AV1_GET_ACCOUNTING, Accounting **) #define AOM_CTRL_AV1_GET_ACCOUNTING + AOM_CTRL_USE_TYPE(AV1_SET_DECODE_TILE_ROW, int) #define AOM_CTRL_AV1_SET_DECODE_TILE_ROW + AOM_CTRL_USE_TYPE(AV1_SET_DECODE_TILE_COL, int) #define AOM_CTRL_AV1_SET_DECODE_TILE_COL + AOM_CTRL_USE_TYPE(AV1_SET_TILE_MODE, unsigned int) #define AOM_CTRL_AV1_SET_TILE_MODE + AOM_CTRL_USE_TYPE(AV1D_GET_FRAME_HEADER_INFO, aom_tile_data *) #define AOM_CTRL_AV1D_GET_FRAME_HEADER_INFO + AOM_CTRL_USE_TYPE(AV1D_GET_TILE_DATA, aom_tile_data *) #define AOM_CTRL_AV1D_GET_TILE_DATA + AOM_CTRL_USE_TYPE(AV1D_SET_EXT_REF_PTR, av1_ext_ref_frame_t *) #define AOM_CTRL_AV1D_SET_EXT_REF_PTR + AOM_CTRL_USE_TYPE(AV1D_EXT_TILE_DEBUG, unsigned int) #define AOM_CTRL_AV1D_EXT_TILE_DEBUG + AOM_CTRL_USE_TYPE(AV1D_SET_ROW_MT, unsigned int) #define AOM_CTRL_AV1D_SET_ROW_MT + AOM_CTRL_USE_TYPE(AV1D_SET_SKIP_FILM_GRAIN, int) #define AOM_CTRL_AV1D_SET_SKIP_FILM_GRAIN + AOM_CTRL_USE_TYPE(AV1D_SET_IS_ANNEXB, unsigned int) #define AOM_CTRL_AV1D_SET_IS_ANNEXB + AOM_CTRL_USE_TYPE(AV1D_SET_OPERATING_POINT, int) #define AOM_CTRL_AV1D_SET_OPERATING_POINT + AOM_CTRL_USE_TYPE(AV1D_SET_OUTPUT_ALL_LAYERS, int) #define AOM_CTRL_AV1D_SET_OUTPUT_ALL_LAYERS + AOM_CTRL_USE_TYPE(AV1_SET_INSPECTION_CALLBACK, aom_inspect_init *) #define AOM_CTRL_AV1_SET_INSPECTION_CALLBACK /*!\endcond */ diff --git a/media/libaom/src/aom/exports_com b/media/libaom/src/aom/exports_com index a192cf9305..6f796f5db0 100644 --- a/media/libaom/src/aom/exports_com +++ b/media/libaom/src/aom/exports_com @@ -1,5 +1,5 @@ text aom_codec_build_config -text aom_codec_control_ +text aom_codec_control text aom_codec_destroy text aom_codec_err_to_string text aom_codec_error @@ -15,10 +15,12 @@ text aom_img_alloc text aom_img_alloc_with_border text aom_img_flip text aom_img_free +text aom_img_get_metadata text aom_img_metadata_array_free text aom_img_metadata_array_alloc text aom_img_metadata_free text aom_img_metadata_alloc +text aom_img_num_metadata text aom_img_plane_height text aom_img_plane_width text aom_img_remove_metadata diff --git a/media/libaom/src/aom/exports_dec b/media/libaom/src/aom/exports_dec index d7d1c4f7da..ffff023ddd 100644 --- a/media/libaom/src/aom/exports_dec +++ b/media/libaom/src/aom/exports_dec @@ -3,8 +3,6 @@ text aom_codec_decode text aom_codec_get_frame text aom_codec_get_stream_info text aom_codec_peek_stream_info -text aom_codec_register_put_frame_cb -text aom_codec_register_put_slice_cb text aom_codec_set_frame_buffer_functions text aom_obu_type_to_string text aom_read_obu_header diff --git a/media/libaom/src/aom/exports_enc b/media/libaom/src/aom/exports_enc index 918d742f05..1473d9d2b5 100644 --- a/media/libaom/src/aom/exports_enc +++ b/media/libaom/src/aom/exports_enc @@ -1,6 +1,5 @@ text aom_codec_enc_config_default text aom_codec_enc_config_set -text aom_codec_enc_init_multi_ver text aom_codec_enc_init_ver text aom_codec_encode text aom_codec_get_cx_data diff --git a/media/libaom/src/aom/internal/aom_codec_internal.h b/media/libaom/src/aom/internal/aom_codec_internal.h index 21c0dc69c7..efe09acc91 100644 --- a/media/libaom/src/aom/internal/aom_codec_internal.h +++ b/media/libaom/src/aom/internal/aom_codec_internal.h @@ -59,10 +59,9 @@ extern "C" { * types, removing or reassigning enums, adding/removing/rearranging * fields to structures */ -#define AOM_CODEC_INTERNAL_ABI_VERSION (5) /**<\hideinitializer*/ +#define AOM_CODEC_INTERNAL_ABI_VERSION (7) /**<\hideinitializer*/ typedef struct aom_codec_alg_priv aom_codec_alg_priv_t; -typedef struct aom_codec_priv_enc_mr_cfg aom_codec_priv_enc_mr_cfg_t; /*!\brief init function pointer prototype * @@ -77,8 +76,7 @@ typedef struct aom_codec_priv_enc_mr_cfg aom_codec_priv_enc_mr_cfg_t; * \retval #AOM_CODEC_MEM_ERROR * Memory operation failed. */ -typedef aom_codec_err_t (*aom_codec_init_fn_t)( - aom_codec_ctx_t *ctx, aom_codec_priv_enc_mr_cfg_t *data); +typedef aom_codec_err_t (*aom_codec_init_fn_t)(aom_codec_ctx_t *ctx); /*!\brief destroy function pointer prototype * @@ -138,7 +136,7 @@ typedef aom_codec_err_t (*aom_codec_get_si_fn_t)(aom_codec_alg_priv_t *ctx, * function, so plugins implementing this interface may trust the input * parameters to be properly initialized. However, this interface does not * provide type safety for the exchanged data or assign meanings to the - * control codes. Those details should be specified in the algorithm's + * control IDs. Those details should be specified in the algorithm's * header file. In particular, the ctrl_id parameter is guaranteed to exist * in the algorithm's control mapping table, and the data parameter may be NULL. * @@ -171,17 +169,12 @@ typedef const struct aom_codec_ctrl_fn_map { /*!\brief decode data function pointer prototype * - * Processes a buffer of coded data. If the processing results in a new - * decoded frame becoming available, #AOM_CODEC_CB_PUT_SLICE and - * #AOM_CODEC_CB_PUT_FRAME events are generated as appropriate. This - * function is called by the generic aom_codec_decode() wrapper function, - * so plugins implementing this interface may trust the input parameters - * to be properly initialized. + * Processes a buffer of coded data. This function is called by the generic + * aom_codec_decode() wrapper function, so plugins implementing this interface + * may trust the input parameters to be properly initialized. * * \param[in] ctx Pointer to this instance's context - * \param[in] data Pointer to this block of new coded data. If - * NULL, a #AOM_CODEC_CB_PUT_FRAME event is posted - * for the previously decoded frame. + * \param[in] data Pointer to this block of new coded data. * \param[in] data_sz Size of the coded data, in bytes. * * \return Returns #AOM_CODEC_OK if the coded data was processed completely @@ -259,24 +252,6 @@ typedef aom_fixed_buf_t *(*aom_codec_get_global_headers_fn_t)( typedef aom_image_t *(*aom_codec_get_preview_frame_fn_t)( aom_codec_alg_priv_t *ctx); -typedef aom_codec_err_t (*aom_codec_enc_mr_get_mem_loc_fn_t)( - const aom_codec_enc_cfg_t *cfg, void **mem_loc); - -/*!\brief usage configuration mapping - * - * This structure stores the mapping between usage identifiers and - * configuration structures. Each algorithm provides a list of these - * mappings. This list is searched by the aom_codec_enc_config_default() - * wrapper function to determine which config to return. The special value - * {-1, {0}} is used to indicate end-of-list, and must be present. At least - * one mapping must be present, in addition to the end-of-list. - * - */ -typedef const struct aom_codec_enc_cfg_map { - int usage; - aom_codec_enc_cfg_t cfg; -} aom_codec_enc_cfg_map_t; - /*!\brief Decoder algorithm interface interface * * All decoders \ref MUST expose a variable of this type. @@ -297,10 +272,9 @@ struct aom_codec_iface { aom_codec_set_fb_fn_t set_fb_fn; /**< \copydoc ::aom_codec_set_fb_fn_t */ } dec; struct aom_codec_enc_iface { - int cfg_map_count; - aom_codec_enc_cfg_map_t - *cfg_maps; /**< \copydoc ::aom_codec_enc_cfg_map_t */ - aom_codec_encode_fn_t encode; /**< \copydoc ::aom_codec_encode_fn_t */ + int cfg_count; + const aom_codec_enc_cfg_t *cfgs; /**< \copydoc ::aom_codec_enc_cfg_t */ + aom_codec_encode_fn_t encode; /**< \copydoc ::aom_codec_encode_fn_t */ aom_codec_get_cx_data_fn_t get_cx_data; /**< \copydoc ::aom_codec_get_cx_data_fn_t */ aom_codec_enc_config_set_fn_t @@ -309,20 +283,9 @@ struct aom_codec_iface { get_glob_hdrs; /**< \copydoc ::aom_codec_get_global_headers_fn_t */ aom_codec_get_preview_frame_fn_t get_preview; /**< \copydoc ::aom_codec_get_preview_frame_fn_t */ - aom_codec_enc_mr_get_mem_loc_fn_t - mr_get_mem_loc; /**< \copydoc ::aom_codec_enc_mr_get_mem_loc_fn_t */ } enc; }; -/*!\brief Callback function pointer / user data pair storage */ -typedef struct aom_codec_priv_cb_pair { - union { - aom_codec_put_frame_cb_fn_t put_frame; - aom_codec_put_slice_cb_fn_t put_slice; - } u; - void *user_priv; -} aom_codec_priv_cb_pair_t; - /*!\brief Instance private storage * * This structure is allocated by the algorithm's init function. It can be @@ -334,38 +297,15 @@ typedef struct aom_codec_priv_cb_pair { struct aom_codec_priv { const char *err_detail; aom_codec_flags_t init_flags; - struct { - aom_codec_priv_cb_pair_t put_frame_cb; - aom_codec_priv_cb_pair_t put_slice_cb; - } dec; struct { aom_fixed_buf_t cx_data_dst_buf; unsigned int cx_data_pad_before; unsigned int cx_data_pad_after; aom_codec_cx_pkt_t cx_data_pkt; - unsigned int total_encoders; } enc; }; -/* - * Multi-resolution encoding internal configuration - */ -struct aom_codec_priv_enc_mr_cfg { - unsigned int mr_total_resolutions; - unsigned int mr_encoder_id; - struct aom_rational mr_down_sampling_factor; - void *mr_low_res_mode_info; -}; - -#undef AOM_CTRL_USE_TYPE -#define AOM_CTRL_USE_TYPE(id, typ) \ - static AOM_INLINE typ id##__value(va_list args) { return va_arg(args, typ); } - -#undef AOM_CTRL_USE_TYPE_DEPRECATED -#define AOM_CTRL_USE_TYPE_DEPRECATED(id, typ) \ - static AOM_INLINE typ id##__value(va_list args) { return va_arg(args, typ); } - -#define CAST(id, arg) id##__value(arg) +#define CAST(id, arg) va_arg((arg), aom_codec_control_type_##id) /* CODEC_INTERFACE convenience macro * diff --git a/media/libaom/src/aom/internal/aom_image_internal.h b/media/libaom/src/aom/internal/aom_image_internal.h index 2629d65d8f..7f2fd1891d 100644 --- a/media/libaom/src/aom/internal/aom_image_internal.h +++ b/media/libaom/src/aom/internal/aom_image_internal.h @@ -43,11 +43,10 @@ aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz); /*!\brief Free metadata array struct. * * Free metadata array struct and all metadata structs inside. - * Returns the number of deleted metadata structs. * * \param[in] arr Metadata array struct pointer */ -size_t aom_img_metadata_array_free(aom_metadata_array_t *arr); +void aom_img_metadata_array_free(aom_metadata_array_t *arr); typedef void *(*aom_alloc_img_data_cb_fn_t)(void *priv, size_t size); diff --git a/media/libaom/src/aom/src/aom_codec.c b/media/libaom/src/aom/src/aom_codec.c index 733bffb25d..196ab8354d 100644 --- a/media/libaom/src/aom/src/aom_codec.c +++ b/media/libaom/src/aom/src/aom_codec.c @@ -89,7 +89,7 @@ aom_codec_caps_t aom_codec_get_caps(aom_codec_iface_t *iface) { return (iface) ? iface->caps : 0; } -aom_codec_err_t aom_codec_control_(aom_codec_ctx_t *ctx, int ctrl_id, ...) { +aom_codec_err_t aom_codec_control(aom_codec_ctx_t *ctx, int ctrl_id, ...) { aom_codec_err_t res; if (!ctx || !ctrl_id) diff --git a/media/libaom/src/aom/src/aom_decoder.c b/media/libaom/src/aom/src/aom_decoder.c index 282ec8a756..49fff26352 100644 --- a/media/libaom/src/aom/src/aom_decoder.c +++ b/media/libaom/src/aom/src/aom_decoder.c @@ -34,9 +34,6 @@ aom_codec_err_t aom_codec_dec_init_ver(aom_codec_ctx_t *ctx, res = AOM_CODEC_INVALID_PARAM; else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION) res = AOM_CODEC_ABI_MISMATCH; - else if ((flags & AOM_CODEC_USE_POSTPROC) && - !(iface->caps & AOM_CODEC_CAP_POSTPROC)) - res = AOM_CODEC_INCAPABLE; else if (!(iface->caps & AOM_CODEC_CAP_DECODER)) res = AOM_CODEC_INCAPABLE; else { @@ -47,7 +44,7 @@ aom_codec_err_t aom_codec_dec_init_ver(aom_codec_ctx_t *ctx, ctx->init_flags = flags; ctx->config.dec = cfg; - res = ctx->iface->init(ctx, NULL); + res = ctx->iface->init(ctx); if (res) { ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; aom_codec_destroy(ctx); @@ -120,44 +117,6 @@ aom_image_t *aom_codec_get_frame(aom_codec_ctx_t *ctx, aom_codec_iter_t *iter) { return img; } -aom_codec_err_t aom_codec_register_put_frame_cb(aom_codec_ctx_t *ctx, - aom_codec_put_frame_cb_fn_t cb, - void *user_priv) { - aom_codec_err_t res; - - if (!ctx || !cb) - res = AOM_CODEC_INVALID_PARAM; - else if (!ctx->iface || !ctx->priv || - !(ctx->iface->caps & AOM_CODEC_CAP_PUT_FRAME)) - res = AOM_CODEC_ERROR; - else { - ctx->priv->dec.put_frame_cb.u.put_frame = cb; - ctx->priv->dec.put_frame_cb.user_priv = user_priv; - res = AOM_CODEC_OK; - } - - return SAVE_STATUS(ctx, res); -} - -aom_codec_err_t aom_codec_register_put_slice_cb(aom_codec_ctx_t *ctx, - aom_codec_put_slice_cb_fn_t cb, - void *user_priv) { - aom_codec_err_t res; - - if (!ctx || !cb) - res = AOM_CODEC_INVALID_PARAM; - else if (!ctx->iface || !ctx->priv || - !(ctx->iface->caps & AOM_CODEC_CAP_PUT_SLICE)) - res = AOM_CODEC_ERROR; - else { - ctx->priv->dec.put_slice_cb.u.put_slice = cb; - ctx->priv->dec.put_slice_cb.user_priv = user_priv; - res = AOM_CODEC_OK; - } - - return SAVE_STATUS(ctx, res); -} - aom_codec_err_t aom_codec_set_frame_buffer_functions( aom_codec_ctx_t *ctx, aom_get_frame_buffer_cb_fn_t cb_get, aom_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) { @@ -165,9 +124,10 @@ aom_codec_err_t aom_codec_set_frame_buffer_functions( if (!ctx || !cb_get || !cb_release) { res = AOM_CODEC_INVALID_PARAM; - } else if (!ctx->iface || !ctx->priv || - !(ctx->iface->caps & AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER)) { + } else if (!ctx->iface || !ctx->priv) { res = AOM_CODEC_ERROR; + } else if (!(ctx->iface->caps & AOM_CODEC_CAP_EXTERNAL_FRAME_BUFFER)) { + res = AOM_CODEC_INCAPABLE; } else { res = ctx->iface->dec.set_fb_fn(get_alg_priv(ctx), cb_get, cb_release, cb_priv); diff --git a/media/libaom/src/aom/src/aom_encoder.c b/media/libaom/src/aom/src/aom_encoder.c index fbe68236a9..bb51c9388f 100644 --- a/media/libaom/src/aom/src/aom_encoder.c +++ b/media/libaom/src/aom/src/aom_encoder.c @@ -24,6 +24,8 @@ #include #include + +#include "aom/aom_encoder.h" #include "aom/internal/aom_codec_internal.h" #define SAVE_STATUS(ctx, var) (ctx ? (ctx->err = var) : var) @@ -54,7 +56,7 @@ aom_codec_err_t aom_codec_enc_init_ver(aom_codec_ctx_t *ctx, ctx->priv = NULL; ctx->init_flags = flags; ctx->config.enc = cfg; - res = ctx->iface->init(ctx, NULL); + res = ctx->iface->init(ctx); if (res) { ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; @@ -65,108 +67,35 @@ aom_codec_err_t aom_codec_enc_init_ver(aom_codec_ctx_t *ctx, return SAVE_STATUS(ctx, res); } -aom_codec_err_t aom_codec_enc_init_multi_ver( - aom_codec_ctx_t *ctx, aom_codec_iface_t *iface, aom_codec_enc_cfg_t *cfg, - int num_enc, aom_codec_flags_t flags, aom_rational_t *dsf, int ver) { - aom_codec_err_t res = AOM_CODEC_OK; - - if (ver != AOM_ENCODER_ABI_VERSION) - res = AOM_CODEC_ABI_MISMATCH; - else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1)) - res = AOM_CODEC_INVALID_PARAM; - else if (iface->abi_version != AOM_CODEC_INTERNAL_ABI_VERSION) - res = AOM_CODEC_ABI_MISMATCH; - else if (!(iface->caps & AOM_CODEC_CAP_ENCODER)) - res = AOM_CODEC_INCAPABLE; - else if ((flags & AOM_CODEC_USE_PSNR) && !(iface->caps & AOM_CODEC_CAP_PSNR)) - res = AOM_CODEC_INCAPABLE; - else { - int i; - void *mem_loc = NULL; - - if (!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) { - for (i = 0; i < num_enc; i++) { - aom_codec_priv_enc_mr_cfg_t mr_cfg; - - /* Validate down-sampling factor. */ - if (dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 || - dsf->den > dsf->num) { - res = AOM_CODEC_INVALID_PARAM; - break; - } - - mr_cfg.mr_low_res_mode_info = mem_loc; - mr_cfg.mr_total_resolutions = num_enc; - mr_cfg.mr_encoder_id = num_enc - 1 - i; - mr_cfg.mr_down_sampling_factor.num = dsf->num; - mr_cfg.mr_down_sampling_factor.den = dsf->den; - - /* Force Key-frame synchronization. Namely, encoder at higher - * resolution always use the same frame_type chosen by the - * lowest-resolution encoder. - */ - if (mr_cfg.mr_encoder_id) cfg->kf_mode = AOM_KF_DISABLED; - - ctx->iface = iface; - ctx->name = iface->name; - ctx->priv = NULL; - ctx->init_flags = flags; - ctx->config.enc = cfg; - res = ctx->iface->init(ctx, &mr_cfg); - - if (res) { - const char *error_detail = ctx->priv ? ctx->priv->err_detail : NULL; - /* Destroy current ctx */ - ctx->err_detail = error_detail; - aom_codec_destroy(ctx); - - /* Destroy already allocated high-level ctx */ - while (i) { - ctx--; - ctx->err_detail = error_detail; - aom_codec_destroy(ctx); - i--; - } - } - - if (res) break; - - ctx++; - cfg++; - dsf++; - } - ctx--; - } - } - - return SAVE_STATUS(ctx, res); -} - aom_codec_err_t aom_codec_enc_config_default(aom_codec_iface_t *iface, aom_codec_enc_cfg_t *cfg, - unsigned int reserved) { + unsigned int usage) { aom_codec_err_t res; - aom_codec_enc_cfg_map_t *map; int i; - if (!iface || !cfg || reserved > INT_MAX) + if (!iface || !cfg) res = AOM_CODEC_INVALID_PARAM; else if (!(iface->caps & AOM_CODEC_CAP_ENCODER)) res = AOM_CODEC_INCAPABLE; else { res = AOM_CODEC_INVALID_PARAM; - for (i = 0; i < iface->enc.cfg_map_count; ++i) { - map = iface->enc.cfg_maps + i; - if (map->usage == (int)reserved) { - *cfg = map->cfg; - cfg->g_usage = reserved; + for (i = 0; i < iface->enc.cfg_count; ++i) { + if (iface->enc.cfgs[i].g_usage == usage) { + *cfg = iface->enc.cfgs[i]; res = AOM_CODEC_OK; break; } } } - + /* default values */ + if (cfg) { + memset(&cfg->encoder_cfg, 0, sizeof(cfg->encoder_cfg)); + cfg->encoder_cfg.super_block_size = 0; // Dynamic + cfg->encoder_cfg.max_partition_size = 128; + cfg->encoder_cfg.min_partition_size = 4; + cfg->encoder_cfg.disable_trellis_quant = 3; + } return res; } @@ -219,38 +148,11 @@ aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img, else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER)) res = AOM_CODEC_INCAPABLE; else { - unsigned int num_enc = ctx->priv->enc.total_encoders; - /* Execute in a normalized floating point environment, if the platform * requires it. */ FLOATING_POINT_INIT - - if (num_enc == 1) - res = - ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags); - else { - /* Multi-resolution encoding: - * Encode multi-levels in reverse order. For example, - * if mr_total_resolutions = 3, first encode level 2, - * then encode level 1, and finally encode level 0. - */ - int i; - - ctx += num_enc - 1; - if (img) img += num_enc - 1; - - for (i = num_enc - 1; i >= 0; i--) { - if ((res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, - flags))) - break; - - ctx--; - if (img) img--; - } - ctx++; - } - + res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags); FLOATING_POINT_RESTORE } diff --git a/media/libaom/src/aom/src/aom_image.c b/media/libaom/src/aom/src/aom_image.c index 9f7ed9906f..cd0b5ed835 100644 --- a/media/libaom/src/aom/src/aom_image.c +++ b/media/libaom/src/aom/src/aom_image.c @@ -288,30 +288,29 @@ int aom_img_plane_height(const aom_image_t *img, int plane) { return img->d_h; } -aom_metadata_t *aom_img_metadata_alloc(uint8_t type, uint8_t *data, size_t sz) { - aom_metadata_t *metadata = - (aom_metadata_t *)calloc(1, sizeof(aom_metadata_t)); +aom_metadata_t *aom_img_metadata_alloc( + uint32_t type, const uint8_t *data, size_t sz, + aom_metadata_insert_flags_t insert_flag) { + if (!data || sz == 0) return NULL; + aom_metadata_t *metadata = (aom_metadata_t *)malloc(sizeof(aom_metadata_t)); if (!metadata) return NULL; metadata->type = type; - if (sz > 0) { - metadata->payload = (uint8_t *)calloc(sz, sizeof(uint8_t)); - if (!metadata->payload) { - free(metadata); - return NULL; - } - if (data) { - memcpy(metadata->payload, data, sz); - metadata->sz = sz; - } + metadata->payload = (uint8_t *)malloc(sz); + if (!metadata->payload) { + free(metadata); + return NULL; } + memcpy(metadata->payload, data, sz); + metadata->sz = sz; + metadata->insert_flag = insert_flag; return metadata; } -int aom_img_metadata_free(aom_metadata_t *metadata) { - if (!metadata) return -1; - if (metadata->payload) free(metadata->payload); - free(metadata); - return 0; +void aom_img_metadata_free(aom_metadata_t *metadata) { + if (metadata) { + if (metadata->payload) free(metadata->payload); + free(metadata); + } } aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz) { @@ -330,29 +329,27 @@ aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz) { return arr; } -size_t aom_img_metadata_array_free(aom_metadata_array_t *arr) { - size_t deleted_metadatas = 0; - if (!arr) return deleted_metadatas; - if (arr->metadata_array) { - for (size_t i = 0; i < arr->sz; i++) { - if (aom_img_metadata_free(arr->metadata_array[i]) == 0) { - deleted_metadatas++; +void aom_img_metadata_array_free(aom_metadata_array_t *arr) { + if (arr) { + if (arr->metadata_array) { + for (size_t i = 0; i < arr->sz; i++) { + aom_img_metadata_free(arr->metadata_array[i]); } + free(arr->metadata_array); } - free(arr->metadata_array); + free(arr); } - free(arr); - return deleted_metadatas; } -int aom_img_add_metadata(aom_image_t *img, uint8_t type, uint8_t *data, - size_t sz) { +int aom_img_add_metadata(aom_image_t *img, uint32_t type, const uint8_t *data, + size_t sz, aom_metadata_insert_flags_t insert_flag) { if (!img) return -1; if (!img->metadata) { img->metadata = aom_img_metadata_array_alloc(0); if (!img->metadata) return -1; } - aom_metadata_t *metadata = aom_img_metadata_alloc(type, data, sz); + aom_metadata_t *metadata = + aom_img_metadata_alloc(type, data, sz, insert_flag); if (!metadata) goto fail; if (!img->metadata->metadata_array) { img->metadata->metadata_array = @@ -375,11 +372,24 @@ fail: return -1; } -size_t aom_img_remove_metadata(aom_image_t *img) { +void aom_img_remove_metadata(aom_image_t *img) { if (img && img->metadata) { - size_t sz = aom_img_metadata_array_free(img->metadata); + aom_img_metadata_array_free(img->metadata); img->metadata = NULL; - return sz; } - return 0; +} + +const aom_metadata_t *aom_img_get_metadata(const aom_image_t *img, + size_t index) { + if (!img) return NULL; + const aom_metadata_array_t *array = img->metadata; + if (array && index < array->sz) { + return array->metadata_array[index]; + } + return NULL; +} + +size_t aom_img_num_metadata(const aom_image_t *img) { + if (!img || !img->metadata) return 0; + return img->metadata->sz; } diff --git a/media/libaom/src/aom_dsp/add_noise.c b/media/libaom/src/aom_dsp/add_noise.c deleted file mode 100644 index 43587ca315..0000000000 --- a/media/libaom/src/aom_dsp/add_noise.c +++ /dev/null @@ -1,73 +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 -#include - -#include "config/aom_config.h" -#include "config/aom_dsp_rtcd.h" - -#include "aom/aom_integer.h" -#include "aom_ports/mem.h" - -void aom_plane_add_noise_c(uint8_t *start, char *noise, char blackclamp[16], - char whiteclamp[16], char bothclamp[16], - unsigned int width, unsigned int height, int pitch) { - unsigned int i, j; - - for (i = 0; i < height; ++i) { - uint8_t *pos = start + i * pitch; - char *ref = (char *)(noise + (rand() & 0xff)); // NOLINT - - for (j = 0; j < width; ++j) { - int v = pos[j]; - - v = clamp(v - blackclamp[0], 0, 255); - v = clamp(v + bothclamp[0], 0, 255); - v = clamp(v - whiteclamp[0], 0, 255); - - pos[j] = v + ref[j]; - } - } -} - -static double gaussian(double sigma, double mu, double x) { - return 1 / (sigma * sqrt(2.0 * PI)) * - (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma))); -} - -int aom_setup_noise(double sigma, int size, char *noise) { - char char_dist[256]; - int next = 0, i, j; - - // set up a 256 entry lookup that matches gaussian distribution - for (i = -32; i < 32; ++i) { - const int a_i = (int)(0.5 + 256 * gaussian(sigma, 0, i)); - if (a_i) { - for (j = 0; j < a_i; ++j) { - char_dist[next + j] = (char)i; - } - next = next + j; - } - } - - // Rounding error - might mean we have less than 256. - for (; next < 256; ++next) { - char_dist[next] = 0; - } - - for (i = 0; i < size; ++i) { - noise[i] = char_dist[rand() & 0xff]; // NOLINT - } - - // Returns the highest non 0 value used in distribution. - return -char_dist[0]; -} diff --git a/media/libaom/src/aom_dsp/aom_convolve.c b/media/libaom/src/aom_dsp/aom_convolve.c index e7cc659bc8..7879b88f64 100644 --- a/media/libaom/src/aom_dsp/aom_convolve.c +++ b/media/libaom/src/aom_dsp/aom_convolve.c @@ -74,7 +74,6 @@ static void convolve_vert(const uint8_t *src, ptrdiff_t src_stride, static const InterpKernel *get_filter_base(const int16_t *filter) { // NOTE: This assumes that the filter table is 256-byte aligned. - // TODO(agrange) Modify to make independent of table alignment. return (const InterpKernel *)(((intptr_t)filter) & ~((intptr_t)0xFF)); } diff --git a/media/libaom/src/aom_dsp/aom_dsp.cmake b/media/libaom/src/aom_dsp/aom_dsp.cmake index 7f4a6f6e4d..f1b61f010b 100644 --- a/media/libaom/src/aom_dsp/aom_dsp.cmake +++ b/media/libaom/src/aom_dsp/aom_dsp.cmake @@ -67,6 +67,7 @@ list(APPEND AOM_DSP_COMMON_INTRIN_SSE2 "${AOM_ROOT}/aom_dsp/x86/highbd_intrapred_sse2.c" "${AOM_ROOT}/aom_dsp/x86/highbd_loopfilter_sse2.c" "${AOM_ROOT}/aom_dsp/x86/intrapred_sse2.c" + "${AOM_ROOT}/aom_dsp/x86/intrapred_x86.h" "${AOM_ROOT}/aom_dsp/x86/loopfilter_sse2.c" "${AOM_ROOT}/aom_dsp/x86/lpf_common_sse2.h" "${AOM_ROOT}/aom_dsp/x86/mem_sse2.h" @@ -154,10 +155,9 @@ if(CONFIG_AV1_DECODER) list(APPEND AOM_DSP_DECODER_SOURCES "${AOM_ROOT}/aom_dsp/binary_codes_reader.c" "${AOM_ROOT}/aom_dsp/binary_codes_reader.h" - "${AOM_ROOT}/aom_dsp/bitreader.h" - "${AOM_ROOT}/aom_dsp/daalaboolreader.c" - "${AOM_ROOT}/aom_dsp/daalaboolreader.h" - "${AOM_ROOT}/aom_dsp/entdec.c" "${AOM_ROOT}/aom_dsp/entdec.h" + "${AOM_ROOT}/aom_dsp/bitreader.c" + "${AOM_ROOT}/aom_dsp/bitreader.h" "${AOM_ROOT}/aom_dsp/entdec.c" + "${AOM_ROOT}/aom_dsp/entdec.h" "${AOM_ROOT}/aom_dsp/grain_synthesis.c" "${AOM_ROOT}/aom_dsp/grain_synthesis.h") endif() @@ -166,10 +166,9 @@ if(CONFIG_AV1_ENCODER) list(APPEND AOM_DSP_ENCODER_SOURCES "${AOM_ROOT}/aom_dsp/binary_codes_writer.c" "${AOM_ROOT}/aom_dsp/binary_codes_writer.h" + "${AOM_ROOT}/aom_dsp/bitwriter.c" "${AOM_ROOT}/aom_dsp/bitwriter.h" "${AOM_ROOT}/aom_dsp/blk_sse_sum.c" - "${AOM_ROOT}/aom_dsp/daalaboolwriter.c" - "${AOM_ROOT}/aom_dsp/daalaboolwriter.h" "${AOM_ROOT}/aom_dsp/entenc.c" "${AOM_ROOT}/aom_dsp/entenc.h" "${AOM_ROOT}/aom_dsp/fwd_txfm.c" @@ -254,6 +253,7 @@ if(CONFIG_AV1_ENCODER) list(APPEND AOM_DSP_ENCODER_INTRIN_SSSE3 "${AOM_ROOT}/aom_dsp/x86/masked_sad_intrin_ssse3.h" "${AOM_ROOT}/aom_dsp/x86/masked_sad_intrin_ssse3.c" + "${AOM_ROOT}/aom_dsp/x86/masked_sad4d_ssse3.c" "${AOM_ROOT}/aom_dsp/x86/masked_variance_intrin_ssse3.h" "${AOM_ROOT}/aom_dsp/x86/masked_variance_intrin_ssse3.c" "${AOM_ROOT}/aom_dsp/x86/quantize_ssse3.c" @@ -277,7 +277,8 @@ if(CONFIG_AV1_ENCODER) "${AOM_ROOT}/aom_dsp/arm/subpel_variance_neon.c" "${AOM_ROOT}/aom_dsp/arm/variance_neon.c" "${AOM_ROOT}/aom_dsp/arm/hadamard_neon.c" - "${AOM_ROOT}/aom_dsp/arm/avg_neon.c") + "${AOM_ROOT}/aom_dsp/arm/avg_neon.c" + "${AOM_ROOT}/aom_dsp/arm/sse_neon.c") list(APPEND AOM_DSP_ENCODER_INTRIN_MSA "${AOM_ROOT}/aom_dsp/mips/sad_msa.c" "${AOM_ROOT}/aom_dsp/mips/subtract_msa.c" @@ -289,6 +290,11 @@ if(CONFIG_AV1_ENCODER) "${AOM_ROOT}/aom_dsp/psnrhvs.c" "${AOM_ROOT}/aom_dsp/ssim.c" "${AOM_ROOT}/aom_dsp/ssim.h") endif() + + if(CONFIG_TUNE_VMAF) + list(APPEND AOM_DSP_ENCODER_SOURCES "${AOM_ROOT}/aom_dsp/vmaf.c" + "${AOM_ROOT}/aom_dsp/vmaf.h") + endif() endif() # Creates aom_dsp build targets. Must not be called until after libaom target @@ -299,6 +305,9 @@ function(setup_aom_dsp_targets) create_dummy_source_file("aom_av1" "c" "dummy_source_file") add_library(aom_dsp OBJECT "${dummy_source_file}") target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() list(APPEND AOM_LIB_TARGETS aom_dsp) # Not all generators support libraries consisting only of object files. Add a @@ -309,96 +318,103 @@ function(setup_aom_dsp_targets) add_library(aom_dsp_decoder OBJECT ${AOM_DSP_DECODER_SOURCES}) list(APPEND AOM_LIB_TARGETS aom_dsp_decoder) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endif() if(CONFIG_AV1_ENCODER) add_library(aom_dsp_encoder OBJECT ${AOM_DSP_ENCODER_SOURCES}) list(APPEND AOM_LIB_TARGETS aom_dsp_encoder) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endif() if(HAVE_SSE2) - add_asm_library("aom_dsp_common_sse2" "AOM_DSP_COMMON_ASM_SSE2" "aom") + add_asm_library("aom_dsp_common_sse2" "AOM_DSP_COMMON_ASM_SSE2") add_intrinsics_object_library("-msse2" "sse2" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_SSE2" "aom") + "AOM_DSP_COMMON_INTRIN_SSE2") if(CONFIG_AV1_ENCODER) if("${AOM_TARGET_CPU}" STREQUAL "x86_64") list(APPEND AOM_DSP_ENCODER_ASM_SSE2 ${AOM_DSP_ENCODER_ASM_SSE2_X86_64}) endif() - add_asm_library("aom_dsp_encoder_sse2" "AOM_DSP_ENCODER_ASM_SSE2" "aom") + add_asm_library("aom_dsp_encoder_sse2" "AOM_DSP_ENCODER_ASM_SSE2") add_intrinsics_object_library("-msse2" "sse2" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_SSE2" "aom") + "AOM_DSP_ENCODER_INTRIN_SSE2") endif() endif() if(HAVE_SSSE3) - add_asm_library("aom_dsp_common_ssse3" "AOM_DSP_COMMON_ASM_SSSE3" "aom") + add_asm_library("aom_dsp_common_ssse3" "AOM_DSP_COMMON_ASM_SSSE3") add_intrinsics_object_library("-mssse3" "ssse3" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_SSSE3" "aom") + "AOM_DSP_COMMON_INTRIN_SSSE3") if(CONFIG_AV1_ENCODER) if("${AOM_TARGET_CPU}" STREQUAL "x86_64") list(APPEND AOM_DSP_ENCODER_ASM_SSSE3 ${AOM_DSP_ENCODER_ASM_SSSE3_X86_64}) endif() - add_asm_library("aom_dsp_encoder_ssse3" "AOM_DSP_ENCODER_ASM_SSSE3" "aom") + add_asm_library("aom_dsp_encoder_ssse3" "AOM_DSP_ENCODER_ASM_SSSE3") add_intrinsics_object_library("-mssse3" "ssse3" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_SSSE3" "aom") + "AOM_DSP_ENCODER_INTRIN_SSSE3") endif() endif() if(HAVE_SSE4_1) add_intrinsics_object_library("-msse4.1" "sse4_1" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_SSE4_1" "aom") + "AOM_DSP_COMMON_INTRIN_SSE4_1") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("-msse4.1" "sse4_1" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_SSE4_1" "aom") + "AOM_DSP_ENCODER_INTRIN_SSE4_1") endif() endif() if(HAVE_AVX AND "${AOM_TARGET_CPU}" STREQUAL "x86_64") if(CONFIG_AV1_ENCODER) - add_asm_library("aom_dsp_encoder_avx" "AOM_DSP_ENCODER_AVX_ASM_X86_64" - "aom") + add_asm_library("aom_dsp_encoder_avx" "AOM_DSP_ENCODER_AVX_ASM_X86_64") endif() endif() if(HAVE_AVX2) add_intrinsics_object_library("-mavx2" "avx2" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_AVX2" "aom") + "AOM_DSP_COMMON_INTRIN_AVX2") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("-mavx2" "avx2" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_AVX2" "aom") + "AOM_DSP_ENCODER_INTRIN_AVX2") endif() endif() if(HAVE_NEON) add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" - "aom_dsp_common" "AOM_DSP_COMMON_INTRIN_NEON" - "aom") + "aom_dsp_common" "AOM_DSP_COMMON_INTRIN_NEON") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_NEON" "aom") + "AOM_DSP_ENCODER_INTRIN_NEON") endif() endif() if(HAVE_DSPR2) add_intrinsics_object_library("" "dspr2" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_DSPR2" "aom") + "AOM_DSP_COMMON_INTRIN_DSPR2") endif() if(HAVE_MSA) add_intrinsics_object_library("" "msa" "aom_dsp_common" - "AOM_DSP_COMMON_INTRIN_MSA" "aom") + "AOM_DSP_COMMON_INTRIN_MSA") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("" "msa" "aom_dsp_encoder" - "AOM_DSP_ENCODER_INTRIN_MSA" "aom") + "AOM_DSP_ENCODER_INTRIN_MSA") endif() endif() target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() # Pass the new lib targets up to the parent scope instance of # $AOM_LIB_TARGETS. diff --git a/media/libaom/src/aom_dsp/aom_dsp_common.h b/media/libaom/src/aom_dsp/aom_dsp_common.h index a185b23c8e..150d35dd15 100644 --- a/media/libaom/src/aom_dsp/aom_dsp_common.h +++ b/media/libaom/src/aom_dsp/aom_dsp_common.h @@ -27,6 +27,9 @@ extern "C" { #define AOMMIN(x, y) (((x) < (y)) ? (x) : (y)) #define AOMMAX(x, y) (((x) > (y)) ? (x) : (y)) +#define AOMSIGN(x) ((x) < 0 ? -1 : 0) + +#define NELEMENTS(x) (int)(sizeof(x) / sizeof(x[0])) #define IMPLIES(a, b) (!(a) || (b)) // Logical 'a implies b' (or 'a -> b') diff --git a/media/libaom/src/aom_dsp/aom_dsp_rtcd_defs.pl b/media/libaom/src/aom_dsp/aom_dsp_rtcd_defs.pl index 9867602d4e..b7d5a41ba1 100644 --- a/media/libaom/src/aom_dsp/aom_dsp_rtcd_defs.pl +++ b/media/libaom/src/aom_dsp/aom_dsp_rtcd_defs.pl @@ -92,6 +92,7 @@ specialize qw/aom_dc_top_predictor_8x32 sse2/; specialize qw/aom_dc_top_predictor_16x4 sse2/; specialize qw/aom_dc_top_predictor_16x8 sse2/; specialize qw/aom_dc_top_predictor_16x16 neon msa sse2/; + specialize qw/aom_dc_top_predictor_16x32 sse2/; specialize qw/aom_dc_top_predictor_16x64 sse2/; specialize qw/aom_dc_top_predictor_32x8 sse2/; @@ -480,8 +481,14 @@ if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { # Forward transform # if (aom_config("CONFIG_AV1_ENCODER") eq "yes"){ + add_proto qw/void aom_fdct4x4/, "const int16_t *input, tran_low_t *output, int stride"; + specialize qw/aom_fdct4x4 neon sse2/; + + add_proto qw/void aom_fdct4x4_lp/, "const int16_t *input, int16_t *output, int stride"; + specialize qw/aom_fdct4x4_lp neon sse2/; + add_proto qw/void aom_fdct8x8/, "const int16_t *input, tran_low_t *output, int stride"; - specialize qw/aom_fdct8x8 sse2/, "$ssse3_x86_64"; + specialize qw/aom_fdct8x8 neon sse2/, "$ssse3_x86_64"; # High bit depth if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { add_proto qw/void aom_highbd_fdct8x8/, "const int16_t *input, tran_low_t *output, int stride"; @@ -591,7 +598,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_subtract_block neon msa sse2 avx2/; add_proto qw/int64_t/, "aom_sse", "const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height"; - specialize qw/aom_sse sse4_1 avx2/; + specialize qw/aom_sse sse4_1 avx2 neon/; add_proto qw/void/, "aom_get_blk_sse_sum", "const int16_t *data, int stride, int bw, int bh, int *x_sum, int64_t *x2_sum"; specialize qw/aom_get_blk_sse_sum sse2 avx2/; @@ -601,7 +608,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_highbd_subtract_block sse2/; add_proto qw/int64_t/, "aom_highbd_sse", "const uint8_t *a8, int a_stride, const uint8_t *b8,int b_stride, int width, int height"; - specialize qw/aom_highbd_sse sse4_1 avx2/; + specialize qw/aom_highbd_sse sse4_1 avx2 neon/; } if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { @@ -613,6 +620,12 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/uint64_t aom_sum_squares_i16/, "const int16_t *src, uint32_t N"; specialize qw/aom_sum_squares_i16 sse2/; + + add_proto qw/uint64_t aom_var_2d_u8/, "uint8_t *src, int src_stride, int width, int height"; + specialize qw/aom_var_2d_u8 sse2 avx2/; + + add_proto qw/uint64_t aom_var_2d_u16/, "uint8_t *src, int src_stride, int width, int height"; + specialize qw/aom_var_2d_u16 sse2 avx2/; } # @@ -810,6 +823,8 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { foreach (@block_sizes) { ($w, $h) = @$_; add_proto qw/void/, "aom_sad${w}x${h}x4d", "const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array"; + add_proto qw/void/, "aom_sad${w}x${h}x4d_avg", "const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, const uint8_t *second_pred, uint32_t *sad_array"; + add_proto qw/void/, "aom_masked_sad${w}x${h}x4d", "const uint8_t *src, int src_stride, const uint8_t *ref[], int ref_stride, const uint8_t *second_pred, const uint8_t *msk, int msk_stride, int invert_mask, unsigned sads[]"; } specialize qw/aom_sad128x128x4d avx2 sse2/; @@ -817,25 +832,87 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_sad64x128x4d avx2 sse2/; specialize qw/aom_sad64x64x4d avx2 neon msa sse2/; specialize qw/aom_sad64x32x4d avx2 msa sse2/; + specialize qw/aom_sad64x16x4d avx2 sse2/; specialize qw/aom_sad32x64x4d avx2 msa sse2/; specialize qw/aom_sad32x32x4d avx2 neon msa sse2/; - specialize qw/aom_sad32x16x4d msa sse2/; + specialize qw/aom_sad32x16x4d avx2 msa sse2/; + specialize qw/aom_sad32x8x4d avx2 sse2/; + specialize qw/aom_sad16x64x4d sse2/; specialize qw/aom_sad16x32x4d msa sse2/; - specialize qw/aom_sad16x16x4d neon msa sse2/; - specialize qw/aom_sad16x8x4d msa sse2/; + specialize qw/aom_sad16x16x4d neon msa sse2/; + specialize qw/aom_sad16x8x4d msa sse2/; + specialize qw/aom_sad8x16x4d msa sse2/; specialize qw/aom_sad8x8x4d msa sse2/; specialize qw/aom_sad8x4x4d msa sse2/; + specialize qw/aom_sad4x16x4d msa sse2/; specialize qw/aom_sad4x8x4d msa sse2/; specialize qw/aom_sad4x4x4d msa sse2/; + specialize qw/aom_sad4x32x4d sse2/; specialize qw/aom_sad4x16x4d sse2/; specialize qw/aom_sad16x4x4d sse2/; specialize qw/aom_sad8x32x4d sse2/; specialize qw/aom_sad32x8x4d sse2/; - specialize qw/aom_sad16x64x4d sse2/; specialize qw/aom_sad64x16x4d sse2/; + specialize qw/aom_sad128x128x4d_avg sse2/; + specialize qw/aom_sad128x64x4d_avg sse2/; + specialize qw/aom_sad64x128x4d_avg sse2/; + specialize qw/aom_sad64x64x4d_avg sse2/; + specialize qw/aom_sad64x32x4d_avg sse2/; + specialize qw/aom_sad64x16x4d_avg sse2/; + specialize qw/aom_sad32x64x4d_avg sse2/; + specialize qw/aom_sad32x32x4d_avg sse2/; + specialize qw/aom_sad32x16x4d_avg sse2/; + specialize qw/aom_sad32x8x4d_avg sse2/; + specialize qw/aom_sad16x64x4d_avg sse2/; + specialize qw/aom_sad16x32x4d_avg sse2/; + specialize qw/aom_sad16x16x4d_avg sse2/; + specialize qw/aom_sad16x8x4d_avg sse2/; + + specialize qw/aom_sad8x16x4d_avg sse2/; + specialize qw/aom_sad8x8x4d_avg sse2/; + specialize qw/aom_sad8x4x4d_avg sse2/; + specialize qw/aom_sad4x16x4d_avg sse2/; + specialize qw/aom_sad4x8x4d_avg sse2/; + specialize qw/aom_sad4x4x4d_avg sse2/; + + specialize qw/aom_sad4x32x4d_avg sse2/; + specialize qw/aom_sad4x16x4d_avg sse2/; + specialize qw/aom_sad16x4x4d_avg sse2/; + specialize qw/aom_sad8x32x4d_avg sse2/; + specialize qw/aom_sad32x8x4d_avg sse2/; + specialize qw/aom_sad64x16x4d_avg sse2/; + + specialize qw/aom_masked_sad128x128x4d ssse3/; + specialize qw/aom_masked_sad128x64x4d ssse3/; + specialize qw/aom_masked_sad64x128x4d ssse3/; + specialize qw/aom_masked_sad64x64x4d ssse3/; + specialize qw/aom_masked_sad64x32x4d ssse3/; + specialize qw/aom_masked_sad64x16x4d ssse3/; + specialize qw/aom_masked_sad32x64x4d ssse3/; + specialize qw/aom_masked_sad32x32x4d ssse3/; + specialize qw/aom_masked_sad32x16x4d ssse3/; + specialize qw/aom_masked_sad32x8x4d ssse3/; + specialize qw/aom_masked_sad16x64x4d ssse3/; + specialize qw/aom_masked_sad16x32x4d ssse3/; + specialize qw/aom_masked_sad16x16x4d ssse3/; + specialize qw/aom_masked_sad16x8x4d ssse3/; + + specialize qw/aom_masked_sad8x16x4d ssse3/; + specialize qw/aom_masked_sad8x8x4d ssse3/; + specialize qw/aom_masked_sad8x4x4d ssse3/; + specialize qw/aom_masked_sad4x16x4d ssse3/; + specialize qw/aom_masked_sad4x8x4d ssse3/; + specialize qw/aom_masked_sad4x4x4d ssse3/; + + specialize qw/aom_masked_sad4x32x4d ssse3/; + specialize qw/aom_masked_sad4x16x4d ssse3/; + specialize qw/aom_masked_sad16x4x4d ssse3/; + specialize qw/aom_masked_sad8x32x4d ssse3/; + specialize qw/aom_masked_sad32x8x4d ssse3/; + specialize qw/aom_masked_sad64x16x4d ssse3/; # # Multi-block SAD, comparing a reference to N independent blocks # @@ -911,6 +988,13 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/void aom_hadamard_32x32/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff"; specialize qw/aom_hadamard_32x32 avx2 sse2/; + add_proto qw/void aom_hadamard_lp_8x8/, "const int16_t *src_diff, ptrdiff_t src_stride, int16_t *coeff"; + specialize qw/aom_hadamard_lp_8x8 sse2 neon/; + + add_proto qw/void aom_hadamard_lp_16x16/, "const int16_t *src_diff, ptrdiff_t src_stride, int16_t *coeff"; + specialize qw/aom_hadamard_lp_16x16 avx2 neon/; + + if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { add_proto qw/void aom_highbd_hadamard_8x8/, "const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff"; specialize qw/aom_highbd_hadamard_8x8 avx2/; @@ -924,6 +1008,10 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/int aom_satd/, "const tran_low_t *coeff, int length"; specialize qw/aom_satd avx2/; + add_proto qw/int aom_satd_lp/, "const int16_t *coeff, int length"; + specialize qw/aom_satd_lp avx2 neon/; + + # # Structured Similarity (SSIM) # @@ -1048,7 +1136,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/uint32_t/, "aom_sub_pixel_avg_variance${w}x${h}", "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse, const uint8_t *second_pred"; add_proto qw/uint32_t/, "aom_dist_wtd_sub_pixel_avg_variance${w}x${h}", "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse, const uint8_t *second_pred, const DIST_WTD_COMP_PARAMS *jcp_param"; } - specialize qw/aom_variance128x128 sse2 avx2 /; + specialize qw/aom_variance128x128 sse2 avx2 neon /; specialize qw/aom_variance128x64 sse2 avx2 /; specialize qw/aom_variance64x128 sse2 avx2 /; specialize qw/aom_variance64x64 sse2 avx2 neon msa/; @@ -1073,9 +1161,9 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_sub_pixel_variance32x64 avx2 msa sse2 ssse3/; specialize qw/aom_sub_pixel_variance32x32 avx2 neon msa sse2 ssse3/; specialize qw/aom_sub_pixel_variance32x16 avx2 msa sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x32 msa sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x16 neon msa sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x8 msa sse2 ssse3/; + specialize qw/aom_sub_pixel_variance16x32 avx2 msa sse2 ssse3/; + specialize qw/aom_sub_pixel_variance16x16 avx2 neon msa sse2 ssse3/; + specialize qw/aom_sub_pixel_variance16x8 avx2 msa sse2 ssse3/; specialize qw/aom_sub_pixel_variance8x16 msa sse2 ssse3/; specialize qw/aom_sub_pixel_variance8x8 neon msa sse2 ssse3/; specialize qw/aom_sub_pixel_variance8x4 msa sse2 ssse3/; @@ -1107,10 +1195,10 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/aom_variance64x16 sse2 avx2/; specialize qw/aom_sub_pixel_variance4x16 sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x4 sse2 ssse3/; + specialize qw/aom_sub_pixel_variance16x4 avx2 sse2 ssse3/; specialize qw/aom_sub_pixel_variance8x32 sse2 ssse3/; specialize qw/aom_sub_pixel_variance32x8 sse2 ssse3/; - specialize qw/aom_sub_pixel_variance16x64 sse2 ssse3/; + specialize qw/aom_sub_pixel_variance16x64 avx2 sse2 ssse3/; specialize qw/aom_sub_pixel_variance64x16 sse2 ssse3/; specialize qw/aom_sub_pixel_avg_variance4x16 sse2 ssse3/; specialize qw/aom_sub_pixel_avg_variance16x4 sse2 ssse3/; diff --git a/media/libaom/src/aom_dsp/arm/avg_neon.c b/media/libaom/src/aom_dsp/arm/avg_neon.c index 3779635cbc..af3769edf8 100644 --- a/media/libaom/src/aom_dsp/arm/avg_neon.c +++ b/media/libaom/src/aom_dsp/arm/avg_neon.c @@ -47,3 +47,28 @@ unsigned int aom_avg_8x8_neon(const uint8_t *a, int a_stride) { return vget_lane_u32(vrshr_n_u32(d, 6), 0); } + +int aom_satd_lp_neon(const int16_t *coeff, int length) { + const int16x4_t zero = vdup_n_s16(0); + int32x4_t accum = vdupq_n_s32(0); + + do { + const int16x8_t src0 = vld1q_s16(coeff); + const int16x8_t src8 = vld1q_s16(coeff + 8); + accum = vabal_s16(accum, vget_low_s16(src0), zero); + accum = vabal_s16(accum, vget_high_s16(src0), zero); + accum = vabal_s16(accum, vget_low_s16(src8), zero); + accum = vabal_s16(accum, vget_high_s16(src8), zero); + length -= 16; + coeff += 16; + } while (length != 0); + + { + // satd: 26 bits, dynamic range [-32640 * 1024, 32640 * 1024] + const int64x2_t s0 = vpaddlq_s32(accum); // cascading summation of 'accum'. + const int32x2_t s1 = vadd_s32(vreinterpret_s32_s64(vget_low_s64(s0)), + vreinterpret_s32_s64(vget_high_s64(s0))); + const int satd = vget_lane_s32(s1, 0); + return satd; + } +} diff --git a/media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c b/media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c index e4300c9920..ce93523478 100644 --- a/media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c +++ b/media/libaom/src/aom_dsp/arm/fwd_txfm_neon.c @@ -14,9 +14,103 @@ #include "config/aom_config.h" #include "aom_dsp/txfm_common.h" +#include "av1/common/arm/mem_neon.h" +#include "av1/common/arm/transpose_neon.h" + +static void aom_fdct4x4_helper(const int16_t *input, int stride, + int16x4_t *input_0, int16x4_t *input_1, + int16x4_t *input_2, int16x4_t *input_3) { + *input_0 = vshl_n_s16(vld1_s16(input + 0 * stride), 4); + *input_1 = vshl_n_s16(vld1_s16(input + 1 * stride), 4); + *input_2 = vshl_n_s16(vld1_s16(input + 2 * stride), 4); + *input_3 = vshl_n_s16(vld1_s16(input + 3 * stride), 4); + // If the very first value != 0, then add 1. + if (input[0] != 0) { + const int16x4_t one = vreinterpret_s16_s64(vdup_n_s64(1)); + *input_0 = vadd_s16(*input_0, one); + } + + for (int i = 0; i < 2; ++i) { + const int16x8_t input_01 = vcombine_s16(*input_0, *input_1); + const int16x8_t input_32 = vcombine_s16(*input_3, *input_2); + + // in_0 +/- in_3, in_1 +/- in_2 + const int16x8_t s_01 = vaddq_s16(input_01, input_32); + const int16x8_t s_32 = vsubq_s16(input_01, input_32); + + // step_0 +/- step_1, step_2 +/- step_3 + const int16x4_t s_0 = vget_low_s16(s_01); + const int16x4_t s_1 = vget_high_s16(s_01); + const int16x4_t s_2 = vget_high_s16(s_32); + const int16x4_t s_3 = vget_low_s16(s_32); + + // (s_0 +/- s_1) * cospi_16_64 + // Must expand all elements to s32. See 'needs32' comment in fwd_txfm.c. + const int32x4_t s_0_p_s_1 = vaddl_s16(s_0, s_1); + const int32x4_t s_0_m_s_1 = vsubl_s16(s_0, s_1); + const int32x4_t temp1 = vmulq_n_s32(s_0_p_s_1, cospi_16_64); + const int32x4_t temp2 = vmulq_n_s32(s_0_m_s_1, cospi_16_64); + + // fdct_round_shift + int16x4_t out_0 = vrshrn_n_s32(temp1, DCT_CONST_BITS); + int16x4_t out_2 = vrshrn_n_s32(temp2, DCT_CONST_BITS); + + // s_3 * cospi_8_64 + s_2 * cospi_24_64 + // s_3 * cospi_24_64 - s_2 * cospi_8_64 + const int32x4_t s_3_cospi_8_64 = vmull_n_s16(s_3, cospi_8_64); + const int32x4_t s_3_cospi_24_64 = vmull_n_s16(s_3, cospi_24_64); + + const int32x4_t temp3 = vmlal_n_s16(s_3_cospi_8_64, s_2, cospi_24_64); + const int32x4_t temp4 = vmlsl_n_s16(s_3_cospi_24_64, s_2, cospi_8_64); + + // fdct_round_shift + int16x4_t out_1 = vrshrn_n_s32(temp3, DCT_CONST_BITS); + int16x4_t out_3 = vrshrn_n_s32(temp4, DCT_CONST_BITS); + + transpose_s16_4x4d(&out_0, &out_1, &out_2, &out_3); + + *input_0 = out_0; + *input_1 = out_1; + *input_2 = out_2; + *input_3 = out_3; + } +} + +void aom_fdct4x4_neon(const int16_t *input, tran_low_t *final_output, + int stride) { + // input[M * stride] * 16 + int16x4_t input_0, input_1, input_2, input_3; + + aom_fdct4x4_helper(input, stride, &input_0, &input_1, &input_2, &input_3); + + // Not quite a rounding shift. Only add 1 despite shifting by 2. + const int16x8_t one = vdupq_n_s16(1); + int16x8_t out_01 = vcombine_s16(input_0, input_1); + int16x8_t out_23 = vcombine_s16(input_2, input_3); + out_01 = vshrq_n_s16(vaddq_s16(out_01, one), 2); + out_23 = vshrq_n_s16(vaddq_s16(out_23, one), 2); + store_s16q_to_tran_low(final_output + 0 * 8, out_01); + store_s16q_to_tran_low(final_output + 1 * 8, out_23); +} + +void aom_fdct4x4_lp_neon(const int16_t *input, int16_t *final_output, + int stride) { + // input[M * stride] * 16 + int16x4_t input_0, input_1, input_2, input_3; + + aom_fdct4x4_helper(input, stride, &input_0, &input_1, &input_2, &input_3); + + // Not quite a rounding shift. Only add 1 despite shifting by 2. + const int16x8_t one = vdupq_n_s16(1); + int16x8_t out_01 = vcombine_s16(input_0, input_1); + int16x8_t out_23 = vcombine_s16(input_2, input_3); + out_01 = vshrq_n_s16(vaddq_s16(out_01, one), 2); + out_23 = vshrq_n_s16(vaddq_s16(out_23, one), 2); + vst1q_s16(final_output + 0 * 8, out_01); + vst1q_s16(final_output + 1 * 8, out_23); +} void aom_fdct8x8_neon(const int16_t *input, int16_t *final_output, int stride) { - int i; // stage 1 int16x8_t input_0 = vshlq_n_s16(vld1q_s16(&input[0 * stride]), 2); int16x8_t input_1 = vshlq_n_s16(vld1q_s16(&input[1 * stride]), 2); @@ -26,7 +120,7 @@ void aom_fdct8x8_neon(const int16_t *input, int16_t *final_output, int stride) { int16x8_t input_5 = vshlq_n_s16(vld1q_s16(&input[5 * stride]), 2); int16x8_t input_6 = vshlq_n_s16(vld1q_s16(&input[6 * stride]), 2); int16x8_t input_7 = vshlq_n_s16(vld1q_s16(&input[7 * stride]), 2); - for (i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) { int16x8_t out_0, out_1, out_2, out_3, out_4, out_5, out_6, out_7; const int16x8_t v_s0 = vaddq_s16(input_0, input_7); const int16x8_t v_s1 = vaddq_s16(input_1, input_6); diff --git a/media/libaom/src/aom_dsp/arm/hadamard_neon.c b/media/libaom/src/aom_dsp/arm/hadamard_neon.c index a995aecc68..929792ab33 100644 --- a/media/libaom/src/aom_dsp/arm/hadamard_neon.c +++ b/media/libaom/src/aom_dsp/arm/hadamard_neon.c @@ -75,6 +75,76 @@ void aom_hadamard_8x8_neon(const int16_t *src_diff, ptrdiff_t src_stride, store_s16q_to_tran_low(coeff + 56, a7); } +void aom_hadamard_lp_8x8_neon(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + int16x8_t a0 = vld1q_s16(src_diff); + int16x8_t a1 = vld1q_s16(src_diff + src_stride); + int16x8_t a2 = vld1q_s16(src_diff + 2 * src_stride); + int16x8_t a3 = vld1q_s16(src_diff + 3 * src_stride); + int16x8_t a4 = vld1q_s16(src_diff + 4 * src_stride); + int16x8_t a5 = vld1q_s16(src_diff + 5 * src_stride); + int16x8_t a6 = vld1q_s16(src_diff + 6 * src_stride); + int16x8_t a7 = vld1q_s16(src_diff + 7 * src_stride); + + hadamard8x8_one_pass(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7); + + transpose_s16_8x8(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7); + + hadamard8x8_one_pass(&a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7); + + // Skip the second transpose because it is not required. + + vst1q_s16(coeff + 0, a0); + vst1q_s16(coeff + 8, a1); + vst1q_s16(coeff + 16, a2); + vst1q_s16(coeff + 24, a3); + vst1q_s16(coeff + 32, a4); + vst1q_s16(coeff + 40, a5); + vst1q_s16(coeff + 48, a6); + vst1q_s16(coeff + 56, a7); +} + +void aom_hadamard_lp_16x16_neon(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + /* Rearrange 16x16 to 8x32 and remove stride. + * Top left first. */ + aom_hadamard_lp_8x8_neon(src_diff + 0 + 0 * src_stride, src_stride, + coeff + 0); + /* Top right. */ + aom_hadamard_lp_8x8_neon(src_diff + 8 + 0 * src_stride, src_stride, + coeff + 64); + /* Bottom left. */ + aom_hadamard_lp_8x8_neon(src_diff + 0 + 8 * src_stride, src_stride, + coeff + 128); + /* Bottom right. */ + aom_hadamard_lp_8x8_neon(src_diff + 8 + 8 * src_stride, src_stride, + coeff + 192); + + for (int i = 0; i < 64; i += 8) { + const int16x8_t a0 = vld1q_s16(coeff + 0); + const int16x8_t a1 = vld1q_s16(coeff + 64); + const int16x8_t a2 = vld1q_s16(coeff + 128); + const int16x8_t a3 = vld1q_s16(coeff + 192); + + const int16x8_t b0 = vhaddq_s16(a0, a1); + const int16x8_t b1 = vhsubq_s16(a0, a1); + const int16x8_t b2 = vhaddq_s16(a2, a3); + const int16x8_t b3 = vhsubq_s16(a2, a3); + + const int16x8_t c0 = vaddq_s16(b0, b2); + const int16x8_t c1 = vaddq_s16(b1, b3); + const int16x8_t c2 = vsubq_s16(b0, b2); + const int16x8_t c3 = vsubq_s16(b1, b3); + + vst1q_s16(coeff + 0, c0); + vst1q_s16(coeff + 64, c1); + vst1q_s16(coeff + 128, c2); + vst1q_s16(coeff + 192, c3); + + coeff += 8; + } +} + void aom_hadamard_16x16_neon(const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff) { /* Rearrange 16x16 to 8x32 and remove stride. diff --git a/media/libaom/src/aom_dsp/arm/sse_neon.c b/media/libaom/src/aom_dsp/arm/sse_neon.c new file mode 100644 index 0000000000..06b81cc3d3 --- /dev/null +++ b/media/libaom/src/aom_dsp/arm/sse_neon.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" + +#include "aom/aom_integer.h" + +static INLINE uint32_t sse_W16x1_neon(uint8x16_t q2, uint8x16_t q3) { + const uint16_t sse1 = 0; + const uint16x8_t q1 = vld1q_dup_u16(&sse1); + + uint32_t sse; + + uint8x16_t q4 = vabdq_u8(q2, q3); // diff = abs(a[x] - b[x]) + uint8x8_t d0 = vget_low_u8(q4); + uint8x8_t d1 = vget_high_u8(q4); + + uint16x8_t q6 = vmlal_u8(q1, d0, d0); + uint16x8_t q7 = vmlal_u8(q1, d1, d1); + + uint32x4_t q8 = vaddl_u16(vget_low_u16(q6), vget_high_u16(q6)); + uint32x4_t q9 = vaddl_u16(vget_low_u16(q7), vget_high_u16(q7)); + + uint32x2_t d4 = vadd_u32(vget_low_u32(q8), vget_high_u32(q8)); + uint32x2_t d5 = vadd_u32(vget_low_u32(q9), vget_high_u32(q9)); + + uint32x2_t d6 = vadd_u32(d4, d5); + + sse = vget_lane_u32(d6, 0); + sse += vget_lane_u32(d6, 1); + + return sse; +} + +int64_t aom_sse_neon(const uint8_t *a, int a_stride, const uint8_t *b, + int b_stride, int width, int height) { + const uint8x16_t q0 = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + int addinc, x, y; + uint8x8_t d0, d1, d2, d3; + uint8_t dx; + uint8x16_t q2, q3, q4, q5; + uint32_t sse = 0; + uint8x8x2_t tmp, tmp2; + + switch (width) { + case 4: + for (y = 0; y < height; y += 4) { + d0 = vld1_u8(a); // load 4 data + a += a_stride; + d1 = vld1_u8(a); + a += a_stride; + d2 = vld1_u8(a); + a += a_stride; + d3 = vld1_u8(a); + a += a_stride; + tmp = vzip_u8(d0, d1); + tmp2 = vzip_u8(d2, d3); + q2 = vcombine_u8(tmp.val[0], tmp2.val[0]); // make a 16 data vector + + d0 = vld1_u8(b); + b += b_stride; + d1 = vld1_u8(b); + b += b_stride; + d2 = vld1_u8(b); + b += b_stride; + d3 = vld1_u8(b); + b += b_stride; + tmp = vzip_u8(d0, d1); + tmp2 = vzip_u8(d2, d3); + q3 = vcombine_u8(tmp.val[0], tmp2.val[0]); + + sse += sse_W16x1_neon(q2, q3); + } + break; + case 8: + for (y = 0; y < height; y += 2) { + d0 = vld1_u8(a); // load 8 data + d1 = vld1_u8(a + a_stride); + q2 = vcombine_u8(d0, d1); // make a 16 data vector + + d0 = vld1_u8(b); + d1 = vld1_u8(b + b_stride); + q3 = vcombine_u8(d0, d1); + + sse += sse_W16x1_neon(q2, q3); + + a += 2 * a_stride; + b += 2 * b_stride; + } + break; + case 16: + for (y = 0; y < height; y++) { + q2 = vld1q_u8(a); + q3 = vld1q_u8(b); + + sse += sse_W16x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 32: + for (y = 0; y < height; y++) { + q2 = vld1q_u8(a); + q3 = vld1q_u8(b); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 16); + q3 = vld1q_u8(b + 16); + + sse += sse_W16x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 64: + for (y = 0; y < height; y++) { + q2 = vld1q_u8(a); + q3 = vld1q_u8(b); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 16); + q3 = vld1q_u8(b + 16); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 32); + q3 = vld1q_u8(b + 32); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 48); + q3 = vld1q_u8(b + 48); + + sse += sse_W16x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 128: + for (y = 0; y < height; y++) { + q2 = vld1q_u8(a); + q3 = vld1q_u8(b); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 16); + q3 = vld1q_u8(b + 16); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 32); + q3 = vld1q_u8(b + 32); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 48); + q3 = vld1q_u8(b + 48); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 64); + q3 = vld1q_u8(b + 64); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 80); + q3 = vld1q_u8(b + 80); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 96); + q3 = vld1q_u8(b + 96); + + sse += sse_W16x1_neon(q2, q3); + + q2 = vld1q_u8(a + 112); + q3 = vld1q_u8(b + 112); + + sse += sse_W16x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + default: + for (y = 0; y < height; y++) { + x = width; + while (x > 0) { + addinc = width - x; + q2 = vld1q_u8(a + addinc); + q3 = vld1q_u8(b + addinc); + if (x < 16) { + dx = x; + q4 = vld1q_dup_u8(&dx); + q5 = vcltq_u8(q0, q4); + q2 = vandq_u8(q2, q5); + q3 = vandq_u8(q3, q5); + } + sse += sse_W16x1_neon(q2, q3); + x -= 16; + } + a += a_stride; + b += b_stride; + } + } + return (int64_t)sse; +} + +#if CONFIG_AV1_HIGHBITDEPTH +static INLINE uint32_t highbd_sse_W8x1_neon(uint16x8_t q2, uint16x8_t q3) { + uint32_t sse; + const uint32_t sse1 = 0; + const uint32x4_t q1 = vld1q_dup_u32(&sse1); + + uint16x8_t q4 = vabdq_u16(q2, q3); // diff = abs(a[x] - b[x]) + uint16x4_t d0 = vget_low_u16(q4); + uint16x4_t d1 = vget_high_u16(q4); + + uint32x4_t q6 = vmlal_u16(q1, d0, d0); + uint32x4_t q7 = vmlal_u16(q1, d1, d1); + + uint32x2_t d4 = vadd_u32(vget_low_u32(q6), vget_high_u32(q6)); + uint32x2_t d5 = vadd_u32(vget_low_u32(q7), vget_high_u32(q7)); + + uint32x2_t d6 = vadd_u32(d4, d5); + + sse = vget_lane_u32(d6, 0); + sse += vget_lane_u32(d6, 1); + + return sse; +} + +int64_t aom_highbd_sse_neon(const uint8_t *a8, int a_stride, const uint8_t *b8, + int b_stride, int width, int height) { + const uint16x8_t q0 = { 0, 1, 2, 3, 4, 5, 6, 7 }; + int64_t sse = 0; + uint16_t *a = CONVERT_TO_SHORTPTR(a8); + uint16_t *b = CONVERT_TO_SHORTPTR(b8); + int x, y; + int addinc; + uint16x4_t d0, d1, d2, d3; + uint16_t dx; + uint16x8_t q2, q3, q4, q5; + + switch (width) { + case 4: + for (y = 0; y < height; y += 2) { + d0 = vld1_u16(a); // load 4 data + a += a_stride; + d1 = vld1_u16(a); + a += a_stride; + + d2 = vld1_u16(b); + b += b_stride; + d3 = vld1_u16(b); + b += b_stride; + q2 = vcombine_u16(d0, d1); // make a 8 data vector + q3 = vcombine_u16(d2, d3); + + sse += highbd_sse_W8x1_neon(q2, q3); + } + break; + case 8: + for (y = 0; y < height; y++) { + q2 = vld1q_u16(a); + q3 = vld1q_u16(b); + + sse += highbd_sse_W8x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 16: + for (y = 0; y < height; y++) { + q2 = vld1q_u16(a); + q3 = vld1q_u16(b); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 8); + q3 = vld1q_u16(b + 8); + + sse += highbd_sse_W8x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 32: + for (y = 0; y < height; y++) { + q2 = vld1q_u16(a); + q3 = vld1q_u16(b); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 8); + q3 = vld1q_u16(b + 8); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 16); + q3 = vld1q_u16(b + 16); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 24); + q3 = vld1q_u16(b + 24); + + sse += highbd_sse_W8x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 64: + for (y = 0; y < height; y++) { + q2 = vld1q_u16(a); + q3 = vld1q_u16(b); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 8); + q3 = vld1q_u16(b + 8); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 16); + q3 = vld1q_u16(b + 16); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 24); + q3 = vld1q_u16(b + 24); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 32); + q3 = vld1q_u16(b + 32); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 40); + q3 = vld1q_u16(b + 40); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 48); + q3 = vld1q_u16(b + 48); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 56); + q3 = vld1q_u16(b + 56); + + sse += highbd_sse_W8x1_neon(q2, q3); + + a += a_stride; + b += b_stride; + } + break; + case 128: + for (y = 0; y < height; y++) { + q2 = vld1q_u16(a); + q3 = vld1q_u16(b); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 8); + q3 = vld1q_u16(b + 8); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 16); + q3 = vld1q_u16(b + 16); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 24); + q3 = vld1q_u16(b + 24); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 32); + q3 = vld1q_u16(b + 32); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 40); + q3 = vld1q_u16(b + 40); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 48); + q3 = vld1q_u16(b + 48); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 56); + q3 = vld1q_u16(b + 56); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 64); + q3 = vld1q_u16(b + 64); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 72); + q3 = vld1q_u16(b + 72); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 80); + q3 = vld1q_u16(b + 80); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 88); + q3 = vld1q_u16(b + 88); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 96); + q3 = vld1q_u16(b + 96); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 104); + q3 = vld1q_u16(b + 104); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 112); + q3 = vld1q_u16(b + 112); + + sse += highbd_sse_W8x1_neon(q2, q3); + + q2 = vld1q_u16(a + 120); + q3 = vld1q_u16(b + 120); + + sse += highbd_sse_W8x1_neon(q2, q3); + a += a_stride; + b += b_stride; + } + break; + default: + + for (y = 0; y < height; y++) { + x = width; + while (x > 0) { + addinc = width - x; + q2 = vld1q_u16(a + addinc); + q3 = vld1q_u16(b + addinc); + if (x < 8) { + dx = x; + q4 = vld1q_dup_u16(&dx); + q5 = vcltq_u16(q0, q4); + q2 = vandq_u16(q2, q5); + q3 = vandq_u16(q3, q5); + } + sse += highbd_sse_W8x1_neon(q2, q3); + x -= 8; + } + a += a_stride; + b += b_stride; + } + } + return (int64_t)sse; +} +#endif diff --git a/media/libaom/src/aom_dsp/arm/variance_neon.c b/media/libaom/src/aom_dsp/arm/variance_neon.c index d94f6e51a2..d4107ce0d2 100644 --- a/media/libaom/src/aom_dsp/arm/variance_neon.c +++ b/media/libaom/src/aom_dsp/arm/variance_neon.c @@ -130,6 +130,24 @@ unsigned int aom_variance64x64_neon(const uint8_t *a, int a_stride, return *sse - (unsigned int)(((int64_t)sum1 * sum1) >> 12); } +unsigned int aom_variance128x128_neon(const uint8_t *a, int a_stride, + const uint8_t *b, int b_stride, + unsigned int *sse) { + int sum1, sum2; + uint32_t sse1, sse2; + sum1 = sse1 = 0; + for (int i = 0; i < 16; i++) { + variance_neon_w8(a + (8 * i * a_stride), a_stride, b + (8 * i * b_stride), + b_stride, 128, 8, &sse2, &sum2); + sse1 += sse2; + sum1 += sum2; + } + + *sse = sse1; + + return *sse - (unsigned int)(((int64_t)sum1 * sum1) >> 14); +} + unsigned int aom_variance16x8_neon(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, @@ -355,9 +373,7 @@ unsigned int aom_get4x4sse_cs_neon(const unsigned char *src_ptr, d6u8 = vld1_u8(ref_ptr); ref_ptr += recon_stride; d3u8 = vld1_u8(src_ptr); - src_ptr += source_stride; d7u8 = vld1_u8(ref_ptr); - ref_ptr += recon_stride; q11u16 = vsubl_u8(d0u8, d4u8); q12u16 = vsubl_u8(d1u8, d5u8); diff --git a/media/libaom/src/aom_dsp/avg.c b/media/libaom/src/aom_dsp/avg.c index 5e8c5a378e..7386296fd0 100644 --- a/media/libaom/src/aom_dsp/avg.c +++ b/media/libaom/src/aom_dsp/avg.c @@ -86,7 +86,7 @@ void aom_highbd_minmax_8x8_c(const uint8_t *s8, int p, const uint8_t *d8, } } } -#endif // CONFIG_VP9_HIGHBITDEPTH +#endif // CONFIG_AV1_HIGHBITDEPTH // src_diff: first pass, 9 bit, dynamic range [-255, 255] // second pass, 12 bit, dynamic range [-2040, 2040] @@ -147,6 +147,30 @@ void aom_hadamard_8x8_c(const int16_t *src_diff, ptrdiff_t src_stride, for (idx = 0; idx < 64; ++idx) coeff[idx] = (tran_low_t)buffer2[idx]; } +void aom_hadamard_lp_8x8_c(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + int16_t buffer[64]; + int16_t buffer2[64]; + int16_t *tmp_buf = &buffer[0]; + for (int idx = 0; idx < 8; ++idx) { + hadamard_col8(src_diff, src_stride, tmp_buf); // src_diff: 9 bit + // dynamic range [-255, 255] + tmp_buf += 8; + ++src_diff; + } + + tmp_buf = &buffer[0]; + for (int idx = 0; idx < 8; ++idx) { + hadamard_col8(tmp_buf, 8, buffer2 + 8 * idx); // tmp_buf: 12 bit + // dynamic range [-2040, 2040] + // buffer2: 15 bit + // dynamic range [-16320, 16320] + ++tmp_buf; + } + + for (int idx = 0; idx < 64; ++idx) coeff[idx] = buffer2[idx]; +} + // In place 16x16 2D Hadamard transform void aom_hadamard_16x16_c(const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff) { @@ -179,6 +203,35 @@ void aom_hadamard_16x16_c(const int16_t *src_diff, ptrdiff_t src_stride, } } +void aom_hadamard_lp_16x16_c(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + for (int idx = 0; idx < 4; ++idx) { + // src_diff: 9 bit, dynamic range [-255, 255] + const int16_t *src_ptr = + src_diff + (idx >> 1) * 8 * src_stride + (idx & 0x01) * 8; + aom_hadamard_lp_8x8_c(src_ptr, src_stride, coeff + idx * 64); + } + + for (int idx = 0; idx < 64; ++idx) { + int16_t a0 = coeff[0]; + int16_t a1 = coeff[64]; + int16_t a2 = coeff[128]; + int16_t a3 = coeff[192]; + + int16_t b0 = (a0 + a1) >> 1; // (a0 + a1): 16 bit, [-32640, 32640] + int16_t b1 = (a0 - a1) >> 1; // b0-b3: 15 bit, dynamic range + int16_t b2 = (a2 + a3) >> 1; // [-16320, 16320] + int16_t b3 = (a2 - a3) >> 1; + + coeff[0] = b0 + b2; // 16 bit, [-32640, 32640] + coeff[64] = b1 + b3; + coeff[128] = b0 - b2; + coeff[192] = b1 - b3; + + ++coeff; + } +} + void aom_hadamard_32x32_c(const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff) { int idx; @@ -379,6 +432,14 @@ int aom_satd_c(const tran_low_t *coeff, int length) { return satd; } +int aom_satd_lp_c(const int16_t *coeff, int length) { + int satd = 0; + for (int i = 0; i < length; ++i) satd += abs(coeff[i]); + + // 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, diff --git a/media/libaom/src/aom_dsp/daalaboolreader.c b/media/libaom/src/aom_dsp/bitreader.c similarity index 59% rename from media/libaom/src/aom_dsp/daalaboolreader.c rename to media/libaom/src/aom_dsp/bitreader.c index 6c2259f233..4c70a91712 100644 --- a/media/libaom/src/aom_dsp/daalaboolreader.c +++ b/media/libaom/src/aom_dsp/bitreader.c @@ -9,39 +9,33 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ -#include "aom_dsp/daalaboolreader.h" +#include "aom_dsp/bitreader.h" -int aom_daala_reader_init(daala_reader *r, const uint8_t *buffer, int size) { +int aom_reader_init(aom_reader *r, const uint8_t *buffer, size_t size) { if (size && !buffer) { return 1; } r->buffer_end = buffer + size; r->buffer = buffer; - od_ec_dec_init(&r->ec, buffer, size); + od_ec_dec_init(&r->ec, buffer, (uint32_t)size); #if CONFIG_ACCOUNTING r->accounting = NULL; #endif return 0; } -const uint8_t *aom_daala_reader_find_begin(daala_reader *r) { - return r->buffer; -} +const uint8_t *aom_reader_find_begin(aom_reader *r) { return r->buffer; } -const uint8_t *aom_daala_reader_find_end(daala_reader *r) { - return r->buffer_end; -} +const uint8_t *aom_reader_find_end(aom_reader *r) { return r->buffer_end; } -uint32_t aom_daala_reader_tell(const daala_reader *r) { - return od_ec_dec_tell(&r->ec); -} +uint32_t aom_reader_tell(const aom_reader *r) { return od_ec_dec_tell(&r->ec); } -uint32_t aom_daala_reader_tell_frac(const daala_reader *r) { +uint32_t aom_reader_tell_frac(const aom_reader *r) { return od_ec_dec_tell_frac(&r->ec); } -int aom_daala_reader_has_overflowed(const daala_reader *r) { - const uint32_t tell_bits = aom_daala_reader_tell(r); +int aom_reader_has_overflowed(const aom_reader *r) { + const uint32_t tell_bits = aom_reader_tell(r); const uint32_t tell_bytes = (tell_bits + 7) >> 3; return ((ptrdiff_t)tell_bytes > r->buffer_end - r->buffer); } diff --git a/media/libaom/src/aom_dsp/bitreader.h b/media/libaom/src/aom_dsp/bitreader.h index 38b17eae5f..a8b3f55efc 100644 --- a/media/libaom/src/aom_dsp/bitreader.h +++ b/media/libaom/src/aom_dsp/bitreader.h @@ -19,7 +19,7 @@ #include "aom/aomdx.h" #include "aom/aom_integer.h" -#include "aom_dsp/daalaboolreader.h" +#include "aom_dsp/entdec.h" #include "aom_dsp/prob.h" #include "av1/common/odintrin.h" @@ -50,36 +50,33 @@ extern "C" { #endif -typedef struct daala_reader aom_reader; +struct aom_reader { + const uint8_t *buffer; + const uint8_t *buffer_end; + od_ec_dec ec; +#if CONFIG_ACCOUNTING + Accounting *accounting; +#endif + uint8_t allow_update_cdf; +}; -static INLINE int aom_reader_init(aom_reader *r, const uint8_t *buffer, - size_t size) { - return aom_daala_reader_init(r, buffer, (int)size); -} +typedef struct aom_reader aom_reader; -static INLINE const uint8_t *aom_reader_find_begin(aom_reader *r) { - return aom_daala_reader_find_begin(r); -} +int aom_reader_init(aom_reader *r, const uint8_t *buffer, size_t size); -static INLINE const uint8_t *aom_reader_find_end(aom_reader *r) { - return aom_daala_reader_find_end(r); -} +const uint8_t *aom_reader_find_begin(aom_reader *r); + +const uint8_t *aom_reader_find_end(aom_reader *r); // Returns true if the bit reader has tried to decode more data from the buffer // than was actually provided. -static INLINE int aom_reader_has_overflowed(const aom_reader *r) { - return aom_daala_reader_has_overflowed(r); -} +int aom_reader_has_overflowed(const aom_reader *r); // Returns the position in the bit reader in bits. -static INLINE uint32_t aom_reader_tell(const aom_reader *r) { - return aom_daala_reader_tell(r); -} +uint32_t aom_reader_tell(const aom_reader *r); // Returns the position in the bit reader in 1/8th bits. -static INLINE uint32_t aom_reader_tell_frac(const aom_reader *r) { - return aom_daala_reader_tell_frac(r); -} +uint32_t aom_reader_tell_frac(const aom_reader *r); #if CONFIG_ACCOUNTING static INLINE void aom_process_accounting(const aom_reader *r ACCT_STR_PARAM) { @@ -101,13 +98,48 @@ static INLINE void aom_update_symb_counts(const aom_reader *r, int is_binary) { #endif static INLINE int aom_read_(aom_reader *r, int prob ACCT_STR_PARAM) { - int ret; - ret = aom_daala_read(r, prob); + int p = (0x7FFFFF - (prob << 15) + prob) >> 8; + int bit = od_ec_decode_bool_q15(&r->ec, p); + +#if CONFIG_BITSTREAM_DEBUG + { + int i; + int ref_bit, ref_nsymbs; + aom_cdf_prob ref_cdf[16]; + const int queue_r = bitstream_queue_get_read(); + const int frame_idx = aom_bitstream_queue_get_frame_read(); + bitstream_queue_pop(&ref_bit, ref_cdf, &ref_nsymbs); + if (ref_nsymbs != 2) { + fprintf(stderr, + "\n *** [bit] nsymbs error, frame_idx_r %d nsymbs %d ref_nsymbs " + "%d queue_r %d\n", + frame_idx, 2, ref_nsymbs, queue_r); + assert(0); + } + if ((ref_nsymbs != 2) || (ref_cdf[0] != (aom_cdf_prob)p) || + (ref_cdf[1] != 32767)) { + fprintf(stderr, + "\n *** [bit] cdf error, frame_idx_r %d cdf {%d, %d} ref_cdf {%d", + frame_idx, p, 32767, ref_cdf[0]); + for (i = 1; i < ref_nsymbs; ++i) fprintf(stderr, ", %d", ref_cdf[i]); + fprintf(stderr, "} queue_r %d\n", queue_r); + assert(0); + } + if (bit != ref_bit) { + fprintf(stderr, + "\n *** [bit] symb error, frame_idx_r %d symb %d ref_symb %d " + "queue_r %d\n", + frame_idx, bit, ref_bit, queue_r); + assert(0); + } + } +#endif + #if CONFIG_ACCOUNTING if (ACCT_STR_NAME) aom_process_accounting(r, ACCT_STR_NAME); aom_update_symb_counts(r, 1); #endif - return ret; + return bit; } static INLINE int aom_read_bit_(aom_reader *r ACCT_STR_PARAM) { @@ -131,14 +163,54 @@ static INLINE int aom_read_literal_(aom_reader *r, int bits ACCT_STR_PARAM) { static INLINE int aom_read_cdf_(aom_reader *r, const aom_cdf_prob *cdf, int nsymbs ACCT_STR_PARAM) { - int ret; - ret = daala_read_symbol(r, cdf, nsymbs); + int symb; + assert(cdf != NULL); + symb = od_ec_decode_cdf_q15(&r->ec, cdf, nsymbs); + +#if CONFIG_BITSTREAM_DEBUG + { + int i; + int cdf_error = 0; + int ref_symb, ref_nsymbs; + aom_cdf_prob ref_cdf[16]; + const int queue_r = bitstream_queue_get_read(); + const int frame_idx = aom_bitstream_queue_get_frame_read(); + bitstream_queue_pop(&ref_symb, ref_cdf, &ref_nsymbs); + if (nsymbs != ref_nsymbs) { + fprintf(stderr, + "\n *** nsymbs error, frame_idx_r %d nsymbs %d ref_nsymbs %d " + "queue_r %d\n", + frame_idx, nsymbs, ref_nsymbs, queue_r); + cdf_error = 0; + assert(0); + } else { + for (i = 0; i < nsymbs; ++i) + if (cdf[i] != ref_cdf[i]) cdf_error = 1; + } + if (cdf_error) { + fprintf(stderr, "\n *** cdf error, frame_idx_r %d cdf {%d", frame_idx, + cdf[0]); + for (i = 1; i < nsymbs; ++i) fprintf(stderr, ", %d", cdf[i]); + fprintf(stderr, "} ref_cdf {%d", ref_cdf[0]); + for (i = 1; i < ref_nsymbs; ++i) fprintf(stderr, ", %d", ref_cdf[i]); + fprintf(stderr, "} queue_r %d\n", queue_r); + assert(0); + } + if (symb != ref_symb) { + fprintf( + stderr, + "\n *** symb error, frame_idx_r %d symb %d ref_symb %d queue_r %d\n", + frame_idx, symb, ref_symb, queue_r); + assert(0); + } + } +#endif #if CONFIG_ACCOUNTING if (ACCT_STR_NAME) aom_process_accounting(r, ACCT_STR_NAME); aom_update_symb_counts(r, (nsymbs == 2)); #endif - return ret; + return symb; } static INLINE int aom_read_symbol_(aom_reader *r, aom_cdf_prob *cdf, diff --git a/media/libaom/src/aom_dsp/daalaboolwriter.c b/media/libaom/src/aom_dsp/bitwriter.c similarity index 55% rename from media/libaom/src/aom_dsp/daalaboolwriter.c rename to media/libaom/src/aom_dsp/bitwriter.c index b24ffbf3fe..41fcc51754 100644 --- a/media/libaom/src/aom_dsp/daalaboolwriter.c +++ b/media/libaom/src/aom_dsp/bitwriter.c @@ -10,22 +10,22 @@ */ #include -#include "aom_dsp/daalaboolwriter.h" +#include "aom_dsp/bitwriter.h" -void aom_daala_start_encode(daala_writer *br, uint8_t *source) { - br->buffer = source; - br->pos = 0; - od_ec_enc_init(&br->ec, 62025); +void aom_start_encode(aom_writer *w, uint8_t *source) { + w->buffer = source; + w->pos = 0; + od_ec_enc_init(&w->ec, 62025); } -int aom_daala_stop_encode(daala_writer *br) { +int aom_stop_encode(aom_writer *w) { int nb_bits; - uint32_t daala_bytes; - unsigned char *daala_data; - daala_data = od_ec_enc_done(&br->ec, &daala_bytes); - nb_bits = od_ec_enc_tell(&br->ec); - memcpy(br->buffer, daala_data, daala_bytes); - br->pos = daala_bytes; - od_ec_enc_clear(&br->ec); + uint32_t bytes; + unsigned char *data; + data = od_ec_enc_done(&w->ec, &bytes); + nb_bits = od_ec_enc_tell(&w->ec); + memcpy(w->buffer, data, bytes); + w->pos = bytes; + od_ec_enc_clear(&w->ec); return nb_bits; } diff --git a/media/libaom/src/aom_dsp/bitwriter.h b/media/libaom/src/aom_dsp/bitwriter.h index b5ecc2382b..4e77a17944 100644 --- a/media/libaom/src/aom_dsp/bitwriter.h +++ b/media/libaom/src/aom_dsp/bitwriter.h @@ -16,7 +16,7 @@ #include "config/aom_config.h" -#include "aom_dsp/daalaboolwriter.h" +#include "aom_dsp/entenc.h" #include "aom_dsp/prob.h" #if CONFIG_RD_DEBUG @@ -28,7 +28,14 @@ extern "C" { #endif -typedef struct daala_writer aom_writer; +struct aom_writer { + unsigned int pos; + uint8_t *buffer; + od_ec_enc ec; + uint8_t allow_update_cdf; +}; + +typedef struct aom_writer aom_writer; typedef struct TOKEN_STATS { int cost; @@ -49,16 +56,26 @@ static INLINE void init_token_stats(TOKEN_STATS *token_stats) { token_stats->cost = 0; } -static INLINE void aom_start_encode(aom_writer *bc, uint8_t *buffer) { - aom_daala_start_encode(bc, buffer); -} +void aom_start_encode(aom_writer *w, uint8_t *buffer); -static INLINE int aom_stop_encode(aom_writer *bc) { - return aom_daala_stop_encode(bc); -} +int aom_stop_encode(aom_writer *w); -static INLINE void aom_write(aom_writer *br, int bit, int probability) { - aom_daala_write(br, bit, probability); +static INLINE void aom_write(aom_writer *w, int bit, int probability) { + int p = (0x7FFFFF - (probability << 15) + probability) >> 8; +#if CONFIG_BITSTREAM_DEBUG + aom_cdf_prob cdf[2] = { (aom_cdf_prob)p, 32767 }; + /*int queue_r = 0; + int frame_idx_r = 0; + int queue_w = bitstream_queue_get_write(); + int frame_idx_w = aom_bitstream_queue_get_frame_writee(); + if (frame_idx_w == frame_idx_r && queue_w == queue_r) { + fprintf(stderr, "\n *** bitstream queue at frame_idx_w %d queue_w %d\n", + frame_idx_w, queue_w); + }*/ + bitstream_queue_push(bit, cdf, 2); +#endif + + od_ec_encode_bool_q15(&w->ec, bit, p); } static INLINE void aom_write_bit(aom_writer *w, int bit) { @@ -73,7 +90,19 @@ static INLINE void aom_write_literal(aom_writer *w, int data, int bits) { static INLINE void aom_write_cdf(aom_writer *w, int symb, const aom_cdf_prob *cdf, int nsymbs) { - daala_write_symbol(w, symb, cdf, nsymbs); +#if CONFIG_BITSTREAM_DEBUG + /*int queue_r = 0; + int frame_idx_r = 0; + int queue_w = bitstream_queue_get_write(); + int frame_idx_w = aom_bitstream_queue_get_frame_writee(); + if (frame_idx_w == frame_idx_r && queue_w == queue_r) { + fprintf(stderr, "\n *** bitstream queue at frame_idx_w %d queue_w %d\n", + frame_idx_w, queue_w); + }*/ + bitstream_queue_push(symb, cdf, nsymbs); +#endif + + od_ec_encode_cdf_q15(&w->ec, symb, cdf, nsymbs); } static INLINE void aom_write_symbol(aom_writer *w, int symb, aom_cdf_prob *cdf, diff --git a/media/libaom/src/aom_dsp/buf_ans.c b/media/libaom/src/aom_dsp/buf_ans.c deleted file mode 100644 index f7703dffc6..0000000000 --- a/media/libaom/src/aom_dsp/buf_ans.c +++ /dev/null @@ -1,70 +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 - -#include "aom_dsp/buf_ans.h" -#include "aom_mem/aom_mem.h" -#include "aom/internal/aom_codec_internal.h" - -void aom_buf_ans_alloc(struct BufAnsCoder *c, - struct aom_internal_error_info *error) { - c->error = error; - assert(c->size > 1); - AOM_CHECK_MEM_ERROR(error, c->buf, aom_malloc(c->size * sizeof(*c->buf))); - // Initialize to overfull to trigger the assert in write. - c->offset = c->size + 1; -} - -void aom_buf_ans_free(struct BufAnsCoder *c) { - aom_free(c->buf); - c->buf = NULL; - c->size = 0; -} - -#if !ANS_MAX_SYMBOLS -void aom_buf_ans_grow(struct BufAnsCoder *c) { - struct buffered_ans_symbol *new_buf = NULL; - int new_size = c->size * 2; - AOM_CHECK_MEM_ERROR(c->error, new_buf, - aom_malloc(new_size * sizeof(*new_buf))); - memcpy(new_buf, c->buf, c->size * sizeof(*c->buf)); - aom_free(c->buf); - c->buf = new_buf; - c->size = new_size; -} -#endif - -void aom_buf_ans_flush(struct BufAnsCoder *const c) { - int offset; -#if ANS_MAX_SYMBOLS - if (c->offset == 0) return; -#endif - assert(c->offset > 0); - offset = c->offset - 1; - // Code the first symbol such that it brings the state to the smallest normal - // state from an initial state that would have been a subnormal/refill state. - if (c->buf[offset].method == ANS_METHOD_RANS) { - c->ans.state += c->buf[offset].val_start; - } else { - c->ans.state += c->buf[offset].val_start ? c->buf[offset].prob : 0; - } - for (offset = offset - 1; offset >= 0; --offset) { - if (c->buf[offset].method == ANS_METHOD_RANS) { - rans_write(&c->ans, c->buf[offset].val_start, c->buf[offset].prob); - } else { - rabs_write(&c->ans, (uint8_t)c->buf[offset].val_start, - (AnsP8)c->buf[offset].prob); - } - } - c->offset = 0; - c->output_bytes += ans_write_end(&c->ans); -} diff --git a/media/libaom/src/aom_dsp/buf_ans.h b/media/libaom/src/aom_dsp/buf_ans.h deleted file mode 100644 index 985fcdf9e5..0000000000 --- a/media/libaom/src/aom_dsp/buf_ans.h +++ /dev/null @@ -1,136 +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. - */ - -#ifndef AOM_AOM_DSP_BUF_ANS_H_ -#define AOM_AOM_DSP_BUF_ANS_H_ -// Buffered forward ANS writer. -// Symbols are written to the writer in forward (decode) order and serialized -// backwards due to ANS's stack like behavior. - -#include -#include "config/aom_config.h" - -#include "aom/aom_integer.h" -#include "aom_dsp/ans.h" -#include "aom_dsp/answriter.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#define ANS_METHOD_RABS 0 -#define ANS_METHOD_RANS 1 - -struct buffered_ans_symbol { - unsigned int method : 1; // one of ANS_METHOD_RABS or ANS_METHOD_RANS - // TODO(aconverse): Should be possible to write this in terms of start for ABS - unsigned int val_start : RANS_PROB_BITS; // Boolean value for ABS - // start in symbol cycle for Rans - unsigned int prob : RANS_PROB_BITS; // Probability of this symbol -}; - -struct BufAnsCoder { - struct aom_internal_error_info *error; - struct buffered_ans_symbol *buf; - struct AnsCoder ans; - int size; - int offset; - int output_bytes; -#if ANS_MAX_SYMBOLS - int window_size; -#endif - int pos; // Dummy variable to store the output buffer after closing - uint8_t allow_update_cdf; -}; - -// Allocate a buffered ANS coder to store size symbols. -// When ANS_MAX_SYMBOLS is turned on, the size is the fixed size of each ANS -// partition. -// When ANS_MAX_SYMBOLS is turned off, size is merely an initial hint and the -// buffer will grow on demand -void aom_buf_ans_alloc(struct BufAnsCoder *c, - struct aom_internal_error_info *error); - -void aom_buf_ans_free(struct BufAnsCoder *c); - -#if !ANS_MAX_SYMBOLS -void aom_buf_ans_grow(struct BufAnsCoder *c); -#endif - -void aom_buf_ans_flush(struct BufAnsCoder *const c); - -static INLINE void buf_ans_write_init(struct BufAnsCoder *const c, - uint8_t *const output_buffer) { - c->offset = 0; - c->output_bytes = 0; - ans_write_init(&c->ans, output_buffer); -} - -static INLINE void buf_rabs_write(struct BufAnsCoder *const c, uint8_t val, - AnsP8 prob) { - assert(c->offset <= c->size); -#if !ANS_MAX_SYMBOLS - if (c->offset == c->size) { - aom_buf_ans_grow(c); - } -#endif - c->buf[c->offset].method = ANS_METHOD_RABS; - c->buf[c->offset].val_start = val; - c->buf[c->offset].prob = prob; - ++c->offset; -#if ANS_MAX_SYMBOLS - if (c->offset == c->size) aom_buf_ans_flush(c); -#endif -} - -// Buffer one symbol for encoding using rANS. -// cum_prob: The cumulative probability before this symbol (the offset of -// the symbol in the symbol cycle) -// prob: The probability of this symbol (l_s from the paper) -// RANS_PRECISION takes the place of m from the paper. -static INLINE void buf_rans_write(struct BufAnsCoder *const c, - aom_cdf_prob cum_prob, aom_cdf_prob prob) { - assert(c->offset <= c->size); -#if !ANS_MAX_SYMBOLS - if (c->offset == c->size) { - aom_buf_ans_grow(c); - } -#endif - c->buf[c->offset].method = ANS_METHOD_RANS; - c->buf[c->offset].val_start = cum_prob; - c->buf[c->offset].prob = prob; - ++c->offset; -#if ANS_MAX_SYMBOLS - if (c->offset == c->size) aom_buf_ans_flush(c); -#endif -} - -static INLINE void buf_rabs_write_bit(struct BufAnsCoder *c, int bit) { - buf_rabs_write(c, bit, 128); -} - -static INLINE void buf_rabs_write_literal(struct BufAnsCoder *c, int literal, - int bits) { - int bit; - - assert(bits < 31); - for (bit = bits - 1; bit >= 0; bit--) - buf_rabs_write_bit(c, 1 & (literal >> bit)); -} - -static INLINE int buf_ans_write_end(struct BufAnsCoder *const c) { - assert(c->offset == 0); - return c->output_bytes; -} -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus -#endif // AOM_AOM_DSP_BUF_ANS_H_ diff --git a/media/libaom/src/aom_dsp/daalaboolreader.h b/media/libaom/src/aom_dsp/daalaboolreader.h deleted file mode 100644 index 9b6ae28ddc..0000000000 --- a/media/libaom/src/aom_dsp/daalaboolreader.h +++ /dev/null @@ -1,156 +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. - */ - -#ifndef AOM_AOM_DSP_DAALABOOLREADER_H_ -#define AOM_AOM_DSP_DAALABOOLREADER_H_ - -#include "aom/aom_integer.h" -#include "aom_dsp/entdec.h" -#include "aom_dsp/prob.h" -#if CONFIG_ACCOUNTING -#include "av1/decoder/accounting.h" -#endif -#if CONFIG_BITSTREAM_DEBUG -#include -#include "aom_util/debug_util.h" -#endif // CONFIG_BITSTREAM_DEBUG - -#ifdef __cplusplus -extern "C" { -#endif - -struct daala_reader { - const uint8_t *buffer; - const uint8_t *buffer_end; - od_ec_dec ec; -#if CONFIG_ACCOUNTING - Accounting *accounting; -#endif - uint8_t allow_update_cdf; -}; - -typedef struct daala_reader daala_reader; - -int aom_daala_reader_init(daala_reader *r, const uint8_t *buffer, int size); -const uint8_t *aom_daala_reader_find_begin(daala_reader *r); -const uint8_t *aom_daala_reader_find_end(daala_reader *r); -uint32_t aom_daala_reader_tell(const daala_reader *r); -uint32_t aom_daala_reader_tell_frac(const daala_reader *r); -// Returns true if the reader has tried to decode more data from the buffer -// than was actually provided. -int aom_daala_reader_has_overflowed(const daala_reader *r); - -static INLINE int aom_daala_read(daala_reader *r, int prob) { - int bit; - int p = (0x7FFFFF - (prob << 15) + prob) >> 8; -#if CONFIG_BITSTREAM_DEBUG -/*{ - const int queue_r = bitstream_queue_get_read(); - const int frame_idx = aom_bitstream_queue_get_frame_read(); - if (frame_idx == 0 && queue_r == 0) { - fprintf(stderr, "\n *** bitstream queue at frame_idx_r %d queue_r %d\n", - frame_idx, queue_r); - } -}*/ -#endif - - bit = od_ec_decode_bool_q15(&r->ec, p); - -#if CONFIG_BITSTREAM_DEBUG - { - int i; - int ref_bit, ref_nsymbs; - aom_cdf_prob ref_cdf[16]; - const int queue_r = bitstream_queue_get_read(); - const int frame_idx = aom_bitstream_queue_get_frame_read(); - bitstream_queue_pop(&ref_bit, ref_cdf, &ref_nsymbs); - if (ref_nsymbs != 2) { - fprintf(stderr, - "\n *** [bit] nsymbs error, frame_idx_r %d nsymbs %d ref_nsymbs " - "%d queue_r %d\n", - frame_idx, 2, ref_nsymbs, queue_r); - assert(0); - } - if ((ref_nsymbs != 2) || (ref_cdf[0] != (aom_cdf_prob)p) || - (ref_cdf[1] != 32767)) { - fprintf(stderr, - "\n *** [bit] cdf error, frame_idx_r %d cdf {%d, %d} ref_cdf {%d", - frame_idx, p, 32767, ref_cdf[0]); - for (i = 1; i < ref_nsymbs; ++i) fprintf(stderr, ", %d", ref_cdf[i]); - fprintf(stderr, "} queue_r %d\n", queue_r); - assert(0); - } - if (bit != ref_bit) { - fprintf(stderr, - "\n *** [bit] symb error, frame_idx_r %d symb %d ref_symb %d " - "queue_r %d\n", - frame_idx, bit, ref_bit, queue_r); - assert(0); - } - } -#endif - - return bit; -} - -static INLINE int daala_read_symbol(daala_reader *r, const aom_cdf_prob *cdf, - int nsymbs) { - int symb; - assert(cdf != NULL); - symb = od_ec_decode_cdf_q15(&r->ec, cdf, nsymbs); - -#if CONFIG_BITSTREAM_DEBUG - { - int i; - int cdf_error = 0; - int ref_symb, ref_nsymbs; - aom_cdf_prob ref_cdf[16]; - const int queue_r = bitstream_queue_get_read(); - const int frame_idx = aom_bitstream_queue_get_frame_read(); - bitstream_queue_pop(&ref_symb, ref_cdf, &ref_nsymbs); - if (nsymbs != ref_nsymbs) { - fprintf(stderr, - "\n *** nsymbs error, frame_idx_r %d nsymbs %d ref_nsymbs %d " - "queue_r %d\n", - frame_idx, nsymbs, ref_nsymbs, queue_r); - cdf_error = 0; - assert(0); - } else { - for (i = 0; i < nsymbs; ++i) - if (cdf[i] != ref_cdf[i]) cdf_error = 1; - } - if (cdf_error) { - fprintf(stderr, "\n *** cdf error, frame_idx_r %d cdf {%d", frame_idx, - cdf[0]); - for (i = 1; i < nsymbs; ++i) fprintf(stderr, ", %d", cdf[i]); - fprintf(stderr, "} ref_cdf {%d", ref_cdf[0]); - for (i = 1; i < ref_nsymbs; ++i) fprintf(stderr, ", %d", ref_cdf[i]); - fprintf(stderr, "} queue_r %d\n", queue_r); - assert(0); - } - if (symb != ref_symb) { - fprintf( - stderr, - "\n *** symb error, frame_idx_r %d symb %d ref_symb %d queue_r %d\n", - frame_idx, symb, ref_symb, queue_r); - assert(0); - } - } -#endif - - return symb; -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // AOM_AOM_DSP_DAALABOOLREADER_H_ diff --git a/media/libaom/src/aom_dsp/daalaboolwriter.h b/media/libaom/src/aom_dsp/daalaboolwriter.h deleted file mode 100644 index 31e45797bc..0000000000 --- a/media/libaom/src/aom_dsp/daalaboolwriter.h +++ /dev/null @@ -1,78 +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. - */ - -#ifndef AOM_AOM_DSP_DAALABOOLWRITER_H_ -#define AOM_AOM_DSP_DAALABOOLWRITER_H_ - -#include - -#include "aom_dsp/entenc.h" -#include "aom_dsp/prob.h" -#if CONFIG_BITSTREAM_DEBUG -#include "aom_util/debug_util.h" -#endif // CONFIG_BITSTREAM_DEBUG - -#ifdef __cplusplus -extern "C" { -#endif - -struct daala_writer { - unsigned int pos; - uint8_t *buffer; - od_ec_enc ec; - uint8_t allow_update_cdf; -}; - -typedef struct daala_writer daala_writer; - -void aom_daala_start_encode(daala_writer *w, uint8_t *buffer); -int aom_daala_stop_encode(daala_writer *w); - -static INLINE void aom_daala_write(daala_writer *w, int bit, int prob) { - int p = (0x7FFFFF - (prob << 15) + prob) >> 8; -#if CONFIG_BITSTREAM_DEBUG - aom_cdf_prob cdf[2] = { (aom_cdf_prob)p, 32767 }; - /*int queue_r = 0; - int frame_idx_r = 0; - int queue_w = bitstream_queue_get_write(); - int frame_idx_w = aom_bitstream_queue_get_frame_writee(); - if (frame_idx_w == frame_idx_r && queue_w == queue_r) { - fprintf(stderr, "\n *** bitstream queue at frame_idx_w %d queue_w %d\n", - frame_idx_w, queue_w); - }*/ - bitstream_queue_push(bit, cdf, 2); -#endif - - od_ec_encode_bool_q15(&w->ec, bit, p); -} - -static INLINE void daala_write_symbol(daala_writer *w, int symb, - const aom_cdf_prob *cdf, int nsymbs) { -#if CONFIG_BITSTREAM_DEBUG - /*int queue_r = 0; - int frame_idx_r = 0; - int queue_w = bitstream_queue_get_write(); - int frame_idx_w = aom_bitstream_queue_get_frame_writee(); - if (frame_idx_w == frame_idx_r && queue_w == queue_r) { - fprintf(stderr, "\n *** bitstream queue at frame_idx_w %d queue_w %d\n", - frame_idx_w, queue_w); - }*/ - bitstream_queue_push(symb, cdf, nsymbs); -#endif - - od_ec_encode_cdf_q15(&w->ec, symb, cdf, nsymbs); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // AOM_AOM_DSP_DAALABOOLWRITER_H_ diff --git a/media/libaom/src/aom_dsp/fwd_txfm.c b/media/libaom/src/aom_dsp/fwd_txfm.c index 92f9cfff9b..3d30444157 100644 --- a/media/libaom/src/aom_dsp/fwd_txfm.c +++ b/media/libaom/src/aom_dsp/fwd_txfm.c @@ -13,6 +13,130 @@ #include "aom_dsp/txfm_common.h" #include "config/aom_dsp_rtcd.h" +void aom_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride) { + // The 2D transform is done with two passes which are actually pretty + // similar. In the first one, we transform the columns and transpose + // the results. In the second one, we transform the rows. To achieve that, + // as the first pass results are transposed, we transpose the columns (that + // is the transposed rows) and transpose the results (so that it goes back + // in normal/row positions). + // We need an intermediate buffer between passes. + tran_low_t intermediate[4 * 4]; + const tran_low_t *in_low = NULL; + tran_low_t *out = intermediate; + // Do the two transform/transpose passes + for (int pass = 0; pass < 2; ++pass) { + tran_high_t in_high[4]; // canbe16 + tran_high_t step[4]; // canbe16 + tran_high_t temp1, temp2; // needs32 + for (int i = 0; i < 4; ++i) { + // Load inputs. + if (pass == 0) { + in_high[0] = input[0 * stride] * 16; + in_high[1] = input[1 * stride] * 16; + in_high[2] = input[2 * stride] * 16; + in_high[3] = input[3 * stride] * 16; + if (i == 0 && in_high[0]) { + ++in_high[0]; + } + } else { + assert(in_low != NULL); + in_high[0] = in_low[0 * 4]; + in_high[1] = in_low[1 * 4]; + in_high[2] = in_low[2 * 4]; + in_high[3] = in_low[3 * 4]; + ++in_low; + } + // Transform. + step[0] = in_high[0] + in_high[3]; + step[1] = in_high[1] + in_high[2]; + step[2] = in_high[1] - in_high[2]; + step[3] = in_high[0] - in_high[3]; + temp1 = (step[0] + step[1]) * cospi_16_64; + temp2 = (step[0] - step[1]) * cospi_16_64; + out[0] = (tran_low_t)fdct_round_shift(temp1); + out[2] = (tran_low_t)fdct_round_shift(temp2); + temp1 = step[2] * cospi_24_64 + step[3] * cospi_8_64; + temp2 = -step[2] * cospi_8_64 + step[3] * cospi_24_64; + out[1] = (tran_low_t)fdct_round_shift(temp1); + out[3] = (tran_low_t)fdct_round_shift(temp2); + // Do next column (which is a transposed row in second/horizontal pass) + ++input; + out += 4; + } + // Setup in/out for next pass. + in_low = intermediate; + out = output; + } + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) + output[j + i * 4] = (output[j + i * 4] + 1) >> 2; + } +} + +void aom_fdct4x4_lp_c(const int16_t *input, int16_t *output, int stride) { + // The 2D transform is done with two passes which are actually pretty + // similar. In the first one, we transform the columns and transpose + // the results. In the second one, we transform the rows. To achieve that, + // as the first pass results are transposed, we transpose the columns (that + // is the transposed rows) and transpose the results (so that it goes back + // in normal/row positions). + // We need an intermediate buffer between passes. + int16_t intermediate[4 * 4]; + const int16_t *in_low = NULL; + int16_t *out = intermediate; + // Do the two transform/transpose passes + for (int pass = 0; pass < 2; ++pass) { + int32_t in_high[4]; // canbe16 + int32_t step[4]; // canbe16 + int32_t temp1, temp2; // needs32 + for (int i = 0; i < 4; ++i) { + // Load inputs. + if (pass == 0) { + in_high[0] = input[0 * stride] * 16; + in_high[1] = input[1 * stride] * 16; + in_high[2] = input[2 * stride] * 16; + in_high[3] = input[3 * stride] * 16; + if (i == 0 && in_high[0]) { + ++in_high[0]; + } + } else { + assert(in_low != NULL); + in_high[0] = in_low[0 * 4]; + in_high[1] = in_low[1 * 4]; + in_high[2] = in_low[2 * 4]; + in_high[3] = in_low[3 * 4]; + ++in_low; + } + // Transform. + step[0] = in_high[0] + in_high[3]; + step[1] = in_high[1] + in_high[2]; + step[2] = in_high[1] - in_high[2]; + step[3] = in_high[0] - in_high[3]; + temp1 = (step[0] + step[1]) * (int32_t)cospi_16_64; + temp2 = (step[0] - step[1]) * (int32_t)cospi_16_64; + out[0] = (int16_t)fdct_round_shift(temp1); + out[2] = (int16_t)fdct_round_shift(temp2); + temp1 = step[2] * (int32_t)cospi_24_64 + step[3] * (int32_t)cospi_8_64; + temp2 = -step[2] * (int32_t)cospi_8_64 + step[3] * (int32_t)cospi_24_64; + out[1] = (int16_t)fdct_round_shift(temp1); + out[3] = (int16_t)fdct_round_shift(temp2); + // Do next column (which is a transposed row in second/horizontal pass) + ++input; + out += 4; + } + // Setup in/out for next pass. + in_low = intermediate; + out = output; + } + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) + output[j + i * 4] = (output[j + i * 4] + 1) >> 2; + } +} + void aom_fdct8x8_c(const int16_t *input, tran_low_t *final_output, int stride) { int i, j; tran_low_t intermediate[64]; diff --git a/media/libaom/src/aom_dsp/mips/add_noise_msa.c b/media/libaom/src/aom_dsp/mips/add_noise_msa.c deleted file mode 100644 index 96d04cff0c..0000000000 --- a/media/libaom/src/aom_dsp/mips/add_noise_msa.c +++ /dev/null @@ -1,61 +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 - -#include "aom_dsp/mips/macros_msa.h" - -void aom_plane_add_noise_msa(uint8_t *start_ptr, char *noise, - char blackclamp[16], char whiteclamp[16], - char bothclamp[16], uint32_t width, - uint32_t height, int32_t pitch) { - uint32_t i, j; - - for (i = 0; i < height / 2; ++i) { - uint8_t *pos0_ptr = start_ptr + (2 * i) * pitch; - int8_t *ref0_ptr = (int8_t *)(noise + (rand() & 0xff)); - uint8_t *pos1_ptr = start_ptr + (2 * i + 1) * pitch; - int8_t *ref1_ptr = (int8_t *)(noise + (rand() & 0xff)); - for (j = width / 16; j--;) { - v16i8 temp00_s, temp01_s; - v16u8 temp00, temp01, black_clamp, white_clamp; - v16u8 pos0, ref0, pos1, ref1; - v16i8 const127 = __msa_ldi_b(127); - - pos0 = LD_UB(pos0_ptr); - ref0 = LD_UB(ref0_ptr); - pos1 = LD_UB(pos1_ptr); - ref1 = LD_UB(ref1_ptr); - black_clamp = (v16u8)__msa_fill_b(blackclamp[0]); - white_clamp = (v16u8)__msa_fill_b(whiteclamp[0]); - temp00 = (pos0 < black_clamp); - pos0 = __msa_bmnz_v(pos0, black_clamp, temp00); - temp01 = (pos1 < black_clamp); - pos1 = __msa_bmnz_v(pos1, black_clamp, temp01); - XORI_B2_128_UB(pos0, pos1); - temp00_s = __msa_adds_s_b((v16i8)white_clamp, const127); - temp00 = (v16u8)(temp00_s < pos0); - pos0 = (v16u8)__msa_bmnz_v((v16u8)pos0, (v16u8)temp00_s, temp00); - temp01_s = __msa_adds_s_b((v16i8)white_clamp, const127); - temp01 = (temp01_s < pos1); - pos1 = (v16u8)__msa_bmnz_v((v16u8)pos1, (v16u8)temp01_s, temp01); - XORI_B2_128_UB(pos0, pos1); - pos0 += ref0; - ST_UB(pos0, pos0_ptr); - pos1 += ref1; - ST_UB(pos1, pos1_ptr); - pos0_ptr += 16; - pos1_ptr += 16; - ref0_ptr += 16; - ref1_ptr += 16; - } - } -} diff --git a/media/libaom/src/aom_dsp/mips/aom_convolve8_horiz_msa.c b/media/libaom/src/aom_dsp/mips/aom_convolve8_horiz_msa.c index 363fad308d..c8ab61249a 100644 --- a/media/libaom/src/aom_dsp/mips/aom_convolve8_horiz_msa.c +++ b/media/libaom/src/aom_dsp/mips/aom_convolve8_horiz_msa.c @@ -446,7 +446,6 @@ static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, FILTER_BITS); LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); ST8x4_UB(out0, out1, dst, dst_stride); diff --git a/media/libaom/src/aom_dsp/mips/aom_convolve8_vert_msa.c b/media/libaom/src/aom_dsp/mips/aom_convolve8_vert_msa.c index aa962b41f7..2c3bc084cc 100644 --- a/media/libaom/src/aom_dsp/mips/aom_convolve8_vert_msa.c +++ b/media/libaom/src/aom_dsp/mips/aom_convolve8_vert_msa.c @@ -313,7 +313,6 @@ static void common_vt_2t_4x4_msa(const uint8_t *src, int32_t src_stride, filt0 = (v16u8)__msa_splati_h(filt, 0); LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); @@ -341,7 +340,6 @@ static void common_vt_2t_4x8_msa(const uint8_t *src, int32_t src_stride, src += (8 * src_stride); src8 = LD_SB(src); - src += src_stride; ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); diff --git a/media/libaom/src/aom_dsp/noise_model.c b/media/libaom/src/aom_dsp/noise_model.c index 528efd94b1..c7a0003a80 100644 --- a/media/libaom/src/aom_dsp/noise_model.c +++ b/media/libaom/src/aom_dsp/noise_model.c @@ -636,10 +636,12 @@ int aom_flat_block_finder_run(const aom_flat_block_finder_t *block_finder, // [{var}, {ratio}, {trace}, {norm}, offset] // with one of the most discriminative being simply the variance. const double weights[5] = { -6682, -0.2056, 13087, -12434, 2.5694 }; - const float score = - (float)(1.0 / (1 + exp(-(weights[0] * var + weights[1] * ratio + - weights[2] * trace + weights[3] * norm + - weights[4])))); + double sum_weights = weights[0] * var + weights[1] * ratio + + weights[2] * trace + weights[3] * norm + + weights[4]; + // clamp the value to [-25.0, 100.0] to prevent overflow + sum_weights = fclamp(sum_weights, -25.0, 100.0); + const float score = (float)(1.0 / (1 + exp(-sum_weights))); flat_blocks[by * num_blocks_w + bx] = is_flat ? 255 : 0; scores[by * num_blocks_w + bx].score = var > kVarThreshold ? score : 0; scores[by * num_blocks_w + bx].index = by * num_blocks_w + bx; diff --git a/media/libaom/src/aom_dsp/postproc.h b/media/libaom/src/aom_dsp/postproc.h deleted file mode 100644 index f3d87f2642..0000000000 --- a/media/libaom/src/aom_dsp/postproc.h +++ /dev/null @@ -1,26 +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. - */ - -#ifndef AOM_AOM_DSP_POSTPROC_H_ -#define AOM_AOM_DSP_POSTPROC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// Fills a noise buffer with gaussian noise strength determined by sigma. -int aom_setup_noise(double sigma, int size, char *noise); - -#ifdef __cplusplus -} -#endif - -#endif // AOM_AOM_DSP_POSTPROC_H_ diff --git a/media/libaom/src/aom_dsp/prob.h b/media/libaom/src/aom_dsp/prob.h index 20ffdeaeaf..ea5e4cb34e 100644 --- a/media/libaom/src/aom_dsp/prob.h +++ b/media/libaom/src/aom_dsp/prob.h @@ -26,7 +26,6 @@ extern "C" { #endif -// TODO(negge): Rename this aom_prob once we remove vpxbool. typedef uint16_t aom_cdf_prob; #define CDF_SIZE(x) ((x) + 1) diff --git a/media/libaom/src/aom_dsp/psnr.c b/media/libaom/src/aom_dsp/psnr.c index 7f5a36137b..c66dd52d05 100644 --- a/media/libaom/src/aom_dsp/psnr.c +++ b/media/libaom/src/aom_dsp/psnr.c @@ -26,9 +26,6 @@ double aom_sse_to_psnr(double samples, double peak, double sse) { } } -/* TODO(yaowu): The block_variance calls the unoptimized versions of variance() - * and highbd_8_variance(). It should not. - */ static void encoder_variance(const uint8_t *a, int a_stride, const uint8_t *b, int b_stride, int w, int h, unsigned int *sse, int *sum) { @@ -179,6 +176,27 @@ static int64_t highbd_get_sse(const uint8_t *a, int a_stride, const uint8_t *b, } #endif // CONFIG_AV1_HIGHBITDEPTH +uint64_t aom_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height) { + return aom_var_2d_u8(a->y_buffer + vstart * a->y_stride + hstart, a->y_stride, + width, height) / + (width * height); +} + +uint64_t aom_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height) { + return aom_var_2d_u8(a->u_buffer + vstart * a->uv_stride + hstart, + a->uv_stride, width, height) / + (width * height); +} + +uint64_t aom_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height) { + return aom_var_2d_u8(a->v_buffer + vstart * a->uv_stride + hstart, + a->uv_stride, width, height) / + (width * height); +} + int64_t aom_get_y_sse_part(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int hstart, int width, int vstart, int height) { @@ -231,6 +249,27 @@ int64_t aom_get_v_sse(const YV12_BUFFER_CONFIG *a, } #if CONFIG_AV1_HIGHBITDEPTH +uint64_t aom_highbd_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height) { + return aom_var_2d_u16(a->y_buffer + vstart * a->y_stride + hstart, + a->y_stride, width, height) / + (width * height); +} + +uint64_t aom_highbd_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height) { + return aom_var_2d_u16(a->u_buffer + vstart * a->uv_stride + hstart, + a->uv_stride, width, height) / + (width * height); +} + +uint64_t aom_highbd_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height) { + return aom_var_2d_u16(a->v_buffer + vstart * a->uv_stride + hstart, + a->uv_stride, width, height) / + (width * height); +} + int64_t aom_highbd_get_y_sse_part(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int hstart, int width, int vstart, int height) { diff --git a/media/libaom/src/aom_dsp/psnr.h b/media/libaom/src/aom_dsp/psnr.h index 99aa54c549..7f40b8b575 100644 --- a/media/libaom/src/aom_dsp/psnr.h +++ b/media/libaom/src/aom_dsp/psnr.h @@ -35,6 +35,12 @@ typedef struct { * \param[in] sse Sum of squared errors */ double aom_sse_to_psnr(double samples, double peak, double sse); +uint64_t aom_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height); +uint64_t aom_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height); +uint64_t aom_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart, int width, + int vstart, int height); int64_t aom_get_y_sse_part(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int hstart, int width, int vstart, int height); @@ -50,6 +56,12 @@ int64_t aom_get_v_sse(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b); int64_t aom_get_sse_plane(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int plane, int highbd); #if CONFIG_AV1_HIGHBITDEPTH +uint64_t aom_highbd_get_y_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height); +uint64_t aom_highbd_get_u_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height); +uint64_t aom_highbd_get_v_var(const YV12_BUFFER_CONFIG *a, int hstart, + int width, int vstart, int height); int64_t aom_highbd_get_y_sse_part(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int hstart, int width, int vstart, int height); diff --git a/media/libaom/src/aom_dsp/psnrhvs.c b/media/libaom/src/aom_dsp/psnrhvs.c index c6ff70ac32..69a1d99bf2 100644 --- a/media/libaom/src/aom_dsp/psnrhvs.c +++ b/media/libaom/src/aom_dsp/psnrhvs.c @@ -102,13 +102,8 @@ static const double csf_cr420[8][8] = { 0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658 } }; -static double convert_score_db(double _score, double _weight, int bit_depth) { - int16_t pix_max = 255; +static double convert_score_db(double _score, double _weight, int16_t pix_max) { assert(_score * _weight >= 0.0); - if (bit_depth == 10) - pix_max = 1023; - else if (bit_depth == 12) - pix_max = 4095; if (_weight * _score < pix_max * pix_max * 1e-10) return MAX_PSNR; return 10 * (log10(pix_max * pix_max) - log10(_weight * _score)); @@ -117,7 +112,8 @@ static double convert_score_db(double _score, double _weight, int bit_depth) { static double calc_psnrhvs(const unsigned char *src, int _systride, const unsigned char *dst, int _dystride, double _par, int _w, int _h, int _step, const double _csf[8][8], - uint32_t _shift, int buf_is_hbd) { + uint32_t _shift, int buf_is_hbd, int16_t pix_max, + int luma) { double ret; const uint8_t *_src8 = src; const uint8_t *_dst8 = dst; @@ -148,7 +144,7 @@ static double calc_psnrhvs(const unsigned char *src, int _systride, } } } - delt = (sum1 - sum2) / (_w * _h); + if (luma) delt = (sum1 - sum2) / (_w * _h); /*In the PSNR-HVS-M paper[1] the authors describe the construction of their masking table as "we have used the quantization table for the color component Y of JPEG [6] that has been also obtained on the @@ -177,21 +173,15 @@ static double calc_psnrhvs(const unsigned char *src, int _systride, for (x = 0; x < _w - 7; x += _step) { int i; int j; - double s_means[4]; - double d_means[4]; - double s_vars[4]; - double d_vars[4]; + int n = 0; + double s_gx = 0; + double s_gy = 0; + double g = 0; double s_gmean = 0; - double d_gmean = 0; double s_gvar = 0; - double d_gvar = 0; double s_mask = 0; - double d_mask = 0; - for (i = 0; i < 4; i++) - s_means[i] = d_means[i] = s_vars[i] = d_vars[i] = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { - int sub = ((i & 12) >> 2) + ((j & 12) >> 1); if (!buf_is_hbd) { dct_s[i * 8 + j] = _src8[(y + i) * _systride + (j + x)]; dct_d[i * 8 + j] = _dst8[(y + i) * _dystride + (j + x)]; @@ -200,35 +190,26 @@ static double calc_psnrhvs(const unsigned char *src, int _systride, dct_d[i * 8 + j] = _dst16[(y + i) * _dystride + (j + x)] >> _shift; } dct_d[i * 8 + j] += (int)(delt + 0.5f); - s_gmean += dct_s[i * 8 + j]; - d_gmean += dct_d[i * 8 + j]; - s_means[sub] += dct_s[i * 8 + j]; - d_means[sub] += dct_d[i * 8 + j]; } } - s_gmean /= 64.f; - d_gmean /= 64.f; - for (i = 0; i < 4; i++) s_means[i] /= 16.f; - for (i = 0; i < 4; i++) d_means[i] /= 16.f; - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - int sub = ((i & 12) >> 2) + ((j & 12) >> 1); - s_gvar += (dct_s[i * 8 + j] - s_gmean) * (dct_s[i * 8 + j] - s_gmean); - d_gvar += (dct_d[i * 8 + j] - d_gmean) * (dct_d[i * 8 + j] - d_gmean); - s_vars[sub] += (dct_s[i * 8 + j] - s_means[sub]) * - (dct_s[i * 8 + j] - s_means[sub]); - d_vars[sub] += (dct_d[i * 8 + j] - d_means[sub]) * - (dct_d[i * 8 + j] - d_means[sub]); + for (i = 1; i < 7; i++) { + for (j = 1; j < 7; j++) { + s_gx = (dct_s[(i - 1) * 8 + j - 1] * 3 - + dct_s[(i - 1) * 8 + j + 1] * 3 + dct_s[i * 8 + j - 1] * 10 - + dct_s[i * 8 + j + 1] * 10 + dct_s[(i + 1) * 8 + j - 1] * 3 - + dct_s[(i + 1) * 8 + j + 1] * 3) / + (pix_max * 16.f); + s_gy = (dct_s[(i - 1) * 8 + j - 1] * 3 - + dct_s[(i + 1) * 8 + j - 1] * 3 + dct_s[(i - 1) * 8 + j] * 10 - + dct_s[(i + 1) * 8 + j] * 10 + dct_s[(i - 1) * 8 + j + 1] * 3 - + dct_s[(i + 1) * 8 + j + 1] * 3) / + (pix_max * 16.f); + g = sqrt(s_gx * s_gx + s_gy * s_gy); + if (g > 0.1f) n++; + s_gmean += g; } } - s_gvar *= 1 / 63.f * 64; - d_gvar *= 1 / 63.f * 64; - for (i = 0; i < 4; i++) s_vars[i] *= 1 / 15.f * 16; - for (i = 0; i < 4; i++) d_vars[i] *= 1 / 15.f * 16; - if (s_gvar > 0) - s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar; - if (d_gvar > 0) - d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar; + s_gvar = 1.f / (36 - n + 1) * s_gmean / 36.f; if (!buf_is_hbd) { od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8); od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8); @@ -239,12 +220,7 @@ static double calc_psnrhvs(const unsigned char *src, int _systride, for (i = 0; i < 8; i++) for (j = (i == 0); j < 8; j++) s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j]; - for (i = 0; i < 8; i++) - for (j = (i == 0); j < 8; j++) - d_mask += dct_d_coef[i * 8 + j] * dct_d_coef[i * 8 + j] * mask[i][j]; - s_mask = sqrt(s_mask * s_gvar) / 32.f; - d_mask = sqrt(d_mask * d_gvar) / 32.f; - if (d_mask > s_mask) s_mask = d_mask; + s_mask = sqrt(s_mask * s_gvar) / 8.f; for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { double err; @@ -276,19 +252,26 @@ double aom_psnrhvs(const YV12_BUFFER_CONFIG *src, const YV12_BUFFER_CONFIG *dst, assert(src->flags == dst->flags); const int buf_is_hbd = src->flags & YV12_FLAG_HIGHBITDEPTH; + int16_t pix_max = 255; + if (in_bd == 10) + pix_max = 1023; + else if (in_bd == 12) + pix_max = 4095; + bd_shift = bd - in_bd; - *y_psnrhvs = calc_psnrhvs( - src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, par, - src->y_crop_width, src->y_crop_height, step, csf_y, bd_shift, buf_is_hbd); + *y_psnrhvs = + calc_psnrhvs(src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, + par, src->y_crop_width, src->y_crop_height, step, csf_y, + bd_shift, buf_is_hbd, pix_max, 1); *u_psnrhvs = calc_psnrhvs(src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride, par, src->uv_crop_width, src->uv_crop_height, step, - csf_cb420, bd_shift, buf_is_hbd); + csf_cb420, bd_shift, buf_is_hbd, pix_max, 0); *v_psnrhvs = calc_psnrhvs(src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride, par, src->uv_crop_width, src->uv_crop_height, step, - csf_cr420, bd_shift, buf_is_hbd); + csf_cr420, bd_shift, buf_is_hbd, pix_max, 0); psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs)); - return convert_score_db(psnrhvs, 1.0, in_bd); + return convert_score_db(psnrhvs, 1.0, pix_max); } diff --git a/media/libaom/src/aom_dsp/quantize.c b/media/libaom/src/aom_dsp/quantize.c index de916ae970..edd4d96480 100644 --- a/media/libaom/src/aom_dsp/quantize.c +++ b/media/libaom/src/aom_dsp/quantize.c @@ -54,7 +54,7 @@ void aom_quantize_b_adaptive_helper_c( for (i = 0; i < non_zero_count; i++) { const int rc = scan[i]; const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int tmp32; @@ -140,7 +140,7 @@ void aom_quantize_b_helper_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, for (i = 0; i < non_zero_count; i++) { const int rc = scan[i]; const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int tmp32; @@ -209,7 +209,7 @@ void aom_highbd_quantize_b_adaptive_helper_c( for (i = 0; i < non_zero_count; i++) { const int rc = scan[i]; const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; if (abs_coeff * wt >= (zbins[rc != 0] << AOM_QM_BITS)) { @@ -292,7 +292,7 @@ void aom_highbd_quantize_b_helper_c( for (i = 0; i < idx; i++) { const int rc = scan[idx_arr[i]]; const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS); const qm_val_t iwt = iqm_ptr != NULL ? iqm_ptr[rc] : (1 << AOM_QM_BITS); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; diff --git a/media/libaom/src/aom_dsp/sad.c b/media/libaom/src/aom_dsp/sad.c index 166a17a26a..8ddc683d6f 100644 --- a/media/libaom/src/aom_dsp/sad.c +++ b/media/libaom/src/aom_dsp/sad.c @@ -64,15 +64,24 @@ static INLINE unsigned int sad(const uint8_t *a, int a_stride, const uint8_t *b, } // Calculate sad against 4 reference locations and store each in sad_array -#define sadMxNx4D(m, n) \ - void aom_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride, \ - const uint8_t *const ref_array[], \ - int ref_stride, uint32_t *sad_array) { \ - int i; \ - for (i = 0; i < 4; ++i) { \ - sad_array[i] = \ - aom_sad##m##x##n##_c(src, src_stride, ref_array[i], ref_stride); \ - } \ +#define sadMxNx4D(m, n) \ + void aom_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride, \ + const uint8_t *const ref_array[], \ + int ref_stride, uint32_t *sad_array) { \ + int i; \ + for (i = 0; i < 4; ++i) { \ + sad_array[i] = \ + aom_sad##m##x##n##_c(src, src_stride, ref_array[i], ref_stride); \ + } \ + } \ + void aom_sad##m##x##n##x4d_avg_c( \ + const uint8_t *src, int src_stride, const uint8_t *const ref_array[], \ + int ref_stride, const uint8_t *second_pred, uint32_t *sad_array) { \ + int i; \ + for (i = 0; i < 4; ++i) { \ + sad_array[i] = aom_sad##m##x##n##_avg_c(src, src_stride, ref_array[i], \ + ref_stride, second_pred); \ + } \ } // 128x128 diff --git a/media/libaom/src/aom_dsp/sad_av1.c b/media/libaom/src/aom_dsp/sad_av1.c index 10c6ac75ac..467518163b 100644 --- a/media/libaom/src/aom_dsp/sad_av1.c +++ b/media/libaom/src/aom_dsp/sad_av1.c @@ -35,7 +35,6 @@ static INLINE unsigned int masked_sad(const uint8_t *src, int src_stride, b += b_stride; m += m_stride; } - sad = (sad + 31) >> 6; return sad; } @@ -50,6 +49,21 @@ static INLINE unsigned int masked_sad(const uint8_t *src, int src_stride, else \ return masked_sad(src, src_stride, second_pred, m, ref, ref_stride, msk, \ msk_stride, m, n); \ + } \ + void aom_masked_sad##m##x##n##x4d_c( \ + const uint8_t *src, int src_stride, const uint8_t *ref[], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int invert_mask, unsigned sads[]) { \ + if (!invert_mask) \ + for (int i = 0; i < 4; i++) { \ + sads[i] = masked_sad(src, src_stride, ref[i], ref_stride, second_pred, \ + m, msk, msk_stride, m, n); \ + } \ + else \ + for (int i = 0; i < 4; i++) { \ + sads[i] = masked_sad(src, src_stride, second_pred, m, ref[i], \ + ref_stride, msk, msk_stride, m, n); \ + } \ } /* clang-format off */ @@ -101,7 +115,6 @@ MASKSADMxN(64, 16) b += b_stride; m += m_stride; } - sad = (sad + 31) >> 6; return sad; } diff --git a/media/libaom/src/aom_dsp/simd/v128_intrinsics.h b/media/libaom/src/aom_dsp/simd/v128_intrinsics.h index 01dbb8fd27..218a7a6186 100644 --- a/media/libaom/src/aom_dsp/simd/v128_intrinsics.h +++ b/media/libaom/src/aom_dsp/simd/v128_intrinsics.h @@ -54,26 +54,28 @@ SIMD_INLINE v128 v128_align(v128 a, v128 b, unsigned int c) { return c_v128_align(a, b, c); } -SIMD_INLINE v128 v128_zero() { return c_v128_zero(); } +SIMD_INLINE v128 v128_zero(void) { return c_v128_zero(); } SIMD_INLINE v128 v128_dup_8(uint8_t x) { return c_v128_dup_8(x); } SIMD_INLINE v128 v128_dup_16(uint16_t x) { return c_v128_dup_16(x); } SIMD_INLINE v128 v128_dup_32(uint32_t x) { return c_v128_dup_32(x); } SIMD_INLINE v128 v128_dup_64(uint64_t x) { return c_v128_dup_64(x); } -typedef uint32_t sad128_internal; -SIMD_INLINE sad128_internal v128_sad_u8_init() { return c_v128_sad_u8_init(); } -SIMD_INLINE sad128_internal v128_sad_u8(sad128_internal s, v128 a, v128 b) { +SIMD_INLINE c_sad128_internal v128_sad_u8_init(void) { + return c_v128_sad_u8_init(); +} +SIMD_INLINE c_sad128_internal v128_sad_u8(c_sad128_internal s, v128 a, v128 b) { return c_v128_sad_u8(s, a, b); } -SIMD_INLINE uint32_t v128_sad_u8_sum(sad128_internal s) { +SIMD_INLINE uint32_t v128_sad_u8_sum(c_sad128_internal s) { return c_v128_sad_u8_sum(s); } -typedef uint32_t ssd128_internal; -SIMD_INLINE ssd128_internal v128_ssd_u8_init() { return c_v128_ssd_u8_init(); } -SIMD_INLINE ssd128_internal v128_ssd_u8(ssd128_internal s, v128 a, v128 b) { +SIMD_INLINE c_ssd128_internal v128_ssd_u8_init(void) { + return c_v128_ssd_u8_init(); +} +SIMD_INLINE c_ssd128_internal v128_ssd_u8(c_ssd128_internal s, v128 a, v128 b) { return c_v128_ssd_u8(s, a, b); } -SIMD_INLINE uint32_t v128_ssd_u8_sum(ssd128_internal s) { +SIMD_INLINE uint32_t v128_ssd_u8_sum(c_ssd128_internal s) { return c_v128_ssd_u8_sum(s); } SIMD_INLINE int64_t v128_dotp_su8(v128 a, v128 b) { @@ -318,7 +320,7 @@ SIMD_INLINE v128 v128_shr_n_s64(v128 a, unsigned int n) { } typedef uint32_t sad128_internal_u16; -SIMD_INLINE sad128_internal_u16 v128_sad_u16_init() { +SIMD_INLINE sad128_internal_u16 v128_sad_u16_init(void) { return c_v128_sad_u16_init(); } SIMD_INLINE sad128_internal_u16 v128_sad_u16(sad128_internal_u16 s, v128 a, @@ -330,7 +332,7 @@ SIMD_INLINE uint32_t v128_sad_u16_sum(sad128_internal_u16 s) { } typedef uint64_t ssd128_internal_s16; -SIMD_INLINE ssd128_internal_s16 v128_ssd_s16_init() { +SIMD_INLINE ssd128_internal_s16 v128_ssd_s16_init(void) { return c_v128_ssd_s16_init(); } SIMD_INLINE ssd128_internal_s16 v128_ssd_s16(ssd128_internal_s16 s, v128 a, diff --git a/media/libaom/src/aom_dsp/simd/v128_intrinsics_arm.h b/media/libaom/src/aom_dsp/simd/v128_intrinsics_arm.h index 3c669d5792..2d497f4c0e 100644 --- a/media/libaom/src/aom_dsp/simd/v128_intrinsics_arm.h +++ b/media/libaom/src/aom_dsp/simd/v128_intrinsics_arm.h @@ -68,9 +68,11 @@ SIMD_INLINE v128 v128_align(v128 a, v128 b, unsigned int c) { #endif } -SIMD_INLINE v128 v128_zero() { return vreinterpretq_s64_u8(vdupq_n_u8(0)); } +SIMD_INLINE v128 v128_zero(void) { return vreinterpretq_s64_u8(vdupq_n_u8(0)); } -SIMD_INLINE v128 v128_ones() { return vreinterpretq_s64_u8(vdupq_n_u8(-1)); } +SIMD_INLINE v128 v128_ones(void) { + return vreinterpretq_s64_u8(vdupq_n_u8(-1)); +} SIMD_INLINE v128 v128_dup_8(uint8_t x) { return vreinterpretq_s64_u8(vdupq_n_u8(x)); @@ -136,7 +138,7 @@ typedef struct { sad64_internal hi, lo; } sad128_internal; -SIMD_INLINE sad128_internal v128_sad_u8_init() { +SIMD_INLINE sad128_internal v128_sad_u8_init(void) { sad128_internal s; s.hi = s.lo = vdupq_n_u16(0); return s; @@ -165,7 +167,7 @@ typedef struct { ssd64_internal hi, lo; } ssd128_internal; -SIMD_INLINE ssd128_internal v128_ssd_u8_init() { +SIMD_INLINE ssd128_internal v128_ssd_u8_init(void) { ssd128_internal s; s.hi = s.lo = v64_ssd_u8_init(); return s; @@ -784,68 +786,79 @@ SIMD_INLINE v128 v128_shl_n_byte(v128 a, unsigned int n) { } SIMD_INLINE v128 v128_shr_n_byte(v128 a, unsigned int n) { - return n < 8 - ? v128_from_64( - (uint64_t)vshr_n_u64(vreinterpret_u64_s64(vget_high_s64(a)), - n * 8), - (uint64_t)vorr_u64( - vshr_n_u64(vreinterpret_u64_s64(vget_low_s64(a)), n * 8), - vshl_n_u64(vreinterpret_u64_s64(vget_high_s64(a)), - (8 - n) * 8))) - : (n == 8 ? v128_from_64(0, (uint64_t)vreinterpret_u64_s64( - vget_high_s64(a))) - : v128_from_64( - 0, (uint64_t)vshr_n_u64( - vreinterpret_u64_s64(vget_high_s64(a)), - (n - 8) * 8))); + return n == 0 + ? a + : (n < 8 + ? v128_from_64( + (uint64_t)vshr_n_u64( + vreinterpret_u64_s64(vget_high_s64(a)), n * 8), + (uint64_t)vorr_u64( + vshr_n_u64(vreinterpret_u64_s64(vget_low_s64(a)), + n * 8), + vshl_n_u64(vreinterpret_u64_s64(vget_high_s64(a)), + (8 - n) * 8))) + : (n == 8 ? v128_from_64(0, (uint64_t)vreinterpret_u64_s64( + vget_high_s64(a))) + : v128_from_64(0, (uint64_t)vshr_n_u64( + vreinterpret_u64_s64( + vget_high_s64(a)), + (n - 8) * 8)))); } SIMD_INLINE v128 v128_shl_n_8(v128 a, unsigned int c) { - return vreinterpretq_s64_u8(vshlq_n_u8(vreinterpretq_u8_s64(a), c)); + return c ? vreinterpretq_s64_u8(vshlq_n_u8(vreinterpretq_u8_s64(a), c)) : a; } SIMD_INLINE v128 v128_shr_n_u8(v128 a, unsigned int c) { - return vreinterpretq_s64_u8(vshrq_n_u8(vreinterpretq_u8_s64(a), c)); + return c ? vreinterpretq_s64_u8(vshrq_n_u8(vreinterpretq_u8_s64(a), c)) : a; } SIMD_INLINE v128 v128_shr_n_s8(v128 a, unsigned int c) { - return vreinterpretq_s64_s8(vshrq_n_s8(vreinterpretq_s8_s64(a), c)); + return c ? vreinterpretq_s64_s8(vshrq_n_s8(vreinterpretq_s8_s64(a), c)) : a; } SIMD_INLINE v128 v128_shl_n_16(v128 a, unsigned int c) { - return vreinterpretq_s64_u16(vshlq_n_u16(vreinterpretq_u16_s64(a), c)); + return c ? vreinterpretq_s64_u16(vshlq_n_u16(vreinterpretq_u16_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_u16(v128 a, unsigned int c) { - return vreinterpretq_s64_u16(vshrq_n_u16(vreinterpretq_u16_s64(a), c)); + return c ? vreinterpretq_s64_u16(vshrq_n_u16(vreinterpretq_u16_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_s16(v128 a, unsigned int c) { - return vreinterpretq_s64_s16(vshrq_n_s16(vreinterpretq_s16_s64(a), c)); + return c ? vreinterpretq_s64_s16(vshrq_n_s16(vreinterpretq_s16_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shl_n_32(v128 a, unsigned int c) { - return vreinterpretq_s64_u32(vshlq_n_u32(vreinterpretq_u32_s64(a), c)); + return c ? vreinterpretq_s64_u32(vshlq_n_u32(vreinterpretq_u32_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_u32(v128 a, unsigned int c) { - return vreinterpretq_s64_u32(vshrq_n_u32(vreinterpretq_u32_s64(a), c)); + return c ? vreinterpretq_s64_u32(vshrq_n_u32(vreinterpretq_u32_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_s32(v128 a, unsigned int c) { - return vreinterpretq_s64_s32(vshrq_n_s32(vreinterpretq_s32_s64(a), c)); + return c ? vreinterpretq_s64_s32(vshrq_n_s32(vreinterpretq_s32_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shl_n_64(v128 a, unsigned int c) { - return vreinterpretq_s64_u64(vshlq_n_u64(vreinterpretq_u64_s64(a), c)); + return c ? vreinterpretq_s64_u64(vshlq_n_u64(vreinterpretq_u64_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_u64(v128 a, unsigned int c) { - return vreinterpretq_s64_u64(vshrq_n_u64(vreinterpretq_u64_s64(a), c)); + return c ? vreinterpretq_s64_u64(vshrq_n_u64(vreinterpretq_u64_s64(a), c)) + : a; } SIMD_INLINE v128 v128_shr_n_s64(v128 a, unsigned int c) { - return vshrq_n_s64(a, c); + return c ? vshrq_n_s64(a, c) : a; } #else @@ -920,7 +933,9 @@ SIMD_INLINE v128 v128_shr_n_s64(v128 a, unsigned int c) { typedef uint32x4_t sad128_internal_u16; -SIMD_INLINE sad128_internal_u16 v128_sad_u16_init() { return vdupq_n_u32(0); } +SIMD_INLINE sad128_internal_u16 v128_sad_u16_init(void) { + return vdupq_n_u32(0); +} /* Implementation dependent return value. Result must be finalised with * v128_sad_u16_sum(). */ @@ -939,7 +954,7 @@ SIMD_INLINE uint32_t v128_sad_u16_sum(sad128_internal_u16 s) { } typedef v128 ssd128_internal_s16; -SIMD_INLINE ssd128_internal_s16 v128_ssd_s16_init() { return v128_zero(); } +SIMD_INLINE ssd128_internal_s16 v128_ssd_s16_init(void) { return v128_zero(); } /* Implementation dependent return value. Result must be finalised with * v128_ssd_s16_sum(). */ diff --git a/media/libaom/src/aom_dsp/simd/v128_intrinsics_c.h b/media/libaom/src/aom_dsp/simd/v128_intrinsics_c.h index bbe9a9d281..466a41e107 100644 --- a/media/libaom/src/aom_dsp/simd/v128_intrinsics_c.h +++ b/media/libaom/src/aom_dsp/simd/v128_intrinsics_c.h @@ -93,7 +93,7 @@ SIMD_INLINE void c_v128_store_aligned(void *p, c_v128 a) { c_v128_store_unaligned(p, a); } -SIMD_INLINE c_v128 c_v128_zero() { +SIMD_INLINE c_v128 c_v128_zero(void) { c_v128 t; t.u64[1] = t.u64[0] = 0; return t; @@ -145,26 +145,39 @@ SIMD_INLINE uint64_t c_v128_hadd_u8(c_v128 a) { return c_v64_hadd_u8(a.v64[1]) + c_v64_hadd_u8(a.v64[0]); } -typedef uint32_t c_sad128_internal; +typedef struct { + uint32_t val; + int count; +} c_sad128_internal; -SIMD_INLINE c_sad128_internal c_v128_sad_u8_init() { return 0; } +SIMD_INLINE c_sad128_internal c_v128_sad_u8_init(void) { + c_sad128_internal t; + t.val = t.count = 0; + return t; +} /* Implementation dependent return value. Result must be finalised with - v128_sad_u8_sum(). - The result for more than 32 v128_sad_u8() calls is undefined. */ + * v128_sad_u8_sum(). The result for more than 32 v128_sad_u8() calls is + * undefined. */ SIMD_INLINE c_sad128_internal c_v128_sad_u8(c_sad128_internal s, c_v128 a, c_v128 b) { int c; for (c = 0; c < 16; c++) - s += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.val += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.count++; + if (SIMD_CHECK && s.count > 32) { + fprintf(stderr, + "Error: sad called 32 times returning an undefined result\n"); + abort(); + } return s; } -SIMD_INLINE uint32_t c_v128_sad_u8_sum(c_sad128_internal s) { return s; } +SIMD_INLINE uint32_t c_v128_sad_u8_sum(c_sad128_internal s) { return s.val; } typedef uint32_t c_ssd128_internal; -SIMD_INLINE c_ssd128_internal c_v128_ssd_u8_init() { return 0; } +SIMD_INLINE c_ssd128_internal c_v128_ssd_u8_init(void) { return 0; } /* Implementation dependent return value. Result must be finalised with * v128_ssd_u8_sum(). */ @@ -720,6 +733,7 @@ SIMD_INLINE c_v128 c_v128_cmpeq_32(c_v128 a, c_v128 b) { } SIMD_INLINE c_v128 c_v128_shl_n_byte(c_v128 a, const unsigned int n) { + if (n == 0) return a; if (n < 8) return c_v128_from_v64(c_v64_or(c_v64_shl_n_byte(a.v64[1], n), c_v64_shr_n_byte(a.v64[0], 8 - n)), @@ -729,6 +743,7 @@ SIMD_INLINE c_v128 c_v128_shl_n_byte(c_v128 a, const unsigned int n) { } SIMD_INLINE c_v128 c_v128_shr_n_byte(c_v128 a, const unsigned int n) { + if (n == 0) return a; if (n < 8) return c_v128_from_v64(c_v64_shr_n_byte(a.v64[1], n), c_v64_or(c_v64_shr_n_byte(a.v64[0], n), @@ -854,7 +869,7 @@ SIMD_INLINE c_v128 c_v128_shr_n_s64(c_v128 a, const unsigned int n) { typedef uint32_t c_sad128_internal_u16; -SIMD_INLINE c_sad128_internal_u16 c_v128_sad_u16_init() { return 0; } +SIMD_INLINE c_sad128_internal_u16 c_v128_sad_u16_init(void) { return 0; } /* Implementation dependent return value. Result must be finalised with * v128_sad_u16_sum(). */ @@ -870,7 +885,7 @@ SIMD_INLINE uint32_t c_v128_sad_u16_sum(c_sad128_internal_u16 s) { return s; } typedef uint64_t c_ssd128_internal_s16; -SIMD_INLINE c_ssd128_internal_s16 c_v128_ssd_s16_init() { return 0; } +SIMD_INLINE c_ssd128_internal_s16 c_v128_ssd_s16_init(void) { return 0; } /* Implementation dependent return value. Result must be finalised with * v128_ssd_s16_sum(). */ diff --git a/media/libaom/src/aom_dsp/simd/v128_intrinsics_x86.h b/media/libaom/src/aom_dsp/simd/v128_intrinsics_x86.h index fc3e5a257b..c404015ef1 100644 --- a/media/libaom/src/aom_dsp/simd/v128_intrinsics_x86.h +++ b/media/libaom/src/aom_dsp/simd/v128_intrinsics_x86.h @@ -45,7 +45,7 @@ SIMD_INLINE v128 v128_load_aligned(const void *p) { SIMD_INLINE v128 v128_load_unaligned(const void *p) { #if defined(__SSSE3__) - return (__m128i)_mm_lddqu_si128((__m128i *)p); + return _mm_lddqu_si128((__m128i *)p); #else return _mm_loadu_si128((__m128i *)p); #endif diff --git a/media/libaom/src/aom_dsp/simd/v256_intrinsics.h b/media/libaom/src/aom_dsp/simd/v256_intrinsics.h index cb99d35b71..17e36eed61 100644 --- a/media/libaom/src/aom_dsp/simd/v256_intrinsics.h +++ b/media/libaom/src/aom_dsp/simd/v256_intrinsics.h @@ -57,29 +57,42 @@ SIMD_INLINE v256 v256_align(v256 a, v256 b, unsigned int c) { return c_v256_align(a, b, c); } -SIMD_INLINE v256 v256_zero() { return c_v256_zero(); } +SIMD_INLINE v256 v256_zero(void) { return c_v256_zero(); } SIMD_INLINE v256 v256_dup_8(uint8_t x) { return c_v256_dup_8(x); } SIMD_INLINE v256 v256_dup_16(uint16_t x) { return c_v256_dup_16(x); } SIMD_INLINE v256 v256_dup_32(uint32_t x) { return c_v256_dup_32(x); } SIMD_INLINE v256 v256_dup_64(uint64_t x) { return c_v256_dup_64(x); } -typedef uint32_t sad256_internal; -SIMD_INLINE sad256_internal v256_sad_u8_init() { return c_v256_sad_u8_init(); } -SIMD_INLINE sad256_internal v256_sad_u8(sad256_internal s, v256 a, v256 b) { +SIMD_INLINE c_sad256_internal v256_sad_u8_init(void) { + return c_v256_sad_u8_init(); +} +SIMD_INLINE c_sad256_internal v256_sad_u8(c_sad256_internal s, v256 a, v256 b) { return c_v256_sad_u8(s, a, b); } -SIMD_INLINE uint32_t v256_sad_u8_sum(sad256_internal s) { +SIMD_INLINE uint32_t v256_sad_u8_sum(c_sad256_internal s) { return c_v256_sad_u8_sum(s); } -typedef uint32_t ssd256_internal; -SIMD_INLINE ssd256_internal v256_ssd_u8_init() { return c_v256_ssd_u8_init(); } -SIMD_INLINE ssd256_internal v256_ssd_u8(ssd256_internal s, v256 a, v256 b) { +SIMD_INLINE c_ssd256_internal v256_ssd_u8_init(void) { + return c_v256_ssd_u8_init(); +} +SIMD_INLINE c_ssd256_internal v256_ssd_u8(c_ssd256_internal s, v256 a, v256 b) { return c_v256_ssd_u8(s, a, b); } -SIMD_INLINE uint32_t v256_ssd_u8_sum(ssd256_internal s) { +SIMD_INLINE uint32_t v256_ssd_u8_sum(c_ssd256_internal s) { return c_v256_ssd_u8_sum(s); } +SIMD_INLINE c_ssd256_internal_s16 v256_ssd_s16_init(void) { + return c_v256_ssd_s16_init(); +} +SIMD_INLINE c_ssd256_internal_s16 v256_ssd_s16(c_ssd256_internal_s16 s, v256 a, + v256 b) { + return c_v256_ssd_s16(s, a, b); +} +SIMD_INLINE uint64_t v256_ssd_s16_sum(c_ssd256_internal_s16 s) { + return c_v256_ssd_s16_sum(s); +} + SIMD_INLINE int64_t v256_dotp_su8(v256 a, v256 b) { return c_v256_dotp_su8(a, b); } @@ -350,7 +363,7 @@ SIMD_INLINE v256 v256_shl_n_word(v256 a, unsigned int n) { } typedef uint32_t sad256_internal_u16; -SIMD_INLINE sad256_internal_u16 v256_sad_u16_init() { +SIMD_INLINE sad256_internal_u16 v256_sad_u16_init(void) { return c_v256_sad_u16_init(); } SIMD_INLINE sad256_internal_u16 v256_sad_u16(sad256_internal_u16 s, v256 a, @@ -361,16 +374,4 @@ SIMD_INLINE uint32_t v256_sad_u16_sum(sad256_internal_u16 s) { return c_v256_sad_u16_sum(s); } -typedef uint64_t ssd256_internal_s16; -SIMD_INLINE ssd256_internal_s16 v256_ssd_s16_init() { - return c_v256_ssd_s16_init(); -} -SIMD_INLINE ssd256_internal_s16 v256_ssd_s16(ssd256_internal_s16 s, v256 a, - v256 b) { - return c_v256_ssd_s16(s, a, b); -} -SIMD_INLINE uint64_t v256_ssd_s16_sum(ssd256_internal_s16 s) { - return c_v256_ssd_s16_sum(s); -} - #endif // AOM_AOM_DSP_SIMD_V256_INTRINSICS_H_ diff --git a/media/libaom/src/aom_dsp/simd/v256_intrinsics_c.h b/media/libaom/src/aom_dsp/simd/v256_intrinsics_c.h index a1c08e95ad..8127ee3566 100644 --- a/media/libaom/src/aom_dsp/simd/v256_intrinsics_c.h +++ b/media/libaom/src/aom_dsp/simd/v256_intrinsics_c.h @@ -149,9 +149,16 @@ SIMD_INLINE uint64_t c_v256_hadd_u8(c_v256 a) { return c_v128_hadd_u8(a.v128[1]) + c_v128_hadd_u8(a.v128[0]); } -typedef uint32_t c_sad256_internal; +typedef struct { + uint32_t val; + int count; +} c_sad256_internal; -SIMD_INLINE c_sad256_internal c_v256_sad_u8_init() { return 0; } +SIMD_INLINE c_sad256_internal c_v256_sad_u8_init(void) { + c_sad256_internal t; + t.val = t.count = 0; + return t; +} /* Implementation dependent return value. Result must be finalised with v256_sad_u8_sum(). @@ -160,11 +167,17 @@ SIMD_INLINE c_sad256_internal c_v256_sad_u8(c_sad256_internal s, c_v256 a, c_v256 b) { int c; for (c = 0; c < 32; c++) - s += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.val += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.count++; + if (SIMD_CHECK && s.count > 32) { + fprintf(stderr, + "Error: sad called 32 times returning an undefined result\n"); + abort(); + } return s; } -SIMD_INLINE uint32_t c_v256_sad_u8_sum(c_sad256_internal s) { return s; } +SIMD_INLINE uint32_t c_v256_sad_u8_sum(c_sad256_internal s) { return s.val; } typedef uint32_t c_ssd256_internal; @@ -746,6 +759,7 @@ SIMD_INLINE c_v256 c_v256_cmpeq_32(c_v256 a, c_v256 b) { } SIMD_INLINE c_v256 c_v256_shl_n_byte(c_v256 a, unsigned int n) { + if (n == 0) return a; if (n < 16) return c_v256_from_v128(c_v128_or(c_v128_shl_n_byte(a.v128[1], n), c_v128_shr_n_byte(a.v128[0], 16 - n)), @@ -758,6 +772,7 @@ SIMD_INLINE c_v256 c_v256_shl_n_byte(c_v256 a, unsigned int n) { } SIMD_INLINE c_v256 c_v256_shr_n_byte(c_v256 a, unsigned int n) { + if (n == 0) return a; if (n < 16) return c_v256_from_v128(c_v128_shr_n_byte(a.v128[1], n), c_v128_or(c_v128_shr_n_byte(a.v128[0], n), diff --git a/media/libaom/src/aom_dsp/simd/v256_intrinsics_v128.h b/media/libaom/src/aom_dsp/simd/v256_intrinsics_v128.h index d5b7905eff..0d22667547 100644 --- a/media/libaom/src/aom_dsp/simd/v256_intrinsics_v128.h +++ b/media/libaom/src/aom_dsp/simd/v256_intrinsics_v128.h @@ -73,7 +73,7 @@ SIMD_INLINE void v256_store_aligned(void *p, v256 a) { v128_store_aligned((uint8_t *)p + 16, a.val[1]); } -SIMD_INLINE v256 v256_zero() { +SIMD_INLINE v256 v256_zero(void) { return v256_from_v128(v128_zero(), v128_zero()); } @@ -117,7 +117,7 @@ typedef struct { sad128_internal val[2]; } sad256_internal; -SIMD_INLINE sad256_internal v256_sad_u8_init() { +SIMD_INLINE sad256_internal v256_sad_u8_init(void) { sad256_internal t; t.val[1] = v128_sad_u8_init(); t.val[0] = v128_sad_u8_init(); @@ -142,7 +142,7 @@ typedef struct { ssd128_internal val[2]; } ssd256_internal; -SIMD_INLINE ssd256_internal v256_ssd_u8_init() { +SIMD_INLINE ssd256_internal v256_ssd_u8_init(void) { ssd256_internal t; t.val[1] = v128_ssd_u8_init(); t.val[0] = v128_ssd_u8_init(); @@ -780,13 +780,16 @@ SIMD_INLINE v256 v256_shr_s64(v256 a, const unsigned int c) { (n) > 16 ? v128_shl_n_byte(a.val[0], (n)-16) : a.val[0], \ v128_zero())) -#define v256_shr_n_byte(a, n) \ - ((n) < 16 ? v256_from_v128(v128_shr_n_byte(a.val[1], n), \ - v128_or(v128_shr_n_byte(a.val[0], n), \ - v128_shl_n_byte(a.val[1], 16 - (n)))) \ - : v256_from_v128( \ - v128_zero(), \ - (n) > 16 ? v128_shr_n_byte(a.val[1], (n)-16) : a.val[1])) +#define v256_shr_n_byte(a, n) \ + (n == 0 \ + ? a \ + : ((n) < 16 \ + ? v256_from_v128(v128_shr_n_byte(a.val[1], n), \ + v128_or(v128_shr_n_byte(a.val[0], n), \ + v128_shl_n_byte(a.val[1], 16 - (n)))) \ + : v256_from_v128( \ + v128_zero(), \ + (n) > 16 ? v128_shr_n_byte(a.val[1], (n)-16) : a.val[1]))) #define v256_align(a, b, c) \ ((c) ? v256_or(v256_shr_n_byte(b, c), v256_shl_n_byte(a, 32 - (c))) : b) @@ -823,7 +826,7 @@ typedef struct { sad128_internal_u16 val[2]; } sad256_internal_u16; -SIMD_INLINE sad256_internal_u16 v256_sad_u16_init() { +SIMD_INLINE sad256_internal_u16 v256_sad_u16_init(void) { sad256_internal_u16 t; t.val[1] = v128_sad_u16_init(); t.val[0] = v128_sad_u16_init(); @@ -849,7 +852,7 @@ typedef struct { ssd128_internal_s16 val[2]; } ssd256_internal_s16; -SIMD_INLINE ssd256_internal_s16 v256_ssd_s16_init() { +SIMD_INLINE ssd256_internal_s16 v256_ssd_s16_init(void) { ssd256_internal_s16 t; t.val[1] = v128_ssd_s16_init(); t.val[0] = v128_ssd_s16_init(); diff --git a/media/libaom/src/aom_dsp/simd/v256_intrinsics_x86.h b/media/libaom/src/aom_dsp/simd/v256_intrinsics_x86.h index 8207cbaa6f..5983cb80ce 100644 --- a/media/libaom/src/aom_dsp/simd/v256_intrinsics_x86.h +++ b/media/libaom/src/aom_dsp/simd/v256_intrinsics_x86.h @@ -57,7 +57,7 @@ SIMD_INLINE v256 v256_from_v64(v64 a, v64 b, v64 c, v64 d) { } SIMD_INLINE v256 v256_from_64(uint64_t a, uint64_t b, uint64_t c, uint64_t d) { - return v256_from_v128(v128_from_64(a, b), v128_from_64(c, d)); + return _mm256_set_epi64x(a, b, c, d); } SIMD_INLINE v256 v256_load_aligned(const void *p) { @@ -76,7 +76,7 @@ SIMD_INLINE void v256_store_unaligned(void *p, v256 a) { _mm256_storeu_si256((__m256i *)p, a); } -SIMD_INLINE v256 v256_zero() { return _mm256_setzero_si256(); } +SIMD_INLINE v256 v256_zero(void) { return _mm256_setzero_si256(); } SIMD_INLINE v256 v256_dup_8(uint8_t x) { return _mm256_set1_epi8(x); } @@ -187,11 +187,11 @@ SIMD_INLINE v256 v256_ziphi_64(v256 a, v256 b) { } SIMD_INLINE v256 v256_ziplo_128(v256 a, v256 b) { - return v256_from_v128(v256_low_v128(a), v256_low_v128(b)); + return _mm256_permute2x128_si256(a, b, 0x02); } SIMD_INLINE v256 v256_ziphi_128(v256 a, v256 b) { - return v256_from_v128(v256_high_v128(a), v256_high_v128(b)); + return _mm256_permute2x128_si256(a, b, 0x13); } SIMD_INLINE v256 v256_zip_8(v128 a, v128 b) { @@ -256,9 +256,7 @@ SIMD_INLINE v256 v256_unziplo_64(v256 a, v256 b) { _MM_SHUFFLE(3, 1, 2, 0)); } -SIMD_INLINE v256 v256_unpack_u8_s16(v128 a) { - return v256_from_v128(v128_unpackhi_u8_s16(a), v128_unpacklo_u8_s16(a)); -} +SIMD_INLINE v256 v256_unpack_u8_s16(v128 a) { return _mm256_cvtepu8_epi16(a); } SIMD_INLINE v256 v256_unpacklo_u8_s16(v256 a) { return _mm256_unpacklo_epi8( @@ -311,11 +309,11 @@ SIMD_INLINE v256 v256_pack_s16_s8(v256 a, v256 b) { } SIMD_INLINE v256 v256_unpack_u16_s32(v128 a) { - return v256_from_v128(v128_unpackhi_u16_s32(a), v128_unpacklo_u16_s32(a)); + return _mm256_cvtepu16_epi32(a); } SIMD_INLINE v256 v256_unpack_s16_s32(v128 a) { - return v256_from_v128(v128_unpackhi_s16_s32(a), v128_unpacklo_s16_s32(a)); + return _mm256_cvtepi16_epi32(a); } SIMD_INLINE v256 v256_unpacklo_u16_s32(v256 a) { @@ -442,7 +440,7 @@ SIMD_INLINE uint64_t v256_hadd_u8(v256 a) { typedef v256 sad256_internal; -SIMD_INLINE sad256_internal v256_sad_u8_init() { +SIMD_INLINE sad256_internal v256_sad_u8_init(void) { return _mm256_setzero_si256(); } @@ -460,7 +458,7 @@ SIMD_INLINE uint32_t v256_sad_u8_sum(sad256_internal s) { typedef v256 ssd256_internal; -SIMD_INLINE ssd256_internal v256_ssd_u8_init() { +SIMD_INLINE ssd256_internal v256_ssd_u8_init(void) { return _mm256_setzero_si256(); } @@ -646,7 +644,7 @@ SIMD_INLINE v256 v256_shr_u64(v256 a, unsigned int c) { } SIMD_INLINE v256 v256_shr_s64(v256 a, unsigned int c) { -#if defined(__AVX512F__) +#if defined(__AVX512VL__) return _mm256_sra_epi64(a, _mm_cvtsi32_si128(c)); #else return v256_from_v128(v128_shr_s64(v256_high_v128(a), c), @@ -670,13 +668,15 @@ SIMD_INLINE v256 v256_shr_s64(v256 a, unsigned int c) { ((n) < 16 \ ? _mm256_alignr_epi8( \ _mm256_permute2x128_si256(a, a, _MM_SHUFFLE(2, 0, 0, 1)), a, n) \ - : _mm256_inserti128_si256( \ - _mm256_setzero_si256(), \ - v128_align(v256_high_v128(a), v256_high_v128(a), n), 0)) + : ((n) == 16 \ + ? _mm256_permute2x128_si256(_mm256_setzero_si256(), a, 3) \ + : _mm256_inserti128_si256( \ + _mm256_setzero_si256(), \ + v128_align(v256_high_v128(a), v256_high_v128(a), n), 0))) // _mm256_alignr_epi8 works on two 128 bit lanes and can't be used #define v256_align(a, b, c) \ - ((c) ? v256_or(v256_shr_n_byte(b, c), v256_shl_n_byte(a, 32 - c)) : b) + ((c) ? v256_or(v256_shr_n_byte(b, c), v256_shl_n_byte(a, 32 - (c))) : b) #define v256_shl_n_8(a, c) \ _mm256_and_si256(_mm256_set1_epi8((uint8_t)(0xff << (c))), \ @@ -701,7 +701,7 @@ SIMD_INLINE v256 v256_shr_s64(v256 a, unsigned int c) { typedef v256 sad256_internal_u16; -SIMD_INLINE sad256_internal_u16 v256_sad_u16_init() { return v256_zero(); } +SIMD_INLINE sad256_internal_u16 v256_sad_u16_init(void) { return v256_zero(); } /* Implementation dependent return value. Result must be finalised with * v256_sad_u16_sum(). */ @@ -728,7 +728,7 @@ SIMD_INLINE uint32_t v256_sad_u16_sum(sad256_internal_u16 s) { typedef v256 ssd256_internal_s16; -SIMD_INLINE ssd256_internal_s16 v256_ssd_s16_init() { return v256_zero(); } +SIMD_INLINE ssd256_internal_s16 v256_ssd_s16_init(void) { return v256_zero(); } /* Implementation dependent return value. Result must be finalised with * v256_ssd_s16_sum(). */ diff --git a/media/libaom/src/aom_dsp/simd/v64_intrinsics.h b/media/libaom/src/aom_dsp/simd/v64_intrinsics.h index afc55428d8..7079949cd8 100644 --- a/media/libaom/src/aom_dsp/simd/v64_intrinsics.h +++ b/media/libaom/src/aom_dsp/simd/v64_intrinsics.h @@ -65,7 +65,7 @@ SIMD_INLINE v64 v64_align(v64 a, v64 b, unsigned int c) { return c_v64_align(a, b, c); } -SIMD_INLINE v64 v64_zero() { return c_v64_zero(); } +SIMD_INLINE v64 v64_zero(void) { return c_v64_zero(); } SIMD_INLINE v64 v64_dup_8(uint8_t x) { return c_v64_dup_8(x); } SIMD_INLINE v64 v64_dup_16(uint16_t x) { return c_v64_dup_16(x); } SIMD_INLINE v64 v64_dup_32(uint32_t x) { return c_v64_dup_32(x); } @@ -128,20 +128,22 @@ SIMD_INLINE v64 v64_shuffle_8(v64 a, v64 pattern) { return c_v64_shuffle_8(a, pattern); } -typedef uint32_t sad64_internal; -SIMD_INLINE sad64_internal v64_sad_u8_init() { return c_v64_sad_u8_init(); } -SIMD_INLINE sad64_internal v64_sad_u8(sad64_internal s, v64 a, v64 b) { +SIMD_INLINE c_sad64_internal v64_sad_u8_init(void) { + return c_v64_sad_u8_init(); +} +SIMD_INLINE c_sad64_internal v64_sad_u8(c_sad64_internal s, v64 a, v64 b) { return c_v64_sad_u8(s, a, b); } -SIMD_INLINE uint32_t v64_sad_u8_sum(sad64_internal s) { +SIMD_INLINE uint32_t v64_sad_u8_sum(c_sad64_internal s) { return c_v64_sad_u8_sum(s); } -typedef uint32_t ssd64_internal; -SIMD_INLINE ssd64_internal v64_ssd_u8_init() { return c_v64_ssd_u8_init(); } -SIMD_INLINE ssd64_internal v64_ssd_u8(ssd64_internal s, v64 a, v64 b) { +SIMD_INLINE c_ssd64_internal v64_ssd_u8_init(void) { + return c_v64_ssd_u8_init(); +} +SIMD_INLINE c_ssd64_internal v64_ssd_u8(c_ssd64_internal s, v64 a, v64 b) { return c_v64_ssd_u8(s, a, b); } -SIMD_INLINE uint32_t v64_ssd_u8_sum(ssd64_internal s) { +SIMD_INLINE uint32_t v64_ssd_u8_sum(c_ssd64_internal s) { return c_v64_ssd_u8_sum(s); } SIMD_INLINE int64_t v64_dotp_su8(v64 a, v64 b) { return c_v64_dotp_su8(a, b); } diff --git a/media/libaom/src/aom_dsp/simd/v64_intrinsics_arm.h b/media/libaom/src/aom_dsp/simd/v64_intrinsics_arm.h index 8f39ad6e81..a4ecdf4b5c 100644 --- a/media/libaom/src/aom_dsp/simd/v64_intrinsics_arm.h +++ b/media/libaom/src/aom_dsp/simd/v64_intrinsics_arm.h @@ -71,7 +71,11 @@ SIMD_INLINE void u32_store_unaligned(void *p, uint32_t a) { #elif defined(__CC_ARM) *(__packed uint32_t *)p) = a; #elif defined(__GNUC__) - *((__attribute((packed)) uint32_t *)p) = a; + struct Unaligned32Struct { + uint32_t value; + uint8_t dummy; // To make the size non-power-of-two. + } __attribute__((__packed__)); + ((struct Unaligned32Struct *)p)->value = a; #else vst1_lane_u32((uint32_t *)p, vreinterpret_u32_s64((uint64x1_t)(uint64_t)a), 0); @@ -107,7 +111,7 @@ SIMD_INLINE v64 v64_align(v64 a, v64 b, unsigned int c) { #endif } -SIMD_INLINE v64 v64_zero() { return vreinterpret_s64_u8(vdup_n_u8(0)); } +SIMD_INLINE v64 v64_zero(void) { return vreinterpret_s64_u8(vdup_n_u8(0)); } SIMD_INLINE v64 v64_dup_8(uint8_t x) { return vreinterpret_s64_u8(vdup_n_u8(x)); @@ -158,7 +162,7 @@ SIMD_INLINE int64_t v64_hadd_s16(v64 a) { typedef uint16x8_t sad64_internal; -SIMD_INLINE sad64_internal v64_sad_u8_init() { return vdupq_n_u16(0); } +SIMD_INLINE sad64_internal v64_sad_u8_init(void) { return vdupq_n_u16(0); } // Implementation dependent return value. Result must be finalised with // v64_sad_u8_sum(). @@ -177,7 +181,7 @@ SIMD_INLINE uint32_t v64_sad_u8_sum(sad64_internal s) { typedef uint32x4_t ssd64_internal; -SIMD_INLINE ssd64_internal v64_ssd_u8_init() { return vdupq_n_u32(0); } +SIMD_INLINE ssd64_internal v64_ssd_u8_init(void) { return vdupq_n_u32(0); } // Implementation dependent return value. Result must be finalised with // v64_ssd_u8_sum(). @@ -604,39 +608,39 @@ SIMD_INLINE v64 v64_shr_n_byte(v64 a, unsigned int c) { } SIMD_INLINE v64 v64_shl_n_8(v64 a, unsigned int c) { - return vreinterpret_s64_u8(vshl_n_u8(vreinterpret_u8_s64(a), c)); + return c ? vreinterpret_s64_u8(vshl_n_u8(vreinterpret_u8_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_u8(v64 a, unsigned int c) { - return vreinterpret_s64_u8(vshr_n_u8(vreinterpret_u8_s64(a), c)); + return c ? vreinterpret_s64_u8(vshr_n_u8(vreinterpret_u8_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_s8(v64 a, unsigned int c) { - return vreinterpret_s64_s8(vshr_n_s8(vreinterpret_s8_s64(a), c)); + return c ? vreinterpret_s64_s8(vshr_n_s8(vreinterpret_s8_s64(a), c)) : a; } SIMD_INLINE v64 v64_shl_n_16(v64 a, unsigned int c) { - return vreinterpret_s64_u16(vshl_n_u16(vreinterpret_u16_s64(a), c)); + return c ? vreinterpret_s64_u16(vshl_n_u16(vreinterpret_u16_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_u16(v64 a, unsigned int c) { - return vreinterpret_s64_u16(vshr_n_u16(vreinterpret_u16_s64(a), c)); + return c ? vreinterpret_s64_u16(vshr_n_u16(vreinterpret_u16_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_s16(v64 a, unsigned int c) { - return vreinterpret_s64_s16(vshr_n_s16(vreinterpret_s16_s64(a), c)); + return c ? vreinterpret_s64_s16(vshr_n_s16(vreinterpret_s16_s64(a), c)) : a; } SIMD_INLINE v64 v64_shl_n_32(v64 a, unsigned int c) { - return vreinterpret_s64_u32(vshl_n_u32(vreinterpret_u32_s64(a), c)); + return c ? vreinterpret_s64_u32(vshl_n_u32(vreinterpret_u32_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_u32(v64 a, unsigned int c) { - return vreinterpret_s64_u32(vshr_n_u32(vreinterpret_u32_s64(a), c)); + return c ? vreinterpret_s64_u32(vshr_n_u32(vreinterpret_u32_s64(a), c)) : a; } SIMD_INLINE v64 v64_shr_n_s32(v64 a, unsigned int c) { - return vreinterpret_s64_s32(vshr_n_s32(vreinterpret_s32_s64(a), c)); + return c ? vreinterpret_s64_s32(vshr_n_s32(vreinterpret_s32_s64(a), c)) : a; } #else diff --git a/media/libaom/src/aom_dsp/simd/v64_intrinsics_c.h b/media/libaom/src/aom_dsp/simd/v64_intrinsics_c.h index 090c44814f..b84f243c45 100644 --- a/media/libaom/src/aom_dsp/simd/v64_intrinsics_c.h +++ b/media/libaom/src/aom_dsp/simd/v64_intrinsics_c.h @@ -143,7 +143,7 @@ SIMD_INLINE void c_v64_store_aligned(void *p, c_v64 a) { c_v64_store_unaligned(p, a); } -SIMD_INLINE c_v64 c_v64_zero() { +SIMD_INLINE c_v64 c_v64_zero(void) { c_v64 t; t.u64 = 0; return t; @@ -601,28 +601,41 @@ SIMD_INLINE int64_t c_v64_hadd_s16(c_v64 a) { return a.s16[3] + a.s16[2] + a.s16[1] + a.s16[0]; } -typedef uint32_t c_sad64_internal; +typedef struct { + uint32_t val; + int count; +} c_sad64_internal; + +SIMD_INLINE c_sad64_internal c_v64_sad_u8_init(void) { + c_sad64_internal t; + t.val = t.count = 0; + return t; +} /* Implementation dependent return value. Result must be finalised with - v64_sad_u8_sum(). - The result for more than 32 v64_sad_u8() calls is undefined. */ -SIMD_INLINE c_sad64_internal c_v64_sad_u8_init() { return 0; } - + v64_sad_u8_sum(). The result for more than 32 v64_sad_u8() calls is + undefined. */ SIMD_INLINE c_sad64_internal c_v64_sad_u8(c_sad64_internal s, c_v64 a, c_v64 b) { int c; for (c = 0; c < 8; c++) - s += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.val += a.u8[c] > b.u8[c] ? a.u8[c] - b.u8[c] : b.u8[c] - a.u8[c]; + s.count++; + if (SIMD_CHECK && s.count > 32) { + fprintf(stderr, + "Error: sad called 32 times returning an undefined result\n"); + abort(); + } return s; } -SIMD_INLINE uint32_t c_v64_sad_u8_sum(c_sad64_internal s) { return s; } +SIMD_INLINE uint32_t c_v64_sad_u8_sum(c_sad64_internal s) { return s.val; } typedef uint32_t c_ssd64_internal; /* Implementation dependent return value. Result must be finalised with * v64_ssd_u8_sum(). */ -SIMD_INLINE c_ssd64_internal c_v64_ssd_u8_init() { return 0; } +SIMD_INLINE c_ssd64_internal c_v64_ssd_u8_init(void) { return 0; } SIMD_INLINE c_ssd64_internal c_v64_ssd_u8(c_ssd64_internal s, c_v64 a, c_v64 b) { diff --git a/media/libaom/src/aom_dsp/simd/v64_intrinsics_x86.h b/media/libaom/src/aom_dsp/simd/v64_intrinsics_x86.h index 8c7b4c4bf1..1f273fe964 100644 --- a/media/libaom/src/aom_dsp/simd/v64_intrinsics_x86.h +++ b/media/libaom/src/aom_dsp/simd/v64_intrinsics_x86.h @@ -99,7 +99,7 @@ SIMD_INLINE void v64_store_unaligned(void *p, v64 a) { : (b)) #endif -SIMD_INLINE v64 v64_zero() { return _mm_setzero_si128(); } +SIMD_INLINE v64 v64_zero(void) { return _mm_setzero_si128(); } SIMD_INLINE v64 v64_dup_8(uint8_t x) { return _mm_set1_epi8(x); } @@ -319,7 +319,7 @@ SIMD_INLINE int64_t v64_hadd_s16(v64 a) { typedef v64 sad64_internal; -SIMD_INLINE sad64_internal v64_sad_u8_init() { return _mm_setzero_si128(); } +SIMD_INLINE sad64_internal v64_sad_u8_init(void) { return _mm_setzero_si128(); } /* Implementation dependent return value. Result must be finalised with v64_sad_u8_sum(). @@ -332,7 +332,7 @@ SIMD_INLINE uint32_t v64_sad_u8_sum(sad64_internal s) { return v64_low_u32(s); } typedef v64 ssd64_internal; -SIMD_INLINE ssd64_internal v64_ssd_u8_init() { return _mm_setzero_si128(); } +SIMD_INLINE ssd64_internal v64_ssd_u8_init(void) { return _mm_setzero_si128(); } /* Implementation dependent return value. Result must be finalised with * v64_ssd_u8_sum(). */ @@ -433,7 +433,7 @@ SIMD_INLINE v64 v64_cmplt_s16(v64 a, v64 b) { return _mm_cmplt_epi16(a, b); } SIMD_INLINE v64 v64_cmpeq_16(v64 a, v64 b) { return _mm_cmpeq_epi16(a, b); } SIMD_INLINE v64 v64_shl_8(v64 a, unsigned int c) { - return _mm_and_si128(_mm_set1_epi8((char)(0xff << c)), + return _mm_and_si128(_mm_set1_epi8((uint8_t)(0xff << c)), _mm_sll_epi16(a, _mm_cvtsi32_si128(c))); } diff --git a/media/libaom/src/aom_dsp/sum_squares.c b/media/libaom/src/aom_dsp/sum_squares.c index 44ec41f2ed..d739a60833 100644 --- a/media/libaom/src/aom_dsp/sum_squares.c +++ b/media/libaom/src/aom_dsp/sum_squares.c @@ -38,3 +38,36 @@ uint64_t aom_sum_squares_i16_c(const int16_t *src, uint32_t n) { return ss; } + +uint64_t aom_var_2d_u8_c(uint8_t *src, int src_stride, int width, int height) { + int r, c; + uint64_t ss = 0, s = 0; + + for (r = 0; r < height; r++) { + for (c = 0; c < width; c++) { + const uint8_t v = src[c]; + ss += v * v; + s += v; + } + src += src_stride; + } + + return (ss - s * s / (width * height)); +} + +uint64_t aom_var_2d_u16_c(uint8_t *src, int src_stride, int width, int height) { + uint16_t *srcp = CONVERT_TO_SHORTPTR(src); + int r, c; + uint64_t ss = 0, s = 0; + + for (r = 0; r < height; r++) { + for (c = 0; c < width; c++) { + const uint16_t v = srcp[c]; + ss += v * v; + s += v; + } + srcp += src_stride; + } + + return (ss - s * s / (width * height)); +} diff --git a/media/libaom/src/aom_dsp/variance.c b/media/libaom/src/aom_dsp/variance.c index 020d4fea65..695f12a524 100644 --- a/media/libaom/src/aom_dsp/variance.c +++ b/media/libaom/src/aom_dsp/variance.c @@ -23,9 +23,10 @@ #include "aom_dsp/blend.h" #include "aom_dsp/variance.h" +#include "av1/common/av1_common_int.h" #include "av1/common/filter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" +#include "av1/encoder/reconinter_enc.h" uint32_t aom_get4x4sse_cs_c(const uint8_t *a, int a_stride, const uint8_t *b, int b_stride) { @@ -295,70 +296,24 @@ void aom_upsampled_pred_c(MACROBLOCKD *xd, const AV1_COMMON *const cm, const int is_scaled = av1_is_scaled(sf); if (is_scaled) { - // Note: This is mostly a copy from the >=8X8 case in - // build_inter_predictors() function, with some small tweaks. - - // Some assumptions. - const int plane = 0; - - // Get pre-requisites. + int plane = 0; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int ssx = pd->subsampling_x; - const int ssy = pd->subsampling_y; - assert(ssx == 0 && ssy == 0); const struct buf_2d *const dst_buf = &pd->dst; const struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref_num]; - const int mi_x = mi_col * MI_SIZE; - const int mi_y = mi_row * MI_SIZE; - - // Calculate subpel_x/y and x/y_step. - const int row_start = 0; // Because ss_y is 0. - const int col_start = 0; // Because ss_x is 0. - const int pre_x = (mi_x + MI_SIZE * col_start) >> ssx; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ssy; - int orig_pos_y = pre_y << SUBPEL_BITS; - orig_pos_y += mv->row * (1 << (1 - ssy)); - int orig_pos_x = pre_x << SUBPEL_BITS; - orig_pos_x += mv->col * (1 << (1 - ssx)); - int pos_y = sf->scale_value_y(orig_pos_y, sf); - int pos_x = sf->scale_value_x(orig_pos_x, sf); - pos_x += SCALE_EXTRA_OFF; - pos_y += SCALE_EXTRA_OFF; - - const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); - const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); - const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - const int right = (pre_buf->width + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - pos_y = clamp(pos_y, top, bottom); - pos_x = clamp(pos_x, left, right); - - const uint8_t *const pre = - pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + - (pos_x >> SCALE_SUBPEL_BITS); InterPredParams inter_pred_params; - - const SubpelParams subpel_params = { sf->x_step_q4, sf->y_step_q4, - pos_x & SCALE_SUBPEL_MASK, - pos_y & SCALE_SUBPEL_MASK }; - - // Get convolve parameters. inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); const int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - av1_init_inter_params( &inter_pred_params, width, height, mi_y >> pd->subsampling_y, mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, filters); - - // Get the inter predictor. - av1_make_inter_predictor(pre, pre_buf->stride, comp_pred, width, - &inter_pred_params, &subpel_params); - + xd->bd, is_cur_buf_hbd(xd), is_intrabc, sf, pre_buf, filters); + av1_enc_build_one_inter_predictor(comp_pred, width, mv, + &inter_pred_params); return; } } @@ -884,69 +839,24 @@ void aom_highbd_upsampled_pred_c(MACROBLOCKD *xd, const int is_scaled = av1_is_scaled(sf); if (is_scaled) { - // Note: This is mostly a copy from the >=8X8 case in - // build_inter_predictors() function, with some small tweaks. - // Some assumptions. - const int plane = 0; - - // Get pre-requisites. + int plane = 0; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int ssx = pd->subsampling_x; - const int ssy = pd->subsampling_y; - assert(ssx == 0 && ssy == 0); const struct buf_2d *const dst_buf = &pd->dst; const struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref_num]; - const int mi_x = mi_col * MI_SIZE; - const int mi_y = mi_row * MI_SIZE; - - // Calculate subpel_x/y and x/y_step. - const int row_start = 0; // Because ss_y is 0. - const int col_start = 0; // Because ss_x is 0. - const int pre_x = (mi_x + MI_SIZE * col_start) >> ssx; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ssy; - int orig_pos_y = pre_y << SUBPEL_BITS; - orig_pos_y += mv->row * (1 << (1 - ssy)); - int orig_pos_x = pre_x << SUBPEL_BITS; - orig_pos_x += mv->col * (1 << (1 - ssx)); - int pos_y = sf->scale_value_y(orig_pos_y, sf); - int pos_x = sf->scale_value_x(orig_pos_x, sf); - pos_x += SCALE_EXTRA_OFF; - pos_y += SCALE_EXTRA_OFF; - - const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); - const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); - const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - const int right = (pre_buf->width + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - pos_y = clamp(pos_y, top, bottom); - pos_x = clamp(pos_x, left, right); - - const uint8_t *const pre = - pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + - (pos_x >> SCALE_SUBPEL_BITS); InterPredParams inter_pred_params; - - const SubpelParams subpel_params = { sf->x_step_q4, sf->y_step_q4, - pos_x & SCALE_SUBPEL_MASK, - pos_y & SCALE_SUBPEL_MASK }; - - // Get convolve parameters. inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); const int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - av1_init_inter_params( &inter_pred_params, width, height, mi_y >> pd->subsampling_y, mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, filters); - - // Get the inter predictor. - av1_make_inter_predictor(pre, pre_buf->stride, comp_pred8, width, - &inter_pred_params, &subpel_params); - + xd->bd, is_cur_buf_hbd(xd), is_intrabc, sf, pre_buf, filters); + av1_enc_build_one_inter_predictor(comp_pred8, width, mv, + &inter_pred_params); return; } } diff --git a/media/libaom/src/aom_dsp/vmaf.c b/media/libaom/src/aom_dsp/vmaf.c new file mode 100644 index 0000000000..3a012e7680 --- /dev/null +++ b/media/libaom/src/aom_dsp/vmaf.c @@ -0,0 +1,159 @@ +/* + * 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 + +#include "aom_dsp/blend.h" +#include "aom_dsp/vmaf.h" +#include "aom_ports/system_state.h" + +typedef struct FrameData { + const YV12_BUFFER_CONFIG *source; + const YV12_BUFFER_CONFIG *distorted; + int frame_set; + int bit_depth; +} FrameData; + +static void vmaf_fatal_error(const char *message) { + fprintf(stderr, "Fatal error: %s\n", message); + exit(EXIT_FAILURE); +} + +// A callback function used to pass data to VMAF. +// Returns 0 after reading a frame. +// Returns 2 when there is no more frame to read. +static int read_frame(float *ref_data, float *main_data, float *temp_data, + int stride, void *user_data) { + FrameData *frames = (FrameData *)user_data; + + if (!frames->frame_set) { + const int width = frames->source->y_width; + const int height = frames->source->y_height; + assert(width == frames->distorted->y_width); + assert(height == frames->distorted->y_height); + + if (frames->bit_depth > 8) { + const float scale_factor = 1.0f / (float)(1 << (frames->bit_depth - 8)); + uint16_t *ref_ptr = CONVERT_TO_SHORTPTR(frames->source->y_buffer); + uint16_t *main_ptr = CONVERT_TO_SHORTPTR(frames->distorted->y_buffer); + + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + ref_data[col] = scale_factor * (float)ref_ptr[col]; + } + ref_ptr += frames->source->y_stride; + ref_data += stride / sizeof(*ref_data); + } + + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + main_data[col] = scale_factor * (float)main_ptr[col]; + } + main_ptr += frames->distorted->y_stride; + main_data += stride / sizeof(*main_data); + } + } else { + uint8_t *ref_ptr = frames->source->y_buffer; + uint8_t *main_ptr = frames->distorted->y_buffer; + + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + ref_data[col] = (float)ref_ptr[col]; + } + ref_ptr += frames->source->y_stride; + ref_data += stride / sizeof(*ref_data); + } + + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + main_data[col] = (float)main_ptr[col]; + } + main_ptr += frames->distorted->y_stride; + main_data += stride / sizeof(*main_data); + } + } + frames->frame_set = 1; + return 0; + } + + (void)temp_data; + return 2; +} + +void aom_calc_vmaf(const char *model_path, const YV12_BUFFER_CONFIG *source, + const YV12_BUFFER_CONFIG *distorted, const int bit_depth, + double *const vmaf) { + aom_clear_system_state(); + const int width = source->y_width; + const int height = source->y_height; + FrameData frames = { source, distorted, 0, bit_depth }; + char *fmt = bit_depth == 10 ? "yuv420p10le" : "yuv420p"; + double vmaf_score; + const int ret = + compute_vmaf(&vmaf_score, fmt, width, height, read_frame, + /*user_data=*/&frames, (char *)model_path, + /*log_path=*/NULL, /*log_fmt=*/NULL, /*disable_clip=*/1, + /*disable_avx=*/0, /*enable_transform=*/0, + /*phone_model=*/0, /*do_psnr=*/0, /*do_ssim=*/0, + /*do_ms_ssim=*/0, /*pool_method=*/NULL, /*n_thread=*/0, + /*n_subsample=*/1, /*enable_conf_interval=*/0); + if (ret) vmaf_fatal_error("Failed to compute VMAF scores."); + + aom_clear_system_state(); + *vmaf = vmaf_score; +} + +void aom_calc_vmaf_multi_frame( + void *user_data, const char *model_path, + int (*read_frame)(float *ref_data, float *main_data, float *temp_data, + int stride_byte, void *user_data), + int frame_width, int frame_height, int bit_depth, double *vmaf) { + aom_clear_system_state(); + + char *fmt = bit_depth == 10 ? "yuv420p10le" : "yuv420p"; + double vmaf_score; + const int ret = compute_vmaf( + &vmaf_score, fmt, frame_width, frame_height, read_frame, + /*user_data=*/user_data, (char *)model_path, + /*log_path=*/"vmaf_scores.xml", /*log_fmt=*/NULL, /*disable_clip=*/0, + /*disable_avx=*/0, /*enable_transform=*/0, + /*phone_model=*/0, /*do_psnr=*/0, /*do_ssim=*/0, + /*do_ms_ssim=*/0, /*pool_method=*/NULL, /*n_thread=*/0, + /*n_subsample=*/1, /*enable_conf_interval=*/0); + FILE *vmaf_log = fopen("vmaf_scores.xml", "r"); + if (vmaf_log == NULL || ret) { + vmaf_fatal_error("Failed to compute VMAF scores."); + } + + int frame_index = 0; + char buf[512]; + while (fgets(buf, 511, vmaf_log) != NULL) { + if (memcmp(buf, "\t\t 100.0) { + vmaf_fatal_error("Failed to compute VMAF scores."); + } + vmaf[frame_index++] = score; + } + } + } + fclose(vmaf_log); + + aom_clear_system_state(); +} diff --git a/media/libaom/src/aom_dsp/vmaf.h b/media/libaom/src/aom_dsp/vmaf.h new file mode 100644 index 0000000000..fb8bf4613a --- /dev/null +++ b/media/libaom/src/aom_dsp/vmaf.h @@ -0,0 +1,27 @@ +/* + * 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_AOM_DSP_VMAF_H_ +#define AOM_AOM_DSP_VMAF_H_ + +#include "aom_scale/yv12config.h" + +void aom_calc_vmaf(const char *model_path, const YV12_BUFFER_CONFIG *source, + const YV12_BUFFER_CONFIG *distorted, int bit_depth, + double *vmaf); + +void aom_calc_vmaf_multi_frame( + void *user_data, const char *model_path, + int (*read_frame)(float *ref_data, float *main_data, float *temp_data, + int stride_byte, void *user_data), + int frame_width, int frame_height, int bit_depth, double *vmaf); + +#endif // AOM_AOM_DSP_VMAF_H_ diff --git a/media/libaom/src/aom_dsp/x86/adaptive_quantize_avx2.c b/media/libaom/src/aom_dsp/x86/adaptive_quantize_avx2.c index 3335087198..e33dff20c2 100644 --- a/media/libaom/src/aom_dsp/x86/adaptive_quantize_avx2.c +++ b/media/libaom/src/aom_dsp/x86/adaptive_quantize_avx2.c @@ -227,7 +227,7 @@ void aom_quantize_b_adaptive_avx2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff0 = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff0 >> 31); + const int coeff_sign = AOMSIGN(coeff0); const int abs_coeff = (coeff0 ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = diff --git a/media/libaom/src/aom_dsp/x86/adaptive_quantize_sse2.c b/media/libaom/src/aom_dsp/x86/adaptive_quantize_sse2.c index 2fc700d7d7..584cd671f1 100644 --- a/media/libaom/src/aom_dsp/x86/adaptive_quantize_sse2.c +++ b/media/libaom/src/aom_dsp/x86/adaptive_quantize_sse2.c @@ -200,7 +200,7 @@ void aom_quantize_b_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = @@ -409,7 +409,7 @@ void aom_quantize_b_32x32_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = @@ -617,7 +617,7 @@ void aom_quantize_b_64x64_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = diff --git a/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c b/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c index 21fc72955f..3bbffbd805 100644 --- a/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c +++ b/media/libaom/src/aom_dsp/x86/avg_intrin_avx2.c @@ -181,6 +181,38 @@ void aom_hadamard_16x16_avx2(const int16_t *src_diff, ptrdiff_t src_stride, hadamard_16x16_avx2(src_diff, src_stride, coeff, 1); } +void aom_hadamard_lp_16x16_avx2(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + int16_t *t_coeff = coeff; + for (int idx = 0; idx < 2; ++idx) { + const int16_t *src_ptr = src_diff + idx * 8 * src_stride; + hadamard_8x8x2_avx2(src_ptr, src_stride, t_coeff + (idx * 64 * 2)); + } + + for (int idx = 0; idx < 64; idx += 16) { + const __m256i coeff0 = _mm256_loadu_si256((const __m256i *)t_coeff); + const __m256i coeff1 = _mm256_loadu_si256((const __m256i *)(t_coeff + 64)); + const __m256i coeff2 = _mm256_loadu_si256((const __m256i *)(t_coeff + 128)); + const __m256i coeff3 = _mm256_loadu_si256((const __m256i *)(t_coeff + 192)); + + __m256i b0 = _mm256_add_epi16(coeff0, coeff1); + __m256i b1 = _mm256_sub_epi16(coeff0, coeff1); + __m256i b2 = _mm256_add_epi16(coeff2, coeff3); + __m256i b3 = _mm256_sub_epi16(coeff2, coeff3); + + b0 = _mm256_srai_epi16(b0, 1); + b1 = _mm256_srai_epi16(b1, 1); + b2 = _mm256_srai_epi16(b2, 1); + b3 = _mm256_srai_epi16(b3, 1); + _mm256_storeu_si256((__m256i *)coeff, _mm256_add_epi16(b0, b2)); + _mm256_storeu_si256((__m256i *)(coeff + 64), _mm256_add_epi16(b1, b3)); + _mm256_storeu_si256((__m256i *)(coeff + 128), _mm256_sub_epi16(b0, b2)); + _mm256_storeu_si256((__m256i *)(coeff + 192), _mm256_sub_epi16(b1, b3)); + coeff += 16; + t_coeff += 16; + } +} + void aom_hadamard_32x32_avx2(const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff) { // For high bitdepths, it is unnecessary to store_tran_low @@ -447,3 +479,26 @@ int aom_satd_avx2(const tran_low_t *coeff, int length) { return _mm_cvtsi128_si32(accum_128); } } + +int aom_satd_lp_avx2(const int16_t *coeff, int length) { + const __m256i one = _mm256_set1_epi16(1); + __m256i accum = _mm256_setzero_si256(); + + for (int i = 0; i < length; i += 16) { + const __m256i src_line = _mm256_loadu_si256((const __m256i *)coeff); + const __m256i abs = _mm256_abs_epi16(src_line); + const __m256i sum = _mm256_madd_epi16(abs, one); + accum = _mm256_add_epi32(accum, sum); + coeff += 16; + } + + { // 32 bit horizontal add + const __m256i a = _mm256_srli_si256(accum, 8); + const __m256i b = _mm256_add_epi32(accum, a); + const __m256i c = _mm256_srli_epi64(b, 32); + const __m256i d = _mm256_add_epi32(b, c); + const __m128i accum_128 = _mm_add_epi32(_mm256_castsi256_si128(d), + _mm256_extractf128_si256(d, 1)); + return _mm_cvtsi128_si32(accum_128); + } +} diff --git a/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c b/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c index 1c5f6ebf7c..260ca2ad17 100644 --- a/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c +++ b/media/libaom/src/aom_dsp/x86/avg_intrin_sse2.c @@ -139,7 +139,7 @@ unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) { return (avg + 8) >> 4; } -static void hadamard_col8_sse2(__m128i *in, int iter) { +static INLINE void hadamard_col8_sse2(__m128i *in, int iter) { __m128i a0 = in[0]; __m128i a1 = in[1]; __m128i a2 = in[2]; @@ -272,6 +272,38 @@ void aom_hadamard_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride, hadamard_8x8_sse2(src_diff, src_stride, coeff, 1); } +void aom_hadamard_lp_8x8_sse2(const int16_t *src_diff, ptrdiff_t src_stride, + int16_t *coeff) { + __m128i src[8]; + src[0] = _mm_load_si128((const __m128i *)src_diff); + src[1] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[2] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[3] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[4] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[5] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[6] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + src[7] = _mm_load_si128((const __m128i *)(src_diff += src_stride)); + + hadamard_col8_sse2(src, 0); + hadamard_col8_sse2(src, 1); + + _mm_store_si128((__m128i *)coeff, src[0]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[1]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[2]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[3]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[4]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[5]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[6]); + coeff += 8; + _mm_store_si128((__m128i *)coeff, src[7]); +} + static INLINE void hadamard_16x16_sse2(const int16_t *src_diff, ptrdiff_t src_stride, tran_low_t *coeff, int is_final) { diff --git a/media/libaom/src/aom_dsp/x86/fwd_txfm_impl_sse2.h b/media/libaom/src/aom_dsp/x86/fwd_txfm_impl_sse2.h index 1e3d13ec85..89fe1899bb 100644 --- a/media/libaom/src/aom_dsp/x86/fwd_txfm_impl_sse2.h +++ b/media/libaom/src/aom_dsp/x86/fwd_txfm_impl_sse2.h @@ -30,6 +30,206 @@ #define SUB_EPI16 _mm_sub_epi16 #endif +static void FDCT4x4_2D_HELPER(const int16_t *input, int stride, __m128i *in0, + __m128i *in1) { + // Constants + // These are the coefficients used for the multiplies. + // In the comments, pN means cos(N pi /64) and mN is -cos(N pi /64), + // where cospi_N_64 = cos(N pi /64) + const __m128i k__cospi_A = + octa_set_epi16(cospi_16_64, cospi_16_64, cospi_16_64, cospi_16_64, + cospi_16_64, -cospi_16_64, cospi_16_64, -cospi_16_64); + const __m128i k__cospi_B = + octa_set_epi16(cospi_16_64, -cospi_16_64, cospi_16_64, -cospi_16_64, + cospi_16_64, cospi_16_64, cospi_16_64, cospi_16_64); + const __m128i k__cospi_C = + octa_set_epi16(cospi_8_64, cospi_24_64, cospi_8_64, cospi_24_64, + cospi_24_64, -cospi_8_64, cospi_24_64, -cospi_8_64); + const __m128i k__cospi_D = + octa_set_epi16(cospi_24_64, -cospi_8_64, cospi_24_64, -cospi_8_64, + cospi_8_64, cospi_24_64, cospi_8_64, cospi_24_64); + const __m128i k__cospi_E = + octa_set_epi16(cospi_16_64, cospi_16_64, cospi_16_64, cospi_16_64, + cospi_16_64, cospi_16_64, cospi_16_64, cospi_16_64); + const __m128i k__cospi_F = + octa_set_epi16(cospi_16_64, -cospi_16_64, cospi_16_64, -cospi_16_64, + cospi_16_64, -cospi_16_64, cospi_16_64, -cospi_16_64); + const __m128i k__cospi_G = + octa_set_epi16(cospi_8_64, cospi_24_64, cospi_8_64, cospi_24_64, + -cospi_8_64, -cospi_24_64, -cospi_8_64, -cospi_24_64); + const __m128i k__cospi_H = + octa_set_epi16(cospi_24_64, -cospi_8_64, cospi_24_64, -cospi_8_64, + -cospi_24_64, cospi_8_64, -cospi_24_64, cospi_8_64); + + const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING); + // This second rounding constant saves doing some extra adds at the end + const __m128i k__DCT_CONST_ROUNDING2 = + _mm_set1_epi32(DCT_CONST_ROUNDING + (DCT_CONST_ROUNDING << 1)); + const int DCT_CONST_BITS2 = DCT_CONST_BITS + 2; + const __m128i k__nonzero_bias_a = _mm_setr_epi16(0, 1, 1, 1, 1, 1, 1, 1); + const __m128i k__nonzero_bias_b = _mm_setr_epi16(1, 0, 0, 0, 0, 0, 0, 0); + + // Load inputs. + *in0 = _mm_loadl_epi64((const __m128i *)(input + 0 * stride)); + *in1 = _mm_loadl_epi64((const __m128i *)(input + 1 * stride)); + *in1 = _mm_unpacklo_epi64( + *in1, _mm_loadl_epi64((const __m128i *)(input + 2 * stride))); + *in0 = _mm_unpacklo_epi64( + *in0, _mm_loadl_epi64((const __m128i *)(input + 3 * stride))); + // in0 = [i0 i1 i2 i3 iC iD iE iF] + // in1 = [i4 i5 i6 i7 i8 i9 iA iB] + // multiply by 16 to give some extra precision + *in0 = _mm_slli_epi16(*in0, 4); + *in1 = _mm_slli_epi16(*in1, 4); + // if (i == 0 && input[0]) input[0] += 1; + // add 1 to the upper left pixel if it is non-zero, which helps reduce + // the round-trip error + { + // The mask will only contain whether the first value is zero, all + // other comparison will fail as something shifted by 4 (above << 4) + // can never be equal to one. To increment in the non-zero case, we + // add the mask and one for the first element: + // - if zero, mask = -1, v = v - 1 + 1 = v + // - if non-zero, mask = 0, v = v + 0 + 1 = v + 1 + __m128i mask = _mm_cmpeq_epi16(*in0, k__nonzero_bias_a); + *in0 = _mm_add_epi16(*in0, mask); + *in0 = _mm_add_epi16(*in0, k__nonzero_bias_b); + } + // There are 4 total stages, alternating between an add/subtract stage + // followed by an multiply-and-add stage. + { + // Stage 1: Add/subtract + + // in0 = [i0 i1 i2 i3 iC iD iE iF] + // in1 = [i4 i5 i6 i7 i8 i9 iA iB] + const __m128i r0 = _mm_unpacklo_epi16(*in0, *in1); + const __m128i r1 = _mm_unpackhi_epi16(*in0, *in1); + // r0 = [i0 i4 i1 i5 i2 i6 i3 i7] + // r1 = [iC i8 iD i9 iE iA iF iB] + const __m128i r2 = _mm_shuffle_epi32(r0, 0xB4); + const __m128i r3 = _mm_shuffle_epi32(r1, 0xB4); + // r2 = [i0 i4 i1 i5 i3 i7 i2 i6] + // r3 = [iC i8 iD i9 iF iB iE iA] + + const __m128i t0 = _mm_add_epi16(r2, r3); + const __m128i t1 = _mm_sub_epi16(r2, r3); + // t0 = [a0 a4 a1 a5 a3 a7 a2 a6] + // t1 = [aC a8 aD a9 aF aB aE aA] + + // Stage 2: multiply by constants (which gets us into 32 bits). + // The constants needed here are: + // k__cospi_A = [p16 p16 p16 p16 p16 m16 p16 m16] + // k__cospi_B = [p16 m16 p16 m16 p16 p16 p16 p16] + // k__cospi_C = [p08 p24 p08 p24 p24 m08 p24 m08] + // k__cospi_D = [p24 m08 p24 m08 p08 p24 p08 p24] + const __m128i u0 = _mm_madd_epi16(t0, k__cospi_A); + const __m128i u2 = _mm_madd_epi16(t0, k__cospi_B); + const __m128i u1 = _mm_madd_epi16(t1, k__cospi_C); + const __m128i u3 = _mm_madd_epi16(t1, k__cospi_D); + // Then add and right-shift to get back to 16-bit range + const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING); + const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING); + const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING); + const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING); + const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS); + const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS); + const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS); + const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS); + // w0 = [b0 b1 b7 b6] + // w1 = [b8 b9 bF bE] + // w2 = [b4 b5 b3 b2] + // w3 = [bC bD bB bA] + const __m128i x0 = _mm_packs_epi32(w0, w1); + const __m128i x1 = _mm_packs_epi32(w2, w3); + + // x0 = [b0 b1 b7 b6 b8 b9 bF bE] + // x1 = [b4 b5 b3 b2 bC bD bB bA] + *in0 = _mm_shuffle_epi32(x0, 0xD8); + *in1 = _mm_shuffle_epi32(x1, 0x8D); + // in0 = [b0 b1 b8 b9 b7 b6 bF bE] + // in1 = [b3 b2 bB bA b4 b5 bC bD] + } + { + // vertical DCTs finished. Now we do the horizontal DCTs. + // Stage 3: Add/subtract + + const __m128i t0 = ADD_EPI16(*in0, *in1); + const __m128i t1 = SUB_EPI16(*in0, *in1); + + // Stage 4: multiply by constants (which gets us into 32 bits). + { + // The constants needed here are: + // k__cospi_E = [p16 p16 p16 p16 p16 p16 p16 p16] + // k__cospi_F = [p16 m16 p16 m16 p16 m16 p16 m16] + // k__cospi_G = [p08 p24 p08 p24 m08 m24 m08 m24] + // k__cospi_H = [p24 m08 p24 m08 m24 p08 m24 p08] + const __m128i u0 = _mm_madd_epi16(t0, k__cospi_E); + const __m128i u1 = _mm_madd_epi16(t0, k__cospi_F); + const __m128i u2 = _mm_madd_epi16(t1, k__cospi_G); + const __m128i u3 = _mm_madd_epi16(t1, k__cospi_H); + // Then add and right-shift to get back to 16-bit range + // but this combines the final right-shift as well to save operations + // This unusual rounding operations is to maintain bit-accurate + // compatibility with the c version of this function which has two + // rounding steps in a row. + const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING2); + const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING2); + const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING2); + const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING2); + const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS2); + const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS2); + const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS2); + const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS2); + // w0 = [o0 o4 o8 oC] + // w1 = [o2 o6 oA oE] + // w2 = [o1 o5 o9 oD] + // w3 = [o3 o7 oB oF] + // remember the o's are numbered according to the correct output location + const __m128i x0 = _mm_packs_epi32(w0, w1); + const __m128i x1 = _mm_packs_epi32(w2, w3); + { + // x0 = [o0 o4 o8 oC o2 o6 oA oE] + // x1 = [o1 o5 o9 oD o3 o7 oB oF] + const __m128i y0 = _mm_unpacklo_epi16(x0, x1); + const __m128i y1 = _mm_unpackhi_epi16(x0, x1); + // y0 = [o0 o1 o4 o5 o8 o9 oC oD] + // y1 = [o2 o3 o6 o7 oA oB oE oF] + *in0 = _mm_unpacklo_epi32(y0, y1); + // in0 = [o0 o1 o2 o3 o4 o5 o6 o7] + *in1 = _mm_unpackhi_epi32(y0, y1); + // in1 = [o8 o9 oA oB oC oD oE oF] + } + } + } +} + +void FDCT4x4_2D(const int16_t *input, tran_low_t *output, int stride) { + // This 2D transform implements 4 vertical 1D transforms followed + // by 4 horizontal 1D transforms. The multiplies and adds are as given + // by Chen, Smith and Fralick ('77). The commands for moving the data + // around have been minimized by hand. + // For the purposes of the comments, the 16 inputs are referred to at i0 + // through iF (in raster order), intermediate variables are a0, b0, c0 + // through f, and correspond to the in-place computations mapped to input + // locations. The outputs, o0 through oF are labeled according to the + // output locations. + __m128i in0, in1; + FDCT4x4_2D_HELPER(input, stride, &in0, &in1); + + // Post-condition (v + 1) >> 2 is now incorporated into previous + // add and right-shift commands. Only 2 store instructions needed + // because we are using the fact that 1/3 are stored just after 0/2. + storeu_output(&in0, output + 0 * 4); + storeu_output(&in1, output + 2 * 4); +} + +void FDCT4x4_2D_LP(const int16_t *input, int16_t *output, int stride) { + __m128i in0, in1; + FDCT4x4_2D_HELPER(input, stride, &in0, &in1); + _mm_storeu_si128((__m128i *)(output + 0 * 4), in0); + _mm_storeu_si128((__m128i *)(output + 2 * 4), in1); +} + void FDCT8x8_2D(const int16_t *input, tran_low_t *output, int stride) { int pass; // Constants diff --git a/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.c b/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.c index 11c7d88d78..0e4fb80468 100644 --- a/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.c +++ b/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.c @@ -18,8 +18,14 @@ #include "aom_dsp/x86/fwd_txfm_sse2.h" #define DCT_HIGH_BIT_DEPTH 0 +#define FDCT4x4_2D_HELPER fdct4x4_helper +#define FDCT4x4_2D aom_fdct4x4_sse2 +#define FDCT4x4_2D_LP aom_fdct4x4_lp_sse2 #define FDCT8x8_2D aom_fdct8x8_sse2 #include "aom_dsp/x86/fwd_txfm_impl_sse2.h" +#undef FDCT4x4_2D_HELPER +#undef FDCT4x4_2D +#undef FDCT4x4_2D_LP #undef FDCT8x8_2D #if CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.h b/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.h index 260d8dd58e..ab3cd91557 100644 --- a/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.h +++ b/media/libaom/src/aom_dsp/x86/fwd_txfm_sse2.h @@ -136,16 +136,21 @@ static INLINE int check_epi16_overflow_x32( } static INLINE void store_output(const __m128i *poutput, tran_low_t *dst_ptr) { - if (sizeof(tran_low_t) == 4) { - const __m128i zero = _mm_setzero_si128(); - const __m128i sign_bits = _mm_cmplt_epi16(*poutput, zero); - __m128i out0 = _mm_unpacklo_epi16(*poutput, sign_bits); - __m128i out1 = _mm_unpackhi_epi16(*poutput, sign_bits); - _mm_store_si128((__m128i *)(dst_ptr), out0); - _mm_store_si128((__m128i *)(dst_ptr + 4), out1); - } else { - _mm_store_si128((__m128i *)(dst_ptr), *poutput); - } + const __m128i zero = _mm_setzero_si128(); + const __m128i sign_bits = _mm_cmplt_epi16(*poutput, zero); + __m128i out0 = _mm_unpacklo_epi16(*poutput, sign_bits); + __m128i out1 = _mm_unpackhi_epi16(*poutput, sign_bits); + _mm_store_si128((__m128i *)(dst_ptr), out0); + _mm_store_si128((__m128i *)(dst_ptr + 4), out1); +} + +static INLINE void storeu_output(const __m128i *poutput, tran_low_t *dst_ptr) { + const __m128i zero = _mm_setzero_si128(); + const __m128i sign_bits = _mm_cmplt_epi16(*poutput, zero); + __m128i out0 = _mm_unpacklo_epi16(*poutput, sign_bits); + __m128i out1 = _mm_unpackhi_epi16(*poutput, sign_bits); + _mm_storeu_si128((__m128i *)(dst_ptr), out0); + _mm_storeu_si128((__m128i *)(dst_ptr + 4), out1); } #ifdef __cplusplus diff --git a/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_avx2.c b/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_avx2.c index a97233b6ea..c500b0a26c 100644 --- a/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_avx2.c +++ b/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_avx2.c @@ -255,7 +255,7 @@ void aom_highbd_quantize_b_adaptive_avx2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = @@ -441,7 +441,7 @@ void aom_highbd_quantize_b_32x32_adaptive_avx2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = diff --git a/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_sse2.c b/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_sse2.c index 8e13f3db48..8f31f3596f 100644 --- a/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_sse2.c +++ b/media/libaom/src/aom_dsp/x86/highbd_adaptive_quantize_sse2.c @@ -283,7 +283,7 @@ void aom_highbd_quantize_b_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = @@ -500,7 +500,7 @@ void aom_highbd_quantize_b_32x32_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = @@ -716,7 +716,7 @@ void aom_highbd_quantize_b_64x64_adaptive_sse2( const int rc = scan[(*eob_ptr - 1)]; if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) { const int coeff = coeff_ptr[rc] * wt; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST; const int prescan_add_val = diff --git a/media/libaom/src/aom_dsp/x86/highbd_quantize_intrin_sse2.c b/media/libaom/src/aom_dsp/x86/highbd_quantize_intrin_sse2.c index 2f4ffd3639..1764a4952a 100644 --- a/media/libaom/src/aom_dsp/x86/highbd_quantize_intrin_sse2.c +++ b/media/libaom/src/aom_dsp/x86/highbd_quantize_intrin_sse2.c @@ -134,7 +134,7 @@ void aom_highbd_quantize_b_32x32_sse2( 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 coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int64_t tmp1 = abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1); const int64_t tmp2 = ((tmp1 * quant_ptr[rc != 0]) >> 16) + tmp1; @@ -192,7 +192,7 @@ void aom_highbd_quantize_b_64x64_sse2( 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 coeff_sign = AOMSIGN(coeff); 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; diff --git a/media/libaom/src/aom_dsp/x86/highbd_variance_sse2.c b/media/libaom/src/aom_dsp/x86/highbd_variance_sse2.c index bb25d36771..b7d15f93ec 100644 --- a/media/libaom/src/aom_dsp/x86/highbd_variance_sse2.c +++ b/media/libaom/src/aom_dsp/x86/highbd_variance_sse2.c @@ -20,9 +20,10 @@ #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/filter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" +#include "av1/encoder/reconinter_enc.h" typedef uint32_t (*high_variance_fn_t)(const uint16_t *src, int src_stride, const uint16_t *ref, int ref_stride, @@ -629,68 +630,24 @@ void aom_highbd_upsampled_pred_sse2(MACROBLOCKD *xd, const int is_scaled = av1_is_scaled(sf); if (is_scaled) { - // Note: This is mostly a copy from the >=8X8 case in - // build_inter_predictors() function, with some small tweaks. - // Some assumptions. - const int plane = 0; - - // Get pre-requisites. + int plane = 0; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int ssx = pd->subsampling_x; - const int ssy = pd->subsampling_y; - assert(ssx == 0 && ssy == 0); const struct buf_2d *const dst_buf = &pd->dst; const struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref_num]; - const int mi_x = mi_col * MI_SIZE; - const int mi_y = mi_row * MI_SIZE; - - // Calculate subpel_x/y and x/y_step. - const int row_start = 0; // Because ss_y is 0. - const int col_start = 0; // Because ss_x is 0. - const int pre_x = (mi_x + MI_SIZE * col_start) >> ssx; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ssy; - int orig_pos_y = pre_y << SUBPEL_BITS; - orig_pos_y += mv->row * (1 << (1 - ssy)); - int orig_pos_x = pre_x << SUBPEL_BITS; - orig_pos_x += mv->col * (1 << (1 - ssx)); - int pos_y = sf->scale_value_y(orig_pos_y, sf); - int pos_x = sf->scale_value_x(orig_pos_x, sf); - pos_x += SCALE_EXTRA_OFF; - pos_y += SCALE_EXTRA_OFF; - - const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); - const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); - const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - const int right = (pre_buf->width + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - pos_y = clamp(pos_y, top, bottom); - pos_x = clamp(pos_x, left, right); - - const uint8_t *const pre = - pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + - (pos_x >> SCALE_SUBPEL_BITS); InterPredParams inter_pred_params; - - const SubpelParams subpel_params = { sf->x_step_q4, sf->y_step_q4, - pos_x & SCALE_SUBPEL_MASK, - pos_y & SCALE_SUBPEL_MASK }; - - // Get convolve parameters. inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); const int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - av1_init_inter_params( &inter_pred_params, width, height, mi_y >> pd->subsampling_y, mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, filters); - - // Get the inter predictor. - av1_make_inter_predictor(pre, pre_buf->stride, comp_pred8, width, - &inter_pred_params, &subpel_params); + xd->bd, is_cur_buf_hbd(xd), is_intrabc, sf, pre_buf, filters); + av1_enc_build_one_inter_predictor(comp_pred8, width, mv, + &inter_pred_params); return; } } diff --git a/media/libaom/src/aom_dsp/x86/intrapred_avx2.c b/media/libaom/src/aom_dsp/x86/intrapred_avx2.c index aae8173df6..546ee74bb3 100644 --- a/media/libaom/src/aom_dsp/x86/intrapred_avx2.c +++ b/media/libaom/src/aom_dsp/x86/intrapred_avx2.c @@ -12,6 +12,7 @@ #include #include "config/aom_dsp_rtcd.h" +#include "aom_dsp/x86/intrapred_x86.h" #include "aom_dsp/x86/lpf_common_sse2.h" static INLINE __m256i dc_sum_64(const uint8_t *ref) { @@ -419,28 +420,6 @@ void aom_h_predictor_32x32_avx2(uint8_t *dst, ptrdiff_t stride, // ----------------------------------------------------------------------------- // Rectangle - -// TODO(luoyi) The following two functions are shared with intrapred_sse2.c. -// Use a header file, intrapred_common_x86.h -static INLINE __m128i dc_sum_16_sse2(const uint8_t *ref) { - __m128i x = _mm_load_si128((__m128i const *)ref); - const __m128i zero = _mm_setzero_si128(); - x = _mm_sad_epu8(x, zero); - const __m128i high = _mm_unpackhi_epi64(x, x); - return _mm_add_epi16(x, high); -} - -static INLINE __m128i dc_sum_32_sse2(const uint8_t *ref) { - __m128i x0 = _mm_load_si128((__m128i const *)ref); - __m128i x1 = _mm_load_si128((__m128i const *)(ref + 16)); - const __m128i zero = _mm_setzero_si128(); - x0 = _mm_sad_epu8(x0, zero); - x1 = _mm_sad_epu8(x1, zero); - x0 = _mm_add_epi16(x0, x1); - const __m128i high = _mm_unpackhi_epi64(x0, x0); - return _mm_add_epi16(x0, high); -} - void aom_dc_predictor_32x16_avx2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { const __m128i top_sum = dc_sum_32_sse2(above); @@ -2010,7 +1989,7 @@ static void highbd_dr_prediction_32bit_z2_Nx4_avx2( 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; + base_shift = (min_base_x - base_x) >> upsample_above; } int base_min_diff = (min_base_x - base_x + upsample_above) >> upsample_above; @@ -2136,7 +2115,7 @@ static void highbd_dr_prediction_z2_Nx4_avx2( 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; + base_shift = (min_base_x - base_x) >> upsample_above; } int base_min_diff = (min_base_x - base_x + upsample_above) >> upsample_above; @@ -2258,7 +2237,7 @@ static void highbd_dr_prediction_32bit_z2_Nx8_avx2( 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; + base_shift = (min_base_x - base_x) >> upsample_above; } int base_min_diff = (min_base_x - base_x + upsample_above) >> upsample_above; @@ -2408,7 +2387,7 @@ static void highbd_dr_prediction_z2_Nx8_avx2( 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; + base_shift = (min_base_x - base_x) >> upsample_above; } int base_min_diff = (min_base_x - base_x + upsample_above) >> upsample_above; @@ -2565,12 +2544,12 @@ static void highbd_dr_prediction_32bit_z2_HxW_avx2( int y = r + 1; ydx = _mm256_set1_epi32(y * dx); - int base_x = (-y * dx) >> frac_bits_x; + int base_x = ((j << 6) - 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); + if ((base_x) < (min_base_x - 1)) { + base_shift = (min_base_x - base_x - 1); } - int base_min_diff = (min_base_x - base_x - j); + int base_min_diff = (min_base_x - base_x); if (base_min_diff > 16) { base_min_diff = 16; } else { @@ -2580,9 +2559,8 @@ static void highbd_dr_prediction_32bit_z2_HxW_avx2( if (base_shift > 7) { resx[0] = _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_loadu_si128((__m128i *)(above + base_x + base_shift)); + a1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 1)); a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); a1_x128 = @@ -2607,16 +2585,16 @@ static void highbd_dr_prediction_32bit_z2_HxW_avx2( res, _mm256_castsi128_si256(_mm256_extracti128_si256(res, 1))); } int base_shift8 = 0; - if ((base_x + j + 8) < (min_base_x - 1)) { - base_shift8 = (min_base_x - (base_x + j + 8) - 1); + if ((base_x + 8) < (min_base_x - 1)) { + base_shift8 = (min_base_x - (base_x + 8) - 1); } if (base_shift8 > 7) { resx[1] = _mm256_setzero_si256(); } else { a0_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 8 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 8)); a1_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 9 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift8 + 9)); a0_1_x128 = _mm_shuffle_epi8(a0_1_x128, *(__m128i *)HighbdLoadMaskx[base_shift8]); a1_1_x128 = _mm_shuffle_epi8(a1_1_x128, @@ -2762,12 +2740,12 @@ static void highbd_dr_prediction_z2_HxW_avx2( for (int j = 0; j < W; j += 16) { j256 = _mm256_set1_epi16(j); - int base_x = (-y * dx) >> frac_bits_x; + int base_x = ((j << 6) - 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); + if ((base_x) < (min_base_x - 1)) { + base_shift = (min_base_x - (base_x)-1); } - int base_min_diff = (min_base_x - base_x - j); + int base_min_diff = (min_base_x - base_x); if (base_min_diff > 16) { base_min_diff = 16; } else { @@ -2775,9 +2753,8 @@ static void highbd_dr_prediction_z2_HxW_avx2( } if (base_shift < 8) { - 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_loadu_si128((__m128i *)(above + base_x + base_shift)); + a1_x128 = _mm_loadu_si128((__m128i *)(above + base_x + base_shift + 1)); a0_x128 = _mm_shuffle_epi8(a0_x128, *(__m128i *)HighbdLoadMaskx[base_shift]); a1_x128 = @@ -2796,9 +2773,9 @@ static void highbd_dr_prediction_z2_HxW_avx2( } if (base_shift1 < 8) { a0_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift1 + 8 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift1 + 8)); a1_1_x128 = - _mm_loadu_si128((__m128i *)(above + base_x + base_shift1 + 9 + j)); + _mm_loadu_si128((__m128i *)(above + base_x + base_shift1 + 9)); a0_1_x128 = _mm_shuffle_epi8(a0_1_x128, *(__m128i *)HighbdLoadMaskx[base_shift1]); a1_1_x128 = _mm_shuffle_epi8(a1_1_x128, diff --git a/media/libaom/src/aom_dsp/x86/intrapred_sse2.c b/media/libaom/src/aom_dsp/x86/intrapred_sse2.c index 5b2452c8eb..5afef68c39 100644 --- a/media/libaom/src/aom_dsp/x86/intrapred_sse2.c +++ b/media/libaom/src/aom_dsp/x86/intrapred_sse2.c @@ -10,7 +10,7 @@ */ #include - +#include "aom_dsp/x86/intrapred_x86.h" #include "config/aom_dsp_rtcd.h" static INLINE void dc_store_4xh(uint32_t dc, int height, uint8_t *dst, @@ -75,25 +75,6 @@ static INLINE __m128i dc_sum_8(const uint8_t *ref) { return _mm_sad_epu8(x, zero); } -static INLINE __m128i dc_sum_16(const uint8_t *ref) { - __m128i x = _mm_load_si128((__m128i const *)ref); - const __m128i zero = _mm_setzero_si128(); - x = _mm_sad_epu8(x, zero); - const __m128i high = _mm_unpackhi_epi64(x, x); - return _mm_add_epi16(x, high); -} - -static INLINE __m128i dc_sum_32(const uint8_t *ref) { - __m128i x0 = _mm_load_si128((__m128i const *)ref); - __m128i x1 = _mm_load_si128((__m128i const *)(ref + 16)); - const __m128i zero = _mm_setzero_si128(); - x0 = _mm_sad_epu8(x0, zero); - x1 = _mm_sad_epu8(x1, zero); - x0 = _mm_add_epi16(x0, x1); - const __m128i high = _mm_unpackhi_epi64(x0, x0); - return _mm_add_epi16(x0, high); -} - static INLINE __m128i dc_sum_64(const uint8_t *ref) { __m128i x0 = _mm_load_si128((__m128i const *)ref); __m128i x1 = _mm_load_si128((__m128i const *)(ref + 16)); @@ -142,7 +123,7 @@ void aom_dc_predictor_4x8_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_4x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - const __m128i sum_left = dc_sum_16(left); + const __m128i sum_left = dc_sum_16_sse2(left); __m128i sum_above = dc_sum_4(above); sum_above = _mm_add_epi16(sum_left, sum_above); @@ -171,7 +152,7 @@ void aom_dc_predictor_8x4_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_8x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - const __m128i sum_left = dc_sum_16(left); + const __m128i sum_left = dc_sum_16_sse2(left); __m128i sum_above = dc_sum_8(above); sum_above = _mm_add_epi16(sum_above, sum_left); @@ -184,7 +165,7 @@ void aom_dc_predictor_8x16_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_8x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - const __m128i sum_left = dc_sum_32(left); + const __m128i sum_left = dc_sum_32_sse2(left); __m128i sum_above = dc_sum_8(above); sum_above = _mm_add_epi16(sum_above, sum_left); @@ -198,7 +179,7 @@ void aom_dc_predictor_8x32_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_16x4_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { const __m128i sum_left = dc_sum_4(left); - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); sum_above = _mm_add_epi16(sum_above, sum_left); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -211,7 +192,7 @@ void aom_dc_predictor_16x4_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_16x8_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { const __m128i sum_left = dc_sum_8(left); - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); sum_above = _mm_add_epi16(sum_above, sum_left); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -223,8 +204,8 @@ void aom_dc_predictor_16x8_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_16x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - const __m128i sum_left = dc_sum_32(left); - __m128i sum_above = dc_sum_16(above); + const __m128i sum_left = dc_sum_32_sse2(left); + __m128i sum_above = dc_sum_16_sse2(above); sum_above = _mm_add_epi16(sum_left, sum_above); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -237,7 +218,7 @@ void aom_dc_predictor_16x32_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_16x64_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { const __m128i sum_left = dc_sum_64(left); - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); sum_above = _mm_add_epi16(sum_left, sum_above); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -249,7 +230,7 @@ void aom_dc_predictor_16x64_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_32x8_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - __m128i sum_above = dc_sum_32(above); + __m128i sum_above = dc_sum_32_sse2(above); const __m128i sum_left = dc_sum_8(left); sum_above = _mm_add_epi16(sum_above, sum_left); @@ -262,8 +243,8 @@ void aom_dc_predictor_32x8_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_32x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - __m128i sum_above = dc_sum_32(above); - const __m128i sum_left = dc_sum_16(left); + __m128i sum_above = dc_sum_32_sse2(above); + const __m128i sum_left = dc_sum_16_sse2(left); sum_above = _mm_add_epi16(sum_above, sum_left); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -275,7 +256,7 @@ void aom_dc_predictor_32x16_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_32x64_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { - __m128i sum_above = dc_sum_32(above); + __m128i sum_above = dc_sum_32_sse2(above); const __m128i sum_left = dc_sum_64(left); sum_above = _mm_add_epi16(sum_above, sum_left); @@ -302,7 +283,7 @@ void aom_dc_predictor_64x64_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_64x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { __m128i sum_above = dc_sum_64(above); - const __m128i sum_left = dc_sum_32(left); + const __m128i sum_left = dc_sum_32_sse2(left); sum_above = _mm_add_epi16(sum_above, sum_left); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -315,7 +296,7 @@ void aom_dc_predictor_64x32_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_predictor_64x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { __m128i sum_above = dc_sum_64(above); - const __m128i sum_left = dc_sum_16(left); + const __m128i sum_left = dc_sum_16_sse2(left); sum_above = _mm_add_epi16(sum_above, sum_left); uint32_t sum = _mm_cvtsi128_si32(sum_above); @@ -395,7 +376,7 @@ void aom_dc_top_predictor_8x32_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_top_predictor_16x4_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_above = _mm_add_epi16(sum_above, eight); sum_above = _mm_srai_epi16(sum_above, 4); @@ -408,7 +389,7 @@ void aom_dc_top_predictor_16x4_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_top_predictor_16x8_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_above = _mm_add_epi16(sum_above, eight); sum_above = _mm_srai_epi16(sum_above, 4); @@ -422,7 +403,7 @@ void aom_dc_top_predictor_16x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_above = _mm_add_epi16(sum_above, eight); sum_above = _mm_srai_epi16(sum_above, 4); @@ -436,7 +417,7 @@ void aom_dc_top_predictor_16x64_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_16(above); + __m128i sum_above = dc_sum_16_sse2(above); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_above = _mm_add_epi16(sum_above, eight); sum_above = _mm_srai_epi16(sum_above, 4); @@ -449,7 +430,7 @@ void aom_dc_top_predictor_16x64_sse2(uint8_t *dst, ptrdiff_t stride, void aom_dc_top_predictor_32x8_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_32(above); + __m128i sum_above = dc_sum_32_sse2(above); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_above = _mm_add_epi16(sum_above, sixteen); sum_above = _mm_srai_epi16(sum_above, 5); @@ -463,7 +444,7 @@ void aom_dc_top_predictor_32x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_32(above); + __m128i sum_above = dc_sum_32_sse2(above); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_above = _mm_add_epi16(sum_above, sixteen); sum_above = _mm_srai_epi16(sum_above, 5); @@ -477,7 +458,7 @@ void aom_dc_top_predictor_32x64_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)left; - __m128i sum_above = dc_sum_32(above); + __m128i sum_above = dc_sum_32_sse2(above); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_above = _mm_add_epi16(sum_above, sixteen); sum_above = _mm_srai_epi16(sum_above, 5); @@ -550,7 +531,7 @@ void aom_dc_left_predictor_4x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_16(left); + __m128i sum_left = dc_sum_16_sse2(left); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_left = _mm_add_epi16(sum_left, eight); sum_left = _mm_srai_epi16(sum_left, 4); @@ -577,7 +558,7 @@ void aom_dc_left_predictor_8x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_16(left); + __m128i sum_left = dc_sum_16_sse2(left); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_left = _mm_add_epi16(sum_left, eight); sum_left = _mm_srai_epi16(sum_left, 4); @@ -590,7 +571,7 @@ void aom_dc_left_predictor_8x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_32(left); + __m128i sum_left = dc_sum_32_sse2(left); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_left = _mm_add_epi16(sum_left, sixteen); sum_left = _mm_srai_epi16(sum_left, 5); @@ -631,7 +612,7 @@ void aom_dc_left_predictor_16x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_32(left); + __m128i sum_left = dc_sum_32_sse2(left); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_left = _mm_add_epi16(sum_left, sixteen); sum_left = _mm_srai_epi16(sum_left, 5); @@ -673,7 +654,7 @@ void aom_dc_left_predictor_32x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_16(left); + __m128i sum_left = dc_sum_16_sse2(left); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_left = _mm_add_epi16(sum_left, eight); sum_left = _mm_srai_epi16(sum_left, 4); @@ -715,7 +696,7 @@ void aom_dc_left_predictor_64x32_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_32(left); + __m128i sum_left = dc_sum_32_sse2(left); const __m128i sixteen = _mm_set1_epi16((uint16_t)16); sum_left = _mm_add_epi16(sum_left, sixteen); sum_left = _mm_srai_epi16(sum_left, 5); @@ -729,7 +710,7 @@ void aom_dc_left_predictor_64x16_sse2(uint8_t *dst, ptrdiff_t stride, const uint8_t *above, const uint8_t *left) { (void)above; - __m128i sum_left = dc_sum_16(left); + __m128i sum_left = dc_sum_16_sse2(left); const __m128i eight = _mm_set1_epi16((uint16_t)8); sum_left = _mm_add_epi16(sum_left, eight); sum_left = _mm_srai_epi16(sum_left, 4); diff --git a/media/libaom/src/aom_dsp/x86/intrapred_x86.h b/media/libaom/src/aom_dsp/x86/intrapred_x86.h new file mode 100644 index 0000000000..b13f575a76 --- /dev/null +++ b/media/libaom/src/aom_dsp/x86/intrapred_x86.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, 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_AOM_DSP_X86_INTRAPRED_X86_H_ +#define AOM_AOM_DSP_X86_INTRAPRED_X86_H_ + +#include // SSE2 +#include "aom/aom_integer.h" +#include "config/aom_config.h" + +static INLINE __m128i dc_sum_16_sse2(const uint8_t *ref) { + __m128i x = _mm_load_si128((__m128i const *)ref); + const __m128i zero = _mm_setzero_si128(); + x = _mm_sad_epu8(x, zero); + const __m128i high = _mm_unpackhi_epi64(x, x); + return _mm_add_epi16(x, high); +} + +static INLINE __m128i dc_sum_32_sse2(const uint8_t *ref) { + __m128i x0 = _mm_load_si128((__m128i const *)ref); + __m128i x1 = _mm_load_si128((__m128i const *)(ref + 16)); + const __m128i zero = _mm_setzero_si128(); + x0 = _mm_sad_epu8(x0, zero); + x1 = _mm_sad_epu8(x1, zero); + x0 = _mm_add_epi16(x0, x1); + const __m128i high = _mm_unpackhi_epi64(x0, x0); + return _mm_add_epi16(x0, high); +} + +#endif // AOM_AOM_DSP_X86_INTRAPRED_X86_H_ diff --git a/media/libaom/src/aom_dsp/x86/masked_sad4d_ssse3.c b/media/libaom/src/aom_dsp/x86/masked_sad4d_ssse3.c new file mode 100644 index 0000000000..8ef7ee0d7b --- /dev/null +++ b/media/libaom/src/aom_dsp/x86/masked_sad4d_ssse3.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2020, 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_config.h" +#include "config/aom_dsp_rtcd.h" + +#include "aom_dsp/blend.h" +#include "aom/aom_integer.h" +#include "aom_dsp/x86/synonyms.h" + +#include "aom_dsp/x86/masked_sad_intrin_ssse3.h" + +#define MASK_SAD16XH_ONE_REF(idx) \ + a = _mm_loadu_si128((const __m128i *)&ref##idx[x]); \ + data_l = _mm_unpacklo_epi8(a, b); \ + mask_l = _mm_unpacklo_epi8(m, m_inv); \ + pred_l = _mm_maddubs_epi16(data_l, mask_l); \ + pred_l = xx_roundn_epu16(pred_l, AOM_BLEND_A64_ROUND_BITS); \ + \ + data_r = _mm_unpackhi_epi8(a, b); \ + mask_r = _mm_unpackhi_epi8(m, m_inv); \ + pred_r = _mm_maddubs_epi16(data_r, mask_r); \ + pred_r = xx_roundn_epu16(pred_r, AOM_BLEND_A64_ROUND_BITS); \ + \ + pred = _mm_packus_epi16(pred_l, pred_r); \ + res##idx = _mm_add_epi32(res##idx, _mm_sad_epu8(pred, src)); + +static INLINE void masked_sadx4d_ssse3(const uint8_t *src_ptr, int src_stride, + const uint8_t *a_ptr[], int a_stride, + const uint8_t *b_ptr, int b_stride, + const uint8_t *m_ptr, int m_stride, + int width, int height, int inv_mask, + unsigned sad_array[]) { + int x, y; + __m128i a; + __m128i data_l, data_r, mask_l, mask_r, pred_l, pred_r, pred; + const __m128i mask_max = _mm_set1_epi8((1 << AOM_BLEND_A64_ROUND_BITS)); + __m128i res0 = _mm_setzero_si128(); + __m128i res1 = _mm_setzero_si128(); + __m128i res2 = _mm_setzero_si128(); + __m128i res3 = _mm_setzero_si128(); + const uint8_t *ref0 = a_ptr[0]; + const uint8_t *ref1 = a_ptr[1]; + const uint8_t *ref2 = a_ptr[2]; + const uint8_t *ref3 = a_ptr[3]; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x += 16) { + const __m128i src = _mm_loadu_si128((const __m128i *)&src_ptr[x]); + const __m128i b = _mm_loadu_si128((const __m128i *)&b_ptr[x]); + const __m128i m_copy = _mm_loadu_si128((const __m128i *)&m_ptr[x]); + __m128i m_inv = _mm_sub_epi8(mask_max, m_copy); + __m128i m = inv_mask ? m_inv : m_copy; + m_inv = inv_mask ? m_copy : m_inv; + + MASK_SAD16XH_ONE_REF(0) + MASK_SAD16XH_ONE_REF(1) + MASK_SAD16XH_ONE_REF(2) + MASK_SAD16XH_ONE_REF(3) + } + + src_ptr += src_stride; + ref0 += a_stride; + ref1 += a_stride; + ref2 += a_stride; + ref3 += a_stride; + b_ptr += b_stride; + m_ptr += m_stride; + } + res0 = _mm_add_epi32(_mm_unpacklo_epi32(res0, res1), + _mm_unpackhi_epi32(res0, res1)); + res2 = _mm_add_epi32(_mm_unpacklo_epi32(res2, res3), + _mm_unpackhi_epi32(res2, res3)); + + res0 = _mm_unpacklo_epi64(res0, res2); + _mm_storeu_si128((__m128i *)sad_array, res0); +} + +#define MASK_SAD8XH_ONE_REF(idx) \ + const __m128i a##idx##0 = _mm_loadl_epi64((__m128i *)ref##idx); \ + const __m128i a##idx##1 = _mm_loadl_epi64((__m128i *)(ref##idx + a_stride)); \ + data_l = _mm_unpacklo_epi8(a##idx##0, b0); \ + mask_l = _mm_unpacklo_epi8(m, m_inv); \ + pred_l = _mm_maddubs_epi16(data_l, mask_l); \ + pred_l = xx_roundn_epu16(pred_l, AOM_BLEND_A64_ROUND_BITS); \ + \ + data_r = _mm_unpacklo_epi8(a##idx##1, b1); \ + mask_r = _mm_unpackhi_epi8(m, m_inv); \ + pred_r = _mm_maddubs_epi16(data_r, mask_r); \ + pred_r = xx_roundn_epu16(pred_r, AOM_BLEND_A64_ROUND_BITS); \ + \ + pred = _mm_packus_epi16(pred_l, pred_r); \ + res##idx = _mm_add_epi32(res##idx, _mm_sad_epu8(pred, src)); + +void aom_masked_sad8xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_array[], int a_stride, + const uint8_t *b_ptr, int b_stride, + const uint8_t *m_ptr, int m_stride, int height, + int inv_mask, unsigned sad_array[]) { + const uint8_t *ref0 = ref_array[0]; + const uint8_t *ref1 = ref_array[1]; + const uint8_t *ref2 = ref_array[2]; + const uint8_t *ref3 = ref_array[3]; + __m128i data_l, data_r, pred_l, pred_r, mask_l, mask_r, pred; + __m128i res0 = _mm_setzero_si128(); + __m128i res1 = _mm_setzero_si128(); + __m128i res2 = _mm_setzero_si128(); + __m128i res3 = _mm_setzero_si128(); + const __m128i mask_max = _mm_set1_epi8((1 << AOM_BLEND_A64_ROUND_BITS)); + + for (int y = 0; y < height; y += 2) { + const __m128i src = _mm_unpacklo_epi64( + _mm_loadl_epi64((const __m128i *)src_ptr), + _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride))); + const __m128i b0 = _mm_loadl_epi64((__m128i *)b_ptr); + const __m128i b1 = _mm_loadl_epi64((__m128i *)(b_ptr + b_stride)); + const __m128i m0 = _mm_loadl_epi64((__m128i *)m_ptr); + const __m128i m1 = _mm_loadl_epi64((__m128i *)(m_ptr + m_stride)); + __m128i m_copy = _mm_unpacklo_epi64(m0, m1); + __m128i m_inv = _mm_sub_epi8(mask_max, m_copy); + __m128i m = inv_mask ? m_inv : m_copy; + m_inv = inv_mask ? m_copy : m_inv; + + MASK_SAD8XH_ONE_REF(0) + MASK_SAD8XH_ONE_REF(1) + MASK_SAD8XH_ONE_REF(2) + MASK_SAD8XH_ONE_REF(3) + + ref0 += 2 * a_stride; + ref1 += 2 * a_stride; + ref2 += 2 * a_stride; + ref3 += 2 * a_stride; + src_ptr += 2 * src_stride; + b_ptr += 2 * b_stride; + m_ptr += 2 * m_stride; + } + res0 = _mm_add_epi32(_mm_unpacklo_epi32(res0, res1), + _mm_unpackhi_epi32(res0, res1)); + res2 = _mm_add_epi32(_mm_unpacklo_epi32(res2, res3), + _mm_unpackhi_epi32(res2, res3)); + res0 = _mm_unpacklo_epi64(res0, res2); + _mm_storeu_si128((__m128i *)sad_array, res0); +} + +#define MASK_SAD4XH_ONE_REF(idx) \ + a = _mm_unpacklo_epi32(_mm_cvtsi32_si128(*(uint32_t *)ref##idx), \ + _mm_cvtsi32_si128(*(uint32_t *)&ref##idx[a_stride])); \ + data = _mm_unpacklo_epi8(a, b); \ + mask = _mm_unpacklo_epi8(m, m_inv); \ + pred = _mm_maddubs_epi16(data, mask); \ + pred = xx_roundn_epu16(pred, AOM_BLEND_A64_ROUND_BITS); \ + \ + pred = _mm_packus_epi16(pred, _mm_setzero_si128()); \ + res##idx = _mm_add_epi32(res##idx, _mm_sad_epu8(pred, src)); + +void aom_masked_sad4xhx4d_ssse3(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_array[], int a_stride, + const uint8_t *b_ptr, int b_stride, + const uint8_t *m_ptr, int m_stride, int height, + int inv_mask, unsigned sad_array[]) { + const uint8_t *ref0 = ref_array[0]; + const uint8_t *ref1 = ref_array[1]; + const uint8_t *ref2 = ref_array[2]; + const uint8_t *ref3 = ref_array[3]; + __m128i data, pred, mask; + __m128i res0 = _mm_setzero_si128(); + __m128i res1 = _mm_setzero_si128(); + __m128i res2 = _mm_setzero_si128(); + __m128i res3 = _mm_setzero_si128(); + __m128i a; + const __m128i mask_max = _mm_set1_epi8((1 << AOM_BLEND_A64_ROUND_BITS)); + + for (int y = 0; y < height; y += 2) { + const __m128i src = _mm_unpacklo_epi32( + _mm_cvtsi32_si128(*(uint32_t *)src_ptr), + _mm_cvtsi32_si128(*(uint32_t *)&src_ptr[src_stride])); + const __m128i b = + _mm_unpacklo_epi32(_mm_cvtsi32_si128(*(uint32_t *)b_ptr), + _mm_cvtsi32_si128(*(uint32_t *)&b_ptr[b_stride])); + const __m128i m_copy = + _mm_unpacklo_epi32(_mm_cvtsi32_si128(*(uint32_t *)m_ptr), + _mm_cvtsi32_si128(*(uint32_t *)&m_ptr[m_stride])); + + __m128i m_inv = _mm_sub_epi8(mask_max, m_copy); + __m128i m = inv_mask ? m_inv : m_copy; + m_inv = inv_mask ? m_copy : m_inv; + + MASK_SAD4XH_ONE_REF(0) + MASK_SAD4XH_ONE_REF(1) + MASK_SAD4XH_ONE_REF(2) + MASK_SAD4XH_ONE_REF(3) + + ref0 += 2 * a_stride; + ref1 += 2 * a_stride; + ref2 += 2 * a_stride; + ref3 += 2 * a_stride; + src_ptr += 2 * src_stride; + b_ptr += 2 * b_stride; + m_ptr += 2 * m_stride; + } + res0 = _mm_unpacklo_epi32(res0, res1); + res2 = _mm_unpacklo_epi32(res2, res3); + res0 = _mm_unpacklo_epi64(res0, res2); + _mm_storeu_si128((__m128i *)sad_array, res0); +} + +#define MASKSADMXN_SSSE3(m, n) \ + void aom_masked_sad##m##x##n##x4d_ssse3( \ + const uint8_t *src, int src_stride, const uint8_t *ref[], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int inv_mask, unsigned sad_array[]) { \ + masked_sadx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, m, msk, \ + msk_stride, m, n, inv_mask, sad_array); \ + } + +#define MASKSAD8XN_SSSE3(n) \ + void aom_masked_sad8x##n##x4d_ssse3( \ + const uint8_t *src, int src_stride, const uint8_t *ref[], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int inv_mask, unsigned sad_array[]) { \ + aom_masked_sad8xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, \ + 8, msk, msk_stride, n, inv_mask, sad_array); \ + } + +#define MASKSAD4XN_SSSE3(n) \ + void aom_masked_sad4x##n##x4d_ssse3( \ + const uint8_t *src, int src_stride, const uint8_t *ref[], \ + int ref_stride, const uint8_t *second_pred, const uint8_t *msk, \ + int msk_stride, int inv_mask, unsigned sad_array[]) { \ + aom_masked_sad4xhx4d_ssse3(src, src_stride, ref, ref_stride, second_pred, \ + 4, msk, msk_stride, n, inv_mask, sad_array); \ + } + +MASKSADMXN_SSSE3(128, 128) +MASKSADMXN_SSSE3(128, 64) +MASKSADMXN_SSSE3(64, 128) +MASKSADMXN_SSSE3(64, 64) +MASKSADMXN_SSSE3(64, 32) +MASKSADMXN_SSSE3(32, 64) +MASKSADMXN_SSSE3(32, 32) +MASKSADMXN_SSSE3(32, 16) +MASKSADMXN_SSSE3(16, 32) +MASKSADMXN_SSSE3(16, 16) +MASKSADMXN_SSSE3(16, 8) +MASKSAD8XN_SSSE3(16) +MASKSAD8XN_SSSE3(8) +MASKSAD8XN_SSSE3(4) +MASKSAD4XN_SSSE3(8) +MASKSAD4XN_SSSE3(4) +MASKSAD4XN_SSSE3(16) +MASKSADMXN_SSSE3(16, 4) +MASKSAD8XN_SSSE3(32) +MASKSADMXN_SSSE3(32, 8) +MASKSADMXN_SSSE3(16, 64) +MASKSADMXN_SSSE3(64, 16) diff --git a/media/libaom/src/aom_dsp/x86/masked_sad_intrin_avx2.c b/media/libaom/src/aom_dsp/x86/masked_sad_intrin_avx2.c index 774fab6d9b..60f0ab3390 100644 --- a/media/libaom/src/aom_dsp/x86/masked_sad_intrin_avx2.c +++ b/media/libaom/src/aom_dsp/x86/masked_sad_intrin_avx2.c @@ -64,7 +64,7 @@ static INLINE unsigned int masked_sad32xh_avx2( res = _mm256_hadd_epi32(res, res); res = _mm256_hadd_epi32(res, res); int32_t sad = _mm256_extract_epi32(res, 0); - return (sad + 31) >> 6; + return sad; } static INLINE __m256i xx_loadu2_m128i(const void *hi, const void *lo) { @@ -117,7 +117,7 @@ static INLINE unsigned int masked_sad16xh_avx2( res = _mm256_hadd_epi32(res, res); res = _mm256_hadd_epi32(res, res); int32_t sad = _mm256_extract_epi32(res, 0); - return (sad + 31) >> 6; + return sad; } static INLINE unsigned int aom_masked_sad_avx2( @@ -253,7 +253,7 @@ static INLINE unsigned int highbd_masked_sad8xh_avx2( res = _mm256_hadd_epi32(res, res); res = _mm256_hadd_epi32(res, res); int sad = _mm256_extract_epi32(res, 0) + _mm256_extract_epi32(res, 4); - return (sad + 31) >> 6; + return sad; } static INLINE unsigned int highbd_masked_sad16xh_avx2( @@ -311,7 +311,7 @@ static INLINE unsigned int highbd_masked_sad16xh_avx2( res = _mm256_hadd_epi32(res, res); res = _mm256_hadd_epi32(res, res); int sad = _mm256_extract_epi32(res, 0) + _mm256_extract_epi32(res, 4); - return (sad + 31) >> 6; + return sad; } static INLINE unsigned int aom_highbd_masked_sad_avx2( diff --git a/media/libaom/src/aom_dsp/x86/masked_sad_intrin_ssse3.c b/media/libaom/src/aom_dsp/x86/masked_sad_intrin_ssse3.c index a179f2ee3d..7168277963 100644 --- a/media/libaom/src/aom_dsp/x86/masked_sad_intrin_ssse3.c +++ b/media/libaom/src/aom_dsp/x86/masked_sad_intrin_ssse3.c @@ -134,7 +134,7 @@ static INLINE unsigned int masked_sad_ssse3(const uint8_t *src_ptr, // At this point, we have two 32-bit partial SADs in lanes 0 and 2 of 'res'. int32_t sad = _mm_cvtsi128_si32(res) + _mm_cvtsi128_si32(_mm_srli_si128(res, 8)); - return (sad + 31) >> 6; + return sad; } unsigned int aom_masked_sad8xh_ssse3(const uint8_t *src_ptr, int src_stride, @@ -179,7 +179,7 @@ unsigned int aom_masked_sad8xh_ssse3(const uint8_t *src_ptr, int src_stride, } int32_t sad = _mm_cvtsi128_si32(res) + _mm_cvtsi128_si32(_mm_srli_si128(res, 8)); - return (sad + 31) >> 6; + return sad; } unsigned int aom_masked_sad4xh_ssse3(const uint8_t *src_ptr, int src_stride, @@ -223,7 +223,7 @@ unsigned int aom_masked_sad4xh_ssse3(const uint8_t *src_ptr, int src_stride, } // At this point, the SAD is stored in lane 0 of 'res' int32_t sad = _mm_cvtsi128_si32(res); - return (sad + 31) >> 6; + return sad; } // For width a multiple of 8 @@ -338,7 +338,7 @@ static INLINE unsigned int highbd_masked_sad_ssse3( res = _mm_hadd_epi32(res, res); res = _mm_hadd_epi32(res, res); int sad = _mm_cvtsi128_si32(res); - return (sad + 31) >> 6; + return sad; } unsigned int aom_highbd_masked_sad4xh_ssse3(const uint8_t *src8, int src_stride, @@ -398,5 +398,5 @@ unsigned int aom_highbd_masked_sad4xh_ssse3(const uint8_t *src8, int src_stride, res = _mm_hadd_epi32(res, res); res = _mm_hadd_epi32(res, res); int sad = _mm_cvtsi128_si32(res); - return (sad + 31) >> 6; + return sad; } diff --git a/media/libaom/src/aom_dsp/x86/sad4d_avx2.c b/media/libaom/src/aom_dsp/x86/sad4d_avx2.c index f662b62b16..0771252584 100644 --- a/media/libaom/src/aom_dsp/x86/sad4d_avx2.c +++ b/media/libaom/src/aom_dsp/x86/sad4d_avx2.c @@ -14,41 +14,43 @@ #include "aom/aom_integer.h" -void aom_sad32x32x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { +void aom_sadMxNx4d_avx2(int M, int N, const uint8_t *src, int src_stride, + const uint8_t *const ref[4], int ref_stride, + uint32_t res[4]) { __m256i src_reg, ref0_reg, ref1_reg, ref2_reg, ref3_reg; __m256i sum_ref0, sum_ref1, sum_ref2, sum_ref3; - __m256i sum_mlow, sum_mhigh; - int i; + int i, j; const uint8_t *ref0, *ref1, *ref2, *ref3; ref0 = ref[0]; ref1 = ref[1]; ref2 = ref[2]; ref3 = ref[3]; - sum_ref0 = _mm256_set1_epi16(0); - sum_ref1 = _mm256_set1_epi16(0); - sum_ref2 = _mm256_set1_epi16(0); - sum_ref3 = _mm256_set1_epi16(0); - for (i = 0; i < 32; i++) { - // load src and all refs - src_reg = _mm256_loadu_si256((const __m256i *)src); - ref0_reg = _mm256_loadu_si256((const __m256i *)ref0); - ref1_reg = _mm256_loadu_si256((const __m256i *)ref1); - ref2_reg = _mm256_loadu_si256((const __m256i *)ref2); - ref3_reg = _mm256_loadu_si256((const __m256i *)ref3); - // sum of the absolute differences between every ref-i to src - ref0_reg = _mm256_sad_epu8(ref0_reg, src_reg); - ref1_reg = _mm256_sad_epu8(ref1_reg, src_reg); - ref2_reg = _mm256_sad_epu8(ref2_reg, src_reg); - ref3_reg = _mm256_sad_epu8(ref3_reg, src_reg); - // sum every ref-i - sum_ref0 = _mm256_add_epi32(sum_ref0, ref0_reg); - sum_ref1 = _mm256_add_epi32(sum_ref1, ref1_reg); - sum_ref2 = _mm256_add_epi32(sum_ref2, ref2_reg); - sum_ref3 = _mm256_add_epi32(sum_ref3, ref3_reg); + sum_ref0 = _mm256_setzero_si256(); + sum_ref2 = _mm256_setzero_si256(); + sum_ref1 = _mm256_setzero_si256(); + sum_ref3 = _mm256_setzero_si256(); + for (i = 0; i < N; i++) { + for (j = 0; j < M; j += 32) { + // load src and all refs + src_reg = _mm256_loadu_si256((const __m256i *)(src + j)); + ref0_reg = _mm256_loadu_si256((const __m256i *)(ref0 + j)); + ref1_reg = _mm256_loadu_si256((const __m256i *)(ref1 + j)); + ref2_reg = _mm256_loadu_si256((const __m256i *)(ref2 + j)); + ref3_reg = _mm256_loadu_si256((const __m256i *)(ref3 + j)); + + // sum of the absolute differences between every ref-i to src + ref0_reg = _mm256_sad_epu8(ref0_reg, src_reg); + ref1_reg = _mm256_sad_epu8(ref1_reg, src_reg); + ref2_reg = _mm256_sad_epu8(ref2_reg, src_reg); + ref3_reg = _mm256_sad_epu8(ref3_reg, src_reg); + // sum every ref-i + sum_ref0 = _mm256_add_epi32(sum_ref0, ref0_reg); + sum_ref1 = _mm256_add_epi32(sum_ref1, ref1_reg); + sum_ref2 = _mm256_add_epi32(sum_ref2, ref2_reg); + sum_ref3 = _mm256_add_epi32(sum_ref3, ref3_reg); + } src += src_stride; ref0 += ref_stride; ref1 += ref_stride; @@ -57,6 +59,7 @@ void aom_sad32x32x4d_avx2(const uint8_t *src, int src_stride, } { __m128i sum; + __m256i sum_mlow, sum_mhigh; // in sum_ref-i the result is saved in the first 4 bytes // the other 4 bytes are zeroed. // sum_ref1 and sum_ref3 are shifted left by 4 bytes @@ -80,139 +83,24 @@ void aom_sad32x32x4d_avx2(const uint8_t *src, int src_stride, _mm_storeu_si128((__m128i *)(res), sum); } - _mm256_zeroupper(); } -void aom_sad64x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - __m256i src_reg, srcnext_reg, ref0_reg, ref0next_reg; - __m256i ref1_reg, ref1next_reg, ref2_reg, ref2next_reg; - __m256i ref3_reg, ref3next_reg; - __m256i sum_ref0, sum_ref1, sum_ref2, sum_ref3; - __m256i sum_mlow, sum_mhigh; - int i; - const uint8_t *ref0, *ref1, *ref2, *ref3; - - ref0 = ref[0]; - ref1 = ref[1]; - ref2 = ref[2]; - ref3 = ref[3]; - sum_ref0 = _mm256_set1_epi16(0); - sum_ref1 = _mm256_set1_epi16(0); - sum_ref2 = _mm256_set1_epi16(0); - sum_ref3 = _mm256_set1_epi16(0); - for (i = 0; i < 64; i++) { - // load 64 bytes from src and all refs - src_reg = _mm256_loadu_si256((const __m256i *)src); - srcnext_reg = _mm256_loadu_si256((const __m256i *)(src + 32)); - ref0_reg = _mm256_loadu_si256((const __m256i *)ref0); - ref0next_reg = _mm256_loadu_si256((const __m256i *)(ref0 + 32)); - ref1_reg = _mm256_loadu_si256((const __m256i *)ref1); - ref1next_reg = _mm256_loadu_si256((const __m256i *)(ref1 + 32)); - ref2_reg = _mm256_loadu_si256((const __m256i *)ref2); - ref2next_reg = _mm256_loadu_si256((const __m256i *)(ref2 + 32)); - ref3_reg = _mm256_loadu_si256((const __m256i *)ref3); - ref3next_reg = _mm256_loadu_si256((const __m256i *)(ref3 + 32)); - // sum of the absolute differences between every ref-i to src - ref0_reg = _mm256_sad_epu8(ref0_reg, src_reg); - ref1_reg = _mm256_sad_epu8(ref1_reg, src_reg); - ref2_reg = _mm256_sad_epu8(ref2_reg, src_reg); - ref3_reg = _mm256_sad_epu8(ref3_reg, src_reg); - ref0next_reg = _mm256_sad_epu8(ref0next_reg, srcnext_reg); - ref1next_reg = _mm256_sad_epu8(ref1next_reg, srcnext_reg); - ref2next_reg = _mm256_sad_epu8(ref2next_reg, srcnext_reg); - ref3next_reg = _mm256_sad_epu8(ref3next_reg, srcnext_reg); - - // sum every ref-i - sum_ref0 = _mm256_add_epi32(sum_ref0, ref0_reg); - sum_ref1 = _mm256_add_epi32(sum_ref1, ref1_reg); - sum_ref2 = _mm256_add_epi32(sum_ref2, ref2_reg); - sum_ref3 = _mm256_add_epi32(sum_ref3, ref3_reg); - sum_ref0 = _mm256_add_epi32(sum_ref0, ref0next_reg); - sum_ref1 = _mm256_add_epi32(sum_ref1, ref1next_reg); - sum_ref2 = _mm256_add_epi32(sum_ref2, ref2next_reg); - sum_ref3 = _mm256_add_epi32(sum_ref3, ref3next_reg); - src += src_stride; - ref0 += ref_stride; - ref1 += ref_stride; - ref2 += ref_stride; - ref3 += ref_stride; +#define sadMxN_avx2(m, n) \ + void aom_sad##m##x##n##x4d_avx2(const uint8_t *src, int src_stride, \ + const uint8_t *const ref[4], int ref_stride, \ + uint32_t res[4]) { \ + aom_sadMxNx4d_avx2(m, n, src, src_stride, ref, ref_stride, res); \ } - { - __m128i sum; - // in sum_ref-i the result is saved in the first 4 bytes - // the other 4 bytes are zeroed. - // sum_ref1 and sum_ref3 are shifted left by 4 bytes - sum_ref1 = _mm256_slli_si256(sum_ref1, 4); - sum_ref3 = _mm256_slli_si256(sum_ref3, 4); +sadMxN_avx2(32, 8); +sadMxN_avx2(32, 16); +sadMxN_avx2(32, 32); +sadMxN_avx2(32, 64); - // merge sum_ref0 and sum_ref1 also sum_ref2 and sum_ref3 - sum_ref0 = _mm256_or_si256(sum_ref0, sum_ref1); - sum_ref2 = _mm256_or_si256(sum_ref2, sum_ref3); +sadMxN_avx2(64, 16); +sadMxN_avx2(64, 32); +sadMxN_avx2(64, 64); +sadMxN_avx2(64, 128); - // merge every 64 bit from each sum_ref-i - sum_mlow = _mm256_unpacklo_epi64(sum_ref0, sum_ref2); - sum_mhigh = _mm256_unpackhi_epi64(sum_ref0, sum_ref2); - - // add the low 64 bit to the high 64 bit - sum_mlow = _mm256_add_epi32(sum_mlow, sum_mhigh); - - // add the low 128 bit to the high 128 bit - sum = _mm_add_epi32(_mm256_castsi256_si128(sum_mlow), - _mm256_extractf128_si256(sum_mlow, 1)); - - _mm_storeu_si128((__m128i *)(res), sum); - } - _mm256_zeroupper(); -} - -void aom_sad32x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - const uint8_t *rf[4]; - uint32_t sum0[4]; - uint32_t sum1[4]; - - rf[0] = ref[0]; - rf[1] = ref[1]; - rf[2] = ref[2]; - rf[3] = ref[3]; - aom_sad32x32x4d_avx2(src, src_stride, rf, ref_stride, sum0); - src += src_stride << 5; - rf[0] += ref_stride << 5; - rf[1] += ref_stride << 5; - rf[2] += ref_stride << 5; - rf[3] += ref_stride << 5; - aom_sad32x32x4d_avx2(src, src_stride, rf, ref_stride, sum1); - res[0] = sum0[0] + sum1[0]; - res[1] = sum0[1] + sum1[1]; - res[2] = sum0[2] + sum1[2]; - res[3] = sum0[3] + sum1[3]; -} - -void aom_sad64x32x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - const uint8_t *rf[4]; - uint32_t sum0[4]; - uint32_t sum1[4]; - unsigned int half_width = 32; - - rf[0] = ref[0]; - rf[1] = ref[1]; - rf[2] = ref[2]; - rf[3] = ref[3]; - aom_sad32x32x4d_avx2(src, src_stride, rf, ref_stride, sum0); - src += half_width; - rf[0] += half_width; - rf[1] += half_width; - rf[2] += half_width; - rf[3] += half_width; - aom_sad32x32x4d_avx2(src, src_stride, rf, ref_stride, sum1); - res[0] = sum0[0] + sum1[0]; - res[1] = sum0[1] + sum1[1]; - res[2] = sum0[2] + sum1[2]; - res[3] = sum0[3] + sum1[3]; -} +sadMxN_avx2(128, 64); +sadMxN_avx2(128, 128); diff --git a/media/libaom/src/aom_dsp/x86/sad4d_sse2.asm b/media/libaom/src/aom_dsp/x86/sad4d_sse2.asm index 55a856985a..a9043742d4 100644 --- a/media/libaom/src/aom_dsp/x86/sad4d_sse2.asm +++ b/media/libaom/src/aom_dsp/x86/sad4d_sse2.asm @@ -15,15 +15,85 @@ SECTION .text -; PROCESS_4x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_4x2x4 5-6 0 - movd m0, [srcq +%2] +%macro AVG_4x2x4 2 + movh m2, [second_predq] + movlhps m2, m2 + pavgb %1, m2 + pavgb %2, m2 + lea second_predq, [second_predq+8] +%endmacro +; 'mflag' affect a lot how the code works. +; +; When 'mflag' is false, the 'src_strideq' resides in register, +; [srcq + src_strideq + offset] is allowed, so we can simply +; use such form to access src memory and don't bother to update +; 'srcq' at each line. We only update 'srcq' each two-lines using +; a compact LEA instruction like [srcq+src_strideq*2]. +; +; When 'mflag' is true, the 'src_strideq' resides in memory. +; we cannot use above form to access memory, we have to update +; 'srcq' at each line break. As we process two parts (first,second) +; together in each macro function, the second part may also sit +; in the next line, which means we also need to possibly add +; one 'src_strideq' to 'srcq' before processing second part. + +%macro HANDLE_FIRST_OFFSET 2 + %define first_offset %2 + %if mflag == 0 && %1 == 1 + %define first_offset (src_strideq + %2) + %endif +%endmacro + +; first_extraline, second_extraline, in_line_offset +%macro HANDLE_SECOND_OFFSET 3 + %define second_offset %3 + %if mflag && %1 == 0 && %2 == 1 + add srcq, src_strideq + %endif + %if mflag == 0 && %2 == 1 + %define second_offset (src_strideq + %3) + %endif +%endmacro + +; Notes for line_ending: +; 0 -- not a line ending +; 1 -- line ending of a odd line [line numbers starts from one] +; 2 -- line ending of a even line +; This is specically designed to handle when src_strideq is a +; memory position, under such case, we can not accomplish +; complex address calculation using LEA, and fall back to +; using simple ADD instruction at each line ending. +%macro ADVANCE_END_OF_LINE 1 + %if mflag + add srcq, src_strideq + %endif + %if mflag == 0 && %1 == 2 + lea srcq, [srcq +src_strideq*2] + %endif + + %if %1 == 2 + lea ref1q, [ref1q+ref_strideq*2] + lea ref2q, [ref2q+ref_strideq*2] + lea ref3q, [ref3q+ref_strideq*2] + lea ref4q, [ref4q+ref_strideq*2] + %endif +%endmacro + +; Please note that the second_offset of src is for in_line_offset, +; so it is less than src_stride. +; PROCESS_4x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first, second}_extraline, line_ending +%macro PROCESS_4x2x4 9 + HANDLE_FIRST_OFFSET %7, %2 + movd m0, [srcq + first_offset] + HANDLE_SECOND_OFFSET %7, %8, %4 %if %1 == 1 movd m6, [ref1q+%3] movd m4, [ref2q+%3] movd m7, [ref3q+%3] movd m5, [ref4q+%3] - movd m1, [srcq +%4] + + movd m1, [srcq + second_offset] movd m2, [ref1q+%5] punpckldq m0, m1 punpckldq m6, m2 @@ -36,6 +106,9 @@ SECTION .text movlhps m0, m0 movlhps m6, m4 movlhps m7, m5 +%if %6 == 1 + AVG_4x2x4 m6, m7 +%endif psadbw m6, m0 psadbw m7, m0 %else @@ -51,38 +124,48 @@ SECTION .text movd m4, [ref4q+%3] movd m5, [ref4q+%5] punpckldq m4, m5 - movd m5, [srcq +%4] + movd m5, [srcq + second_offset] punpckldq m0, m5 movlhps m0, m0 movlhps m1, m2 movlhps m3, m4 +%if %6 == 1 + AVG_4x2x4 m1, m3 +%endif psadbw m1, m0 psadbw m3, m0 paddd m6, m1 paddd m7, m3 %endif -%if %6 == 1 - lea srcq, [srcq +src_strideq*2] - lea ref1q, [ref1q+ref_strideq*2] - lea ref2q, [ref2q+ref_strideq*2] - lea ref3q, [ref3q+ref_strideq*2] - lea ref4q, [ref4q+ref_strideq*2] +%if %9 > 0 + ADVANCE_END_OF_LINE %9 %endif %endmacro -; PROCESS_8x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_8x2x4 5-6 0 - movh m0, [srcq +%2] +; PROCESS_8x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first,second}_extraline, line_ending +%macro PROCESS_8x2x4 9 + HANDLE_FIRST_OFFSET %7, %2 + movh m0, [srcq + first_offset] + HANDLE_SECOND_OFFSET %7, %8, %4 %if %1 == 1 movh m4, [ref1q+%3] movh m5, [ref2q+%3] movh m6, [ref3q+%3] movh m7, [ref4q+%3] - movhps m0, [srcq +%4] + movhps m0, [srcq + second_offset] movhps m4, [ref1q+%5] movhps m5, [ref2q+%5] movhps m6, [ref3q+%5] movhps m7, [ref4q+%5] +%if %6 == 1 + movu m3, [second_predq] + pavgb m4, m3 + pavgb m5, m3 + pavgb m6, m3 + pavgb m7, m3 + lea second_predq, [second_predq+mmsize] +%endif psadbw m4, m0 psadbw m5, m0 psadbw m6, m0 @@ -90,105 +173,148 @@ SECTION .text %else movh m1, [ref1q+%3] movh m2, [ref2q+%3] - movh m3, [ref3q+%3] - movhps m0, [srcq +%4] + movhps m0, [srcq + second_offset] movhps m1, [ref1q+%5] movhps m2, [ref2q+%5] - movhps m3, [ref3q+%5] +%if %6 == 1 + movu m3, [second_predq] + pavgb m1, m3 + pavgb m2, m3 +%endif psadbw m1, m0 psadbw m2, m0 - psadbw m3, m0 paddd m4, m1 - movh m1, [ref4q+%3] - movhps m1, [ref4q+%5] paddd m5, m2 - paddd m6, m3 - psadbw m1, m0 - paddd m7, m1 -%endif + + movh m1, [ref3q+%3] + movhps m1, [ref3q+%5] + movh m2, [ref4q+%3] + movhps m2, [ref4q+%5] %if %6 == 1 - lea srcq, [srcq +src_strideq*2] - lea ref1q, [ref1q+ref_strideq*2] - lea ref2q, [ref2q+ref_strideq*2] - lea ref3q, [ref3q+ref_strideq*2] - lea ref4q, [ref4q+ref_strideq*2] + pavgb m1, m3 + pavgb m2, m3 + lea second_predq, [second_predq+mmsize] +%endif + psadbw m1, m0 + psadbw m2, m0 + paddd m6, m1 + paddd m7, m2 +%endif +%if %9 > 0 + ADVANCE_END_OF_LINE %9 %endif %endmacro -; PROCESS_16x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_16x2x4 5-6 0 +; PROCESS_16x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first,second}_extraline, line_ending +%macro PROCESS_16x2x4 9 ; 1st 16 px - mova m0, [srcq +%2] + HANDLE_FIRST_OFFSET %7, %2 + mova m0, [srcq + first_offset] + HANDLE_SECOND_OFFSET %7, %8, %4 %if %1 == 1 movu m4, [ref1q+%3] movu m5, [ref2q+%3] movu m6, [ref3q+%3] movu m7, [ref4q+%3] +%if %6 == 1 + movu m3, [second_predq] + pavgb m4, m3 + pavgb m5, m3 + pavgb m6, m3 + pavgb m7, m3 + lea second_predq, [second_predq+mmsize] +%endif psadbw m4, m0 psadbw m5, m0 psadbw m6, m0 psadbw m7, m0 -%else +%else ; %1 == 1 movu m1, [ref1q+%3] movu m2, [ref2q+%3] - movu m3, [ref3q+%3] +%if %6 == 1 + movu m3, [second_predq] + pavgb m1, m3 + pavgb m2, m3 +%endif psadbw m1, m0 psadbw m2, m0 - psadbw m3, m0 paddd m4, m1 - movu m1, [ref4q+%3] paddd m5, m2 - paddd m6, m3 - psadbw m1, m0 - paddd m7, m1 + + movu m1, [ref3q+%3] + movu m2, [ref4q+%3] +%if %6 == 1 + pavgb m1, m3 + pavgb m2, m3 + lea second_predq, [second_predq+mmsize] %endif + psadbw m1, m0 + psadbw m2, m0 + paddd m6, m1 + paddd m7, m2 +%endif ; %1 == 1 ; 2nd 16 px - mova m0, [srcq +%4] + mova m0, [srcq + second_offset] movu m1, [ref1q+%5] movu m2, [ref2q+%5] - movu m3, [ref3q+%5] - psadbw m1, m0 - psadbw m2, m0 - psadbw m3, m0 - paddd m4, m1 - movu m1, [ref4q+%5] - paddd m5, m2 - paddd m6, m3 + %if %6 == 1 - lea srcq, [srcq +src_strideq*2] - lea ref1q, [ref1q+ref_strideq*2] - lea ref2q, [ref2q+ref_strideq*2] - lea ref3q, [ref3q+ref_strideq*2] - lea ref4q, [ref4q+ref_strideq*2] + movu m3, [second_predq] + pavgb m1, m3 + pavgb m2, m3 %endif psadbw m1, m0 - paddd m7, m1 + psadbw m2, m0 + paddd m4, m1 + paddd m5, m2 + + movu m1, [ref3q+%5] + movu m2, [ref4q+%5] + +%if %9 > 0 + ADVANCE_END_OF_LINE %9 +%endif + +%if %6 == 1 + pavgb m1, m3 + pavgb m2, m3 + lea second_predq, [second_predq+mmsize] +%endif + psadbw m1, m0 + psadbw m2, m0 + paddd m6, m1 + paddd m7, m2 %endmacro -; PROCESS_32x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_32x2x4 5-6 0 - PROCESS_16x2x4 %1, %2, %3, %2 + 16, %3 + 16 - PROCESS_16x2x4 0, %4, %5, %4 + 16, %5 + 16, %6 +; PROCESS_32x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first,second}_extraline, line_ending +%macro PROCESS_32x2x4 9 + PROCESS_16x2x4 %1, %2, %3, %2 + 16, %3 + 16, %6, %7, %7, %8 - %7 + PROCESS_16x2x4 0, %4, %5, %4 + 16, %5 + 16, %6, %8, %8, %9 %endmacro -; PROCESS_64x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_64x2x4 5-6 0 - PROCESS_32x2x4 %1, %2, %3, %2 + 32, %3 + 32 - PROCESS_32x2x4 0, %4, %5, %4 + 32, %5 + 32, %6 +; PROCESS_64x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first,second}_extraline, line_ending +%macro PROCESS_64x2x4 9 + PROCESS_32x2x4 %1, %2, %3, %2 + 32, %3 + 32, %6, %7, %7, %8 - %7 + PROCESS_32x2x4 0, %4, %5, %4 + 32, %5 + 32, %6, %8, %8, %9 %endmacro -; PROCESS_128x2x4 first, off_{first,second}_{src,ref}, advance_at_end -%macro PROCESS_128x2x4 5-6 0 - PROCESS_64x2x4 %1, %2, %3, %2 + 64, %3 + 64 - PROCESS_64x2x4 0, %4, %5, %4 + 64, %5 + 64, %6 +; PROCESS_128x2x4 first, off_{first,second}_{src,ref}, do_avg, +; {first,second}_extraline, line_ending +%macro PROCESS_128x2x4 9 + PROCESS_64x2x4 %1, %2, %3, %2 + 64, %3 + 64, %6, %7, %7, %8 - %7 + PROCESS_64x2x4 0, %4, %5, %4 + 64, %5 + 64, %6, %8, %8, %9 %endmacro ; void aom_sadNxNx4d_sse2(uint8_t *src, int src_stride, ; uint8_t *ref[4], int ref_stride, ; uint32_t res[4]); ; where NxN = 64x64, 32x32, 16x16, 16x8, 8x16, 8x8, 8x4, 4x8 and 4x4 -%macro SADNXN4D 2 +%macro SADNXN4D 2-3 0 +%if %3 == 0 %if UNIX64 cglobal sad%1x%2x4d, 5, 8, 8, src, src_stride, ref1, ref_stride, \ res, ref2, ref3, ref4 @@ -196,18 +322,41 @@ cglobal sad%1x%2x4d, 5, 8, 8, src, src_stride, ref1, ref_stride, \ cglobal sad%1x%2x4d, 4, 7, 8, src, src_stride, ref1, ref_stride, \ ref2, ref3, ref4 %endif +%else ; avg + +%if UNIX64 +cglobal sad%1x%2x4d_avg, 6, 10, 8, src, src_stride, ref1, ref_stride, \ + second_pred, res, ref2, ref3, ref4 +%else +cglobal sad%1x%2x4d_avg, 5, 7, 8, src, ref4, ref1, ref_stride, \ + second_pred, ref2, ref3 + %define src_strideq r1mp + %define src_strided r1mp +%endif +%endif + + %define mflag ((1 - UNIX64) & %3) movsxdifnidn src_strideq, src_strided movsxdifnidn ref_strideq, ref_strided + mov ref2q, [ref1q+gprsize*1] mov ref3q, [ref1q+gprsize*2] mov ref4q, [ref1q+gprsize*3] mov ref1q, [ref1q+gprsize*0] - PROCESS_%1x2x4 1, 0, 0, src_strideq, ref_strideq, 1 + PROCESS_%1x2x4 1, 0, 0, 0, ref_strideq, %3, 0, 1, 2 %rep (%2-4)/2 - PROCESS_%1x2x4 0, 0, 0, src_strideq, ref_strideq, 1 + PROCESS_%1x2x4 0, 0, 0, 0, ref_strideq, %3, 0, 1, 2 %endrep - PROCESS_%1x2x4 0, 0, 0, src_strideq, ref_strideq, 0 + PROCESS_%1x2x4 0, 0, 0, 0, ref_strideq, %3, 0, 1, 2 + +%if %3 == 0 + %define resultq r4 + %define resultmp r4mp +%else + %define resultq r5 + %define resultmp r5mp +%endif %if %1 > 4 pslldq m5, 4 @@ -218,16 +367,16 @@ cglobal sad%1x%2x4d, 4, 7, 8, src, src_stride, ref1, ref_stride, \ mova m7, m6 punpcklqdq m4, m6 punpckhqdq m5, m7 - movifnidn r4, r4mp paddd m4, m5 - movu [r4], m4 + movifnidn resultq, resultmp + movu [resultq], m4 RET %else - movifnidn r4, r4mp pshufd m6, m6, 0x08 pshufd m7, m7, 0x08 - movq [r4+0], m6 - movq [r4+8], m7 + movifnidn resultq, resultmp + movq [resultq+0], m6 + movq [resultq+8], m7 RET %endif %endmacro @@ -255,3 +404,25 @@ SADNXN4D 8, 32 SADNXN4D 32, 8 SADNXN4D 16, 64 SADNXN4D 64, 16 +SADNXN4D 128, 128, 1 +SADNXN4D 128, 64, 1 +SADNXN4D 64, 128, 1 +SADNXN4D 64, 64, 1 +SADNXN4D 64, 32, 1 +SADNXN4D 32, 64, 1 +SADNXN4D 32, 32, 1 +SADNXN4D 32, 16, 1 +SADNXN4D 16, 32, 1 +SADNXN4D 16, 16, 1 +SADNXN4D 16, 8, 1 +SADNXN4D 8, 16, 1 +SADNXN4D 8, 8, 1 +SADNXN4D 8, 4, 1 +SADNXN4D 4, 8, 1 +SADNXN4D 4, 4, 1 +SADNXN4D 4, 16, 1 +SADNXN4D 16, 4, 1 +SADNXN4D 8, 32, 1 +SADNXN4D 32, 8, 1 +SADNXN4D 16, 64, 1 +SADNXN4D 64, 16, 1 diff --git a/media/libaom/src/aom_dsp/x86/sad_highbd_avx2.c b/media/libaom/src/aom_dsp/x86/sad_highbd_avx2.c index eba442ccf5..2cff2e6a9f 100644 --- a/media/libaom/src/aom_dsp/x86/sad_highbd_avx2.c +++ b/media/libaom/src/aom_dsp/x86/sad_highbd_avx2.c @@ -37,532 +37,247 @@ static INLINE unsigned int get_sad_from_mm256_epi32(const __m256i *v) { return (unsigned int)_mm_cvtsi128_si32(lo128); } -unsigned int aom_highbd_sad16x8_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - const uint16_t *src_ptr = CONVERT_TO_SHORTPTR(src); - const uint16_t *ref_ptr = CONVERT_TO_SHORTPTR(ref); - - // first 4 rows - __m256i s0 = _mm256_loadu_si256((const __m256i *)src_ptr); - __m256i s1 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - __m256i s2 = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride)); - __m256i s3 = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride)); - - __m256i r0 = _mm256_loadu_si256((const __m256i *)ref_ptr); - __m256i r1 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - __m256i r2 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride)); - __m256i r3 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride)); - - __m256i u0 = _mm256_sub_epi16(s0, r0); - __m256i u1 = _mm256_sub_epi16(s1, r1); - __m256i u2 = _mm256_sub_epi16(s2, r2); - __m256i u3 = _mm256_sub_epi16(s3, r3); - __m256i zero = _mm256_setzero_si256(); - __m256i sum0, sum1; - - u0 = _mm256_abs_epi16(u0); - u1 = _mm256_abs_epi16(u1); - u2 = _mm256_abs_epi16(u2); - u3 = _mm256_abs_epi16(u3); - - sum0 = _mm256_add_epi16(u0, u1); - sum0 = _mm256_add_epi16(sum0, u2); - sum0 = _mm256_add_epi16(sum0, u3); - - // second 4 rows - src_ptr += src_stride << 2; - ref_ptr += ref_stride << 2; - s0 = _mm256_loadu_si256((const __m256i *)src_ptr); - s1 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - s2 = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride)); - s3 = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride)); - - r0 = _mm256_loadu_si256((const __m256i *)ref_ptr); - r1 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - r2 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride)); - r3 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride)); - - u0 = _mm256_sub_epi16(s0, r0); - u1 = _mm256_sub_epi16(s1, r1); - u2 = _mm256_sub_epi16(s2, r2); - u3 = _mm256_sub_epi16(s3, r3); - - u0 = _mm256_abs_epi16(u0); - u1 = _mm256_abs_epi16(u1); - u2 = _mm256_abs_epi16(u2); - u3 = _mm256_abs_epi16(u3); - - sum1 = _mm256_add_epi16(u0, u1); - sum1 = _mm256_add_epi16(sum1, u2); - sum1 = _mm256_add_epi16(sum1, u3); - - // find out the SAD - s0 = _mm256_unpacklo_epi16(sum0, zero); - s1 = _mm256_unpackhi_epi16(sum0, zero); - r0 = _mm256_unpacklo_epi16(sum1, zero); - r1 = _mm256_unpackhi_epi16(sum1, zero); - s0 = _mm256_add_epi32(s0, s1); - r0 = _mm256_add_epi32(r0, r1); - sum0 = _mm256_add_epi32(s0, r0); - // 8 32-bit summation - - return (unsigned int)get_sad_from_mm256_epi32(&sum0); -} - -unsigned int aom_highbd_sad16x16_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - const uint16_t *src_ptr = CONVERT_TO_SHORTPTR(src); - const uint16_t *ref_ptr = CONVERT_TO_SHORTPTR(ref); - __m256i s0, s1, s2, s3, r0, r1, r2, r3, u0, u1, u2, u3; - __m256i sum0; - __m256i sum = _mm256_setzero_si256(); +static INLINE void highbd_sad16x4_core_avx2(__m256i *s, __m256i *r, + __m256i *sad_acc) { const __m256i zero = _mm256_setzero_si256(); - int row = 0; - - // Loop for every 4 rows - while (row < 16) { - s0 = _mm256_loadu_si256((const __m256i *)src_ptr); - s1 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - s2 = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride)); - s3 = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride)); - - r0 = _mm256_loadu_si256((const __m256i *)ref_ptr); - r1 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - r2 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride)); - r3 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride)); - - u0 = _mm256_sub_epi16(s0, r0); - u1 = _mm256_sub_epi16(s1, r1); - u2 = _mm256_sub_epi16(s2, r2); - u3 = _mm256_sub_epi16(s3, r3); - - u0 = _mm256_abs_epi16(u0); - u1 = _mm256_abs_epi16(u1); - u2 = _mm256_abs_epi16(u2); - u3 = _mm256_abs_epi16(u3); - - sum0 = _mm256_add_epi16(u0, u1); - sum0 = _mm256_add_epi16(sum0, u2); - sum0 = _mm256_add_epi16(sum0, u3); - - s0 = _mm256_unpacklo_epi16(sum0, zero); - s1 = _mm256_unpackhi_epi16(sum0, zero); - sum = _mm256_add_epi32(sum, s0); - sum = _mm256_add_epi32(sum, s1); - // 8 32-bit summation - - row += 4; - src_ptr += src_stride << 2; - ref_ptr += ref_stride << 2; + int i; + for (i = 0; i < 4; i++) { + s[i] = _mm256_sub_epi16(s[i], r[i]); + s[i] = _mm256_abs_epi16(s[i]); } - return get_sad_from_mm256_epi32(&sum); -} - -static void sad32x4(const uint16_t *src_ptr, int src_stride, - const uint16_t *ref_ptr, int ref_stride, - const uint16_t *sec_ptr, __m256i *sad_acc) { - __m256i s0, s1, s2, s3, r0, r1, r2, r3; - const __m256i zero = _mm256_setzero_si256(); - int row_sections = 0; - - while (row_sections < 2) { - s0 = _mm256_loadu_si256((const __m256i *)src_ptr); - s1 = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); - s2 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - s3 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 16)); - - r0 = _mm256_loadu_si256((const __m256i *)ref_ptr); - r1 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); - r2 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - r3 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 16)); - - if (sec_ptr) { - r0 = _mm256_avg_epu16(r0, _mm256_loadu_si256((const __m256i *)sec_ptr)); - r1 = _mm256_avg_epu16( - r1, _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); - r2 = _mm256_avg_epu16( - r2, _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); - r3 = _mm256_avg_epu16( - r3, _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); - } - s0 = _mm256_sub_epi16(s0, r0); - s1 = _mm256_sub_epi16(s1, r1); - s2 = _mm256_sub_epi16(s2, r2); - s3 = _mm256_sub_epi16(s3, r3); - - s0 = _mm256_abs_epi16(s0); - s1 = _mm256_abs_epi16(s1); - s2 = _mm256_abs_epi16(s2); - s3 = _mm256_abs_epi16(s3); - - s0 = _mm256_add_epi16(s0, s1); - s0 = _mm256_add_epi16(s0, s2); - s0 = _mm256_add_epi16(s0, s3); - - r0 = _mm256_unpacklo_epi16(s0, zero); - r1 = _mm256_unpackhi_epi16(s0, zero); - - r0 = _mm256_add_epi32(r0, r1); - *sad_acc = _mm256_add_epi32(*sad_acc, r0); - - row_sections += 1; - src_ptr += src_stride << 1; - ref_ptr += ref_stride << 1; - if (sec_ptr) sec_ptr += 32 << 1; - } -} - -unsigned int aom_highbd_sad32x16_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - __m256i sad = _mm256_setzero_si256(); - uint16_t *srcp = CONVERT_TO_SHORTPTR(src); - uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - const int left_shift = 2; - int row_section = 0; - - while (row_section < 4) { - sad32x4(srcp, src_stride, refp, ref_stride, NULL, &sad); - srcp += src_stride << left_shift; - refp += ref_stride << left_shift; - row_section += 1; - } - return get_sad_from_mm256_epi32(&sad); -} - -unsigned int aom_highbd_sad32x8_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - __m256i sad = _mm256_setzero_si256(); - uint16_t *srcp = CONVERT_TO_SHORTPTR(src); - uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - const int left_shift = 2; - int row_section = 0; - - while (row_section < 2) { - sad32x4(srcp, src_stride, refp, ref_stride, NULL, &sad); - srcp += src_stride << left_shift; - refp += ref_stride << left_shift; - row_section += 1; - } - return get_sad_from_mm256_epi32(&sad); -} - -unsigned int aom_highbd_sad16x32_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad16x16_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 4; - ref += ref_stride << 4; - sum += aom_highbd_sad16x16_avx2(src, src_stride, ref, ref_stride); - return sum; -} - -unsigned int aom_highbd_sad32x32_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad32x16_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 4; - ref += ref_stride << 4; - sum += aom_highbd_sad32x16_avx2(src, src_stride, ref, ref_stride); - return sum; -} - -unsigned int aom_highbd_sad32x64_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad32x32_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 5; - ref += ref_stride << 5; - sum += aom_highbd_sad32x32_avx2(src, src_stride, ref, ref_stride); - return sum; -} - -static void sad64x2(const uint16_t *src_ptr, int src_stride, - const uint16_t *ref_ptr, int ref_stride, - const uint16_t *sec_ptr, __m256i *sad_acc) { - __m256i s[8], r[8]; - const __m256i zero = _mm256_setzero_si256(); - - s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); - s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); - s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32)); - s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48)); - s[4] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - s[5] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 16)); - s[6] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 32)); - s[7] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 48)); - - r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); - r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); - r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32)); - r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48)); - r[4] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - r[5] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 16)); - r[6] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 32)); - r[7] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 48)); - - if (sec_ptr) { - r[0] = _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); - r[1] = _mm256_avg_epu16( - r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); - r[2] = _mm256_avg_epu16( - r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); - r[3] = _mm256_avg_epu16( - r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); - r[4] = _mm256_avg_epu16( - r[4], _mm256_loadu_si256((const __m256i *)(sec_ptr + 64))); - r[5] = _mm256_avg_epu16( - r[5], _mm256_loadu_si256((const __m256i *)(sec_ptr + 80))); - r[6] = _mm256_avg_epu16( - r[6], _mm256_loadu_si256((const __m256i *)(sec_ptr + 96))); - r[7] = _mm256_avg_epu16( - r[7], _mm256_loadu_si256((const __m256i *)(sec_ptr + 112))); - } - - s[0] = _mm256_sub_epi16(s[0], r[0]); - s[1] = _mm256_sub_epi16(s[1], r[1]); - s[2] = _mm256_sub_epi16(s[2], r[2]); - s[3] = _mm256_sub_epi16(s[3], r[3]); - s[4] = _mm256_sub_epi16(s[4], r[4]); - s[5] = _mm256_sub_epi16(s[5], r[5]); - s[6] = _mm256_sub_epi16(s[6], r[6]); - s[7] = _mm256_sub_epi16(s[7], r[7]); - - s[0] = _mm256_abs_epi16(s[0]); - s[1] = _mm256_abs_epi16(s[1]); - s[2] = _mm256_abs_epi16(s[2]); - s[3] = _mm256_abs_epi16(s[3]); - s[4] = _mm256_abs_epi16(s[4]); - s[5] = _mm256_abs_epi16(s[5]); - s[6] = _mm256_abs_epi16(s[6]); - s[7] = _mm256_abs_epi16(s[7]); s[0] = _mm256_add_epi16(s[0], s[1]); s[0] = _mm256_add_epi16(s[0], s[2]); s[0] = _mm256_add_epi16(s[0], s[3]); - s[4] = _mm256_add_epi16(s[4], s[5]); - s[4] = _mm256_add_epi16(s[4], s[6]); - s[4] = _mm256_add_epi16(s[4], s[7]); - r[0] = _mm256_unpacklo_epi16(s[0], zero); r[1] = _mm256_unpackhi_epi16(s[0], zero); - r[2] = _mm256_unpacklo_epi16(s[4], zero); - r[3] = _mm256_unpackhi_epi16(s[4], zero); r[0] = _mm256_add_epi32(r[0], r[1]); - r[0] = _mm256_add_epi32(r[0], r[2]); - r[0] = _mm256_add_epi32(r[0], r[3]); *sad_acc = _mm256_add_epi32(*sad_acc, r[0]); } -unsigned int aom_highbd_sad64x32_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - __m256i sad = _mm256_setzero_si256(); - uint16_t *srcp = CONVERT_TO_SHORTPTR(src); - uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - const int left_shift = 1; - int row_section = 0; - - while (row_section < 16) { - sad64x2(srcp, src_stride, refp, ref_stride, NULL, &sad); - srcp += src_stride << left_shift; - refp += ref_stride << left_shift; - row_section += 1; - } - return get_sad_from_mm256_epi32(&sad); -} - -unsigned int aom_highbd_sad64x16_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - __m256i sad = _mm256_setzero_si256(); - uint16_t *srcp = CONVERT_TO_SHORTPTR(src); - uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - const int left_shift = 1; - int row_section = 0; - - while (row_section < 8) { - sad64x2(srcp, src_stride, refp, ref_stride, NULL, &sad); - srcp += src_stride << left_shift; - refp += ref_stride << left_shift; - row_section += 1; - } - return get_sad_from_mm256_epi32(&sad); -} - -unsigned int aom_highbd_sad64x64_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad64x32_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 5; - ref += ref_stride << 5; - sum += aom_highbd_sad64x32_avx2(src, src_stride, ref, ref_stride); - return sum; -} - -static void sad128x1(const uint16_t *src_ptr, const uint16_t *ref_ptr, - const uint16_t *sec_ptr, __m256i *sad_acc) { - __m256i s[8], r[8]; - const __m256i zero = _mm256_setzero_si256(); - - s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); - s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); - s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32)); - s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48)); - s[4] = _mm256_loadu_si256((const __m256i *)(src_ptr + 64)); - s[5] = _mm256_loadu_si256((const __m256i *)(src_ptr + 80)); - s[6] = _mm256_loadu_si256((const __m256i *)(src_ptr + 96)); - s[7] = _mm256_loadu_si256((const __m256i *)(src_ptr + 112)); - - r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); - r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); - r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32)); - r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48)); - r[4] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 64)); - r[5] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 80)); - r[6] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 96)); - r[7] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 112)); - - if (sec_ptr) { - r[0] = _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); - r[1] = _mm256_avg_epu16( - r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); - r[2] = _mm256_avg_epu16( - r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); - r[3] = _mm256_avg_epu16( - r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); - r[4] = _mm256_avg_epu16( - r[4], _mm256_loadu_si256((const __m256i *)(sec_ptr + 64))); - r[5] = _mm256_avg_epu16( - r[5], _mm256_loadu_si256((const __m256i *)(sec_ptr + 80))); - r[6] = _mm256_avg_epu16( - r[6], _mm256_loadu_si256((const __m256i *)(sec_ptr + 96))); - r[7] = _mm256_avg_epu16( - r[7], _mm256_loadu_si256((const __m256i *)(sec_ptr + 112))); - } - - s[0] = _mm256_sub_epi16(s[0], r[0]); - s[1] = _mm256_sub_epi16(s[1], r[1]); - s[2] = _mm256_sub_epi16(s[2], r[2]); - s[3] = _mm256_sub_epi16(s[3], r[3]); - s[4] = _mm256_sub_epi16(s[4], r[4]); - s[5] = _mm256_sub_epi16(s[5], r[5]); - s[6] = _mm256_sub_epi16(s[6], r[6]); - s[7] = _mm256_sub_epi16(s[7], r[7]); - - s[0] = _mm256_abs_epi16(s[0]); - s[1] = _mm256_abs_epi16(s[1]); - s[2] = _mm256_abs_epi16(s[2]); - s[3] = _mm256_abs_epi16(s[3]); - s[4] = _mm256_abs_epi16(s[4]); - s[5] = _mm256_abs_epi16(s[5]); - s[6] = _mm256_abs_epi16(s[6]); - s[7] = _mm256_abs_epi16(s[7]); - - s[0] = _mm256_add_epi16(s[0], s[1]); - s[0] = _mm256_add_epi16(s[0], s[2]); - s[0] = _mm256_add_epi16(s[0], s[3]); - - s[4] = _mm256_add_epi16(s[4], s[5]); - s[4] = _mm256_add_epi16(s[4], s[6]); - s[4] = _mm256_add_epi16(s[4], s[7]); - - r[0] = _mm256_unpacklo_epi16(s[0], zero); - r[1] = _mm256_unpackhi_epi16(s[0], zero); - r[2] = _mm256_unpacklo_epi16(s[4], zero); - r[3] = _mm256_unpackhi_epi16(s[4], zero); - - r[0] = _mm256_add_epi32(r[0], r[1]); - r[0] = _mm256_add_epi32(r[0], r[2]); - r[0] = _mm256_add_epi32(r[0], r[3]); - *sad_acc = _mm256_add_epi32(*sad_acc, r[0]); -} - -unsigned int aom_highbd_sad128x64_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - __m256i sad = _mm256_setzero_si256(); - uint16_t *srcp = CONVERT_TO_SHORTPTR(src); - uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - int row = 0; - while (row < 64) { - sad128x1(srcp, refp, NULL, &sad); - srcp += src_stride; - refp += ref_stride; - row += 1; - } - return get_sad_from_mm256_epi32(&sad); -} - -unsigned int aom_highbd_sad64x128_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad64x64_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 6; - ref += ref_stride << 6; - sum += aom_highbd_sad64x64_avx2(src, src_stride, ref, ref_stride); - return sum; -} - -unsigned int aom_highbd_sad128x128_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - uint32_t sum = aom_highbd_sad128x64_avx2(src, src_stride, ref, ref_stride); - src += src_stride << 6; - ref += ref_stride << 6; - sum += aom_highbd_sad128x64_avx2(src, src_stride, ref, ref_stride); - return sum; -} - // If sec_ptr = 0, calculate regular SAD. Otherwise, calculate average SAD. static INLINE void sad16x4(const uint16_t *src_ptr, int src_stride, const uint16_t *ref_ptr, int ref_stride, const uint16_t *sec_ptr, __m256i *sad_acc) { - __m256i s0, s1, s2, s3, r0, r1, r2, r3; - const __m256i zero = _mm256_setzero_si256(); + __m256i s[4], r[4]; + s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); + s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); + s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride)); + s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride)); - s0 = _mm256_loadu_si256((const __m256i *)src_ptr); - s1 = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); - s2 = _mm256_loadu_si256((const __m256i *)(src_ptr + 2 * src_stride)); - s3 = _mm256_loadu_si256((const __m256i *)(src_ptr + 3 * src_stride)); - - r0 = _mm256_loadu_si256((const __m256i *)ref_ptr); - r1 = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); - r2 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride)); - r3 = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride)); + r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); + r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); + r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 2 * ref_stride)); + r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 3 * ref_stride)); if (sec_ptr) { - r0 = _mm256_avg_epu16(r0, _mm256_loadu_si256((const __m256i *)sec_ptr)); - r1 = _mm256_avg_epu16(r1, - _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); - r2 = _mm256_avg_epu16(r2, - _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); - r3 = _mm256_avg_epu16(r3, - _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); + r[0] = _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); + r[1] = _mm256_avg_epu16( + r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); + r[2] = _mm256_avg_epu16( + r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); + r[3] = _mm256_avg_epu16( + r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); } - - s0 = _mm256_sub_epi16(s0, r0); - s1 = _mm256_sub_epi16(s1, r1); - s2 = _mm256_sub_epi16(s2, r2); - s3 = _mm256_sub_epi16(s3, r3); - - s0 = _mm256_abs_epi16(s0); - s1 = _mm256_abs_epi16(s1); - s2 = _mm256_abs_epi16(s2); - s3 = _mm256_abs_epi16(s3); - - s0 = _mm256_add_epi16(s0, s1); - s0 = _mm256_add_epi16(s0, s2); - s0 = _mm256_add_epi16(s0, s3); - - r0 = _mm256_unpacklo_epi16(s0, zero); - r1 = _mm256_unpackhi_epi16(s0, zero); - - r0 = _mm256_add_epi32(r0, r1); - *sad_acc = _mm256_add_epi32(*sad_acc, r0); + highbd_sad16x4_core_avx2(s, r, sad_acc); } -unsigned int aom_highbd_sad16x4_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { +static AOM_FORCE_INLINE unsigned int aom_highbd_sad16xN_avx2(int N, + const uint8_t *src, + int src_stride, + const uint8_t *ref, + int ref_stride) { + const uint16_t *src_ptr = CONVERT_TO_SHORTPTR(src); + const uint16_t *ref_ptr = CONVERT_TO_SHORTPTR(ref); + int i; + __m256i sad = _mm256_setzero_si256(); + for (i = 0; i < N; i += 4) { + sad16x4(src_ptr, src_stride, ref_ptr, ref_stride, NULL, &sad); + src_ptr += src_stride << 2; + ref_ptr += ref_stride << 2; + } + return (unsigned int)get_sad_from_mm256_epi32(&sad); +} + +static void sad32x4(const uint16_t *src_ptr, int src_stride, + const uint16_t *ref_ptr, int ref_stride, + const uint16_t *sec_ptr, __m256i *sad_acc) { + __m256i s[4], r[4]; + int row_sections = 0; + + while (row_sections < 2) { + s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); + s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); + s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride)); + s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + src_stride + 16)); + + r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); + r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); + r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride)); + r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + ref_stride + 16)); + + if (sec_ptr) { + r[0] = + _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); + r[1] = _mm256_avg_epu16( + r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); + r[2] = _mm256_avg_epu16( + r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); + r[3] = _mm256_avg_epu16( + r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); + sec_ptr += 32 << 1; + } + highbd_sad16x4_core_avx2(s, r, sad_acc); + + row_sections += 1; + src_ptr += src_stride << 1; + ref_ptr += ref_stride << 1; + } +} + +static AOM_FORCE_INLINE unsigned int aom_highbd_sad32xN_avx2(int N, + const uint8_t *src, + int src_stride, + const uint8_t *ref, + int ref_stride) { __m256i sad = _mm256_setzero_si256(); uint16_t *srcp = CONVERT_TO_SHORTPTR(src); uint16_t *refp = CONVERT_TO_SHORTPTR(ref); - sad16x4(srcp, src_stride, refp, ref_stride, NULL, &sad); + const int left_shift = 2; + int i; + + for (i = 0; i < N; i += 4) { + sad32x4(srcp, src_stride, refp, ref_stride, NULL, &sad); + srcp += src_stride << left_shift; + refp += ref_stride << left_shift; + } return get_sad_from_mm256_epi32(&sad); } +static void sad64x2(const uint16_t *src_ptr, int src_stride, + const uint16_t *ref_ptr, int ref_stride, + const uint16_t *sec_ptr, __m256i *sad_acc) { + __m256i s[4], r[4]; + int i; + for (i = 0; i < 2; i++) { + s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); + s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); + s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32)); + s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48)); + + r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); + r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); + r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32)); + r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48)); + if (sec_ptr) { + r[0] = + _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); + r[1] = _mm256_avg_epu16( + r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); + r[2] = _mm256_avg_epu16( + r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); + r[3] = _mm256_avg_epu16( + r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); + sec_ptr += 64; + } + highbd_sad16x4_core_avx2(s, r, sad_acc); + src_ptr += src_stride; + ref_ptr += ref_stride; + } +} + +static AOM_FORCE_INLINE unsigned int aom_highbd_sad64xN_avx2(int N, + const uint8_t *src, + int src_stride, + const uint8_t *ref, + int ref_stride) { + __m256i sad = _mm256_setzero_si256(); + uint16_t *srcp = CONVERT_TO_SHORTPTR(src); + uint16_t *refp = CONVERT_TO_SHORTPTR(ref); + const int left_shift = 1; + int i; + for (i = 0; i < N; i += 2) { + sad64x2(srcp, src_stride, refp, ref_stride, NULL, &sad); + srcp += src_stride << left_shift; + refp += ref_stride << left_shift; + } + return get_sad_from_mm256_epi32(&sad); +} + +static void sad128x1(const uint16_t *src_ptr, const uint16_t *ref_ptr, + const uint16_t *sec_ptr, __m256i *sad_acc) { + __m256i s[4], r[4]; + int i; + for (i = 0; i < 2; i++) { + s[0] = _mm256_loadu_si256((const __m256i *)src_ptr); + s[1] = _mm256_loadu_si256((const __m256i *)(src_ptr + 16)); + s[2] = _mm256_loadu_si256((const __m256i *)(src_ptr + 32)); + s[3] = _mm256_loadu_si256((const __m256i *)(src_ptr + 48)); + r[0] = _mm256_loadu_si256((const __m256i *)ref_ptr); + r[1] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 16)); + r[2] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 32)); + r[3] = _mm256_loadu_si256((const __m256i *)(ref_ptr + 48)); + if (sec_ptr) { + r[0] = + _mm256_avg_epu16(r[0], _mm256_loadu_si256((const __m256i *)sec_ptr)); + r[1] = _mm256_avg_epu16( + r[1], _mm256_loadu_si256((const __m256i *)(sec_ptr + 16))); + r[2] = _mm256_avg_epu16( + r[2], _mm256_loadu_si256((const __m256i *)(sec_ptr + 32))); + r[3] = _mm256_avg_epu16( + r[3], _mm256_loadu_si256((const __m256i *)(sec_ptr + 48))); + sec_ptr += 64; + } + highbd_sad16x4_core_avx2(s, r, sad_acc); + src_ptr += 64; + ref_ptr += 64; + } +} + +static AOM_FORCE_INLINE unsigned int aom_highbd_sad128xN_avx2( + int N, const uint8_t *src, int src_stride, const uint8_t *ref, + int ref_stride) { + __m256i sad = _mm256_setzero_si256(); + uint16_t *srcp = CONVERT_TO_SHORTPTR(src); + uint16_t *refp = CONVERT_TO_SHORTPTR(ref); + int row = 0; + while (row < N) { + sad128x1(srcp, refp, NULL, &sad); + srcp += src_stride; + refp += ref_stride; + row++; + } + return get_sad_from_mm256_epi32(&sad); +} + +#define highbd_sadMxN_avx2(m, n) \ + unsigned int aom_highbd_sad##m##x##n##_avx2( \ + const uint8_t *src, int src_stride, const uint8_t *ref, \ + int ref_stride) { \ + return aom_highbd_sad##m##xN_avx2(n, src, src_stride, ref, ref_stride); \ + } + +highbd_sadMxN_avx2(16, 4); +highbd_sadMxN_avx2(16, 8); +highbd_sadMxN_avx2(16, 16); +highbd_sadMxN_avx2(16, 32); +highbd_sadMxN_avx2(16, 64); + +highbd_sadMxN_avx2(32, 8); +highbd_sadMxN_avx2(32, 16); +highbd_sadMxN_avx2(32, 32); +highbd_sadMxN_avx2(32, 64); + +highbd_sadMxN_avx2(64, 16); +highbd_sadMxN_avx2(64, 32); +highbd_sadMxN_avx2(64, 64); +highbd_sadMxN_avx2(64, 128); + +highbd_sadMxN_avx2(128, 64); +highbd_sadMxN_avx2(128, 128); + unsigned int aom_highbd_sad16x4_avg_avx2(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, const uint8_t *second_pred) { @@ -621,16 +336,6 @@ unsigned int aom_highbd_sad16x32_avg_avx2(const uint8_t *src, int src_stride, return sum; } -unsigned int aom_highbd_sad16x64_avx2(const uint8_t *src, int src_stride, - const uint8_t *ref, int ref_stride) { - const int left_shift = 5; - uint32_t sum = aom_highbd_sad16x32_avx2(src, src_stride, ref, ref_stride); - src += src_stride << left_shift; - ref += ref_stride << left_shift; - sum += aom_highbd_sad16x32_avx2(src, src_stride, ref, ref_stride); - return sum; -} - unsigned int aom_highbd_sad16x64_avg_avx2(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, const uint8_t *second_pred) { @@ -816,7 +521,7 @@ unsigned int aom_highbd_sad128x128_avg_avx2(const uint8_t *src, int src_stride, } // SAD 4D -// Combine 4 __m256i vectors to uint32_t result[4] +// Combine 4 __m256i input vectors v to uint32_t result[4] static INLINE void get_4d_sad_from_mm256_epi32(const __m256i *v, uint32_t *res) { __m256i u0, u1, u2, u3; @@ -871,386 +576,124 @@ static void init_sad(__m256i *s) { s[3] = _mm256_setzero_si256(); } -void aom_highbd_sad16x4x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - __m256i sad_vec[4]; - const uint16_t *refp[4]; - const uint16_t *keep = CONVERT_TO_SHORTPTR(src); - const uint16_t *srcp; - int i; - - init_sad(sad_vec); - convert_pointers(ref_array, refp); - - for (i = 0; i < 4; ++i) { - srcp = keep; - sad16x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); - } - get_4d_sad_from_mm256_epi32(sad_vec, sad_array); -} - -void aom_highbd_sad16x8x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { +static AOM_FORCE_INLINE void aom_highbd_sad16xNx4d_avx2( + int N, const uint8_t *src, int src_stride, const uint8_t *const ref_array[], + int ref_stride, uint32_t *sad_array) { __m256i sad_vec[4]; const uint16_t *refp[4]; const uint16_t *keep = CONVERT_TO_SHORTPTR(src); const uint16_t *srcp; const int shift_for_4_rows = 2; - int i; + int i, j; init_sad(sad_vec); convert_pointers(ref_array, refp); for (i = 0; i < 4; ++i) { srcp = keep; - sad16x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); - srcp += src_stride << shift_for_4_rows; - refp[i] += ref_stride << shift_for_4_rows; - sad16x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); - } - get_4d_sad_from_mm256_epi32(sad_vec, sad_array); -} - -void aom_highbd_sad16x16x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first8rows[4]; - uint32_t second8rows[4]; - const uint8_t *ref[4]; - const int shift_for_8_rows = 3; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad16x8x4d_avx2(src, src_stride, ref, ref_stride, first8rows); - src += src_stride << shift_for_8_rows; - ref[0] += ref_stride << shift_for_8_rows; - ref[1] += ref_stride << shift_for_8_rows; - ref[2] += ref_stride << shift_for_8_rows; - ref[3] += ref_stride << shift_for_8_rows; - aom_highbd_sad16x8x4d_avx2(src, src_stride, ref, ref_stride, second8rows); - sad_array[0] = first8rows[0] + second8rows[0]; - sad_array[1] = first8rows[1] + second8rows[1]; - sad_array[2] = first8rows[2] + second8rows[2]; - sad_array[3] = first8rows[3] + second8rows[3]; -} - -void aom_highbd_sad16x32x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 4; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad16x16x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad16x16x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad16x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 5; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad16x32x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad16x32x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad32x8x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - __m256i sad_vec[4]; - const uint16_t *refp[4]; - const uint16_t *keep = CONVERT_TO_SHORTPTR(src); - const uint16_t *srcp; - const int shift_for_4_rows = 2; - int i; - int rows_section; - - init_sad(sad_vec); - convert_pointers(ref_array, refp); - - for (i = 0; i < 4; ++i) { - srcp = keep; - rows_section = 0; - while (rows_section < 2) { - sad32x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); + for (j = 0; j < N; j += 4) { + sad16x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); srcp += src_stride << shift_for_4_rows; refp[i] += ref_stride << shift_for_4_rows; - rows_section++; } } get_4d_sad_from_mm256_epi32(sad_vec, sad_array); } -void aom_highbd_sad32x16x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { +static AOM_FORCE_INLINE void aom_highbd_sad32xNx4d_avx2( + int N, const uint8_t *src, int src_stride, const uint8_t *const ref_array[], + int ref_stride, uint32_t *sad_array) { __m256i sad_vec[4]; const uint16_t *refp[4]; const uint16_t *keep = CONVERT_TO_SHORTPTR(src); const uint16_t *srcp; const int shift_for_4_rows = 2; - int i; - int rows_section; + int i, r; init_sad(sad_vec); convert_pointers(ref_array, refp); for (i = 0; i < 4; ++i) { srcp = keep; - rows_section = 0; - while (rows_section < 4) { + for (r = 0; r < N; r += 4) { sad32x4(srcp, src_stride, refp[i], ref_stride, 0, &sad_vec[i]); srcp += src_stride << shift_for_4_rows; refp[i] += ref_stride << shift_for_4_rows; - rows_section++; } } get_4d_sad_from_mm256_epi32(sad_vec, sad_array); } -void aom_highbd_sad32x32x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 4; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad32x16x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad32x16x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad32x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 5; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad32x32x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad32x32x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad64x16x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { +static AOM_FORCE_INLINE void aom_highbd_sad64xNx4d_avx2( + int N, const uint8_t *src, int src_stride, const uint8_t *const ref_array[], + int ref_stride, uint32_t *sad_array) { __m256i sad_vec[4]; const uint16_t *refp[4]; const uint16_t *keep = CONVERT_TO_SHORTPTR(src); const uint16_t *srcp; const int shift_for_rows = 1; - int i; - int rows_section; + int i, r; init_sad(sad_vec); convert_pointers(ref_array, refp); for (i = 0; i < 4; ++i) { srcp = keep; - rows_section = 0; - while (rows_section < 8) { + for (r = 0; r < N; r += 2) { sad64x2(srcp, src_stride, refp[i], ref_stride, NULL, &sad_vec[i]); srcp += src_stride << shift_for_rows; refp[i] += ref_stride << shift_for_rows; - rows_section++; } } get_4d_sad_from_mm256_epi32(sad_vec, sad_array); } -void aom_highbd_sad64x32x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { +static AOM_FORCE_INLINE void aom_highbd_sad128xNx4d_avx2( + int N, const uint8_t *src, int src_stride, const uint8_t *const ref_array[], + int ref_stride, uint32_t *sad_array) { __m256i sad_vec[4]; const uint16_t *refp[4]; const uint16_t *keep = CONVERT_TO_SHORTPTR(src); const uint16_t *srcp; - const int shift_for_rows = 1; - int i; - int rows_section; + int i, r; init_sad(sad_vec); convert_pointers(ref_array, refp); for (i = 0; i < 4; ++i) { srcp = keep; - rows_section = 0; - while (rows_section < 16) { - sad64x2(srcp, src_stride, refp[i], ref_stride, NULL, &sad_vec[i]); - srcp += src_stride << shift_for_rows; - refp[i] += ref_stride << shift_for_rows; - rows_section++; - } - } - get_4d_sad_from_mm256_epi32(sad_vec, sad_array); -} - -void aom_highbd_sad64x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 5; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad64x32x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad64x32x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad64x128x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 6; - - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; - - aom_highbd_sad64x64x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad64x64x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} - -void aom_highbd_sad128x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - __m256i sad_vec[4]; - const uint16_t *refp[4]; - const uint16_t *keep = CONVERT_TO_SHORTPTR(src); - const uint16_t *srcp; - int i; - int rows_section; - - init_sad(sad_vec); - convert_pointers(ref_array, refp); - - for (i = 0; i < 4; ++i) { - srcp = keep; - rows_section = 0; - while (rows_section < 64) { + for (r = 0; r < N; r++) { sad128x1(srcp, refp[i], NULL, &sad_vec[i]); srcp += src_stride; refp[i] += ref_stride; - rows_section++; } } get_4d_sad_from_mm256_epi32(sad_vec, sad_array); } -void aom_highbd_sad128x128x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref_array[], - int ref_stride, uint32_t *sad_array) { - uint32_t first_half[4]; - uint32_t second_half[4]; - const uint8_t *ref[4]; - const int shift_for_rows = 6; +#define highbd_sadMxNx4d_avx2(m, n) \ + void aom_highbd_sad##m##x##n##x4d_avx2( \ + const uint8_t *src, int src_stride, const uint8_t *const ref_array[], \ + int ref_stride, uint32_t *sad_array) { \ + aom_highbd_sad##m##xNx4d_avx2(n, src, src_stride, ref_array, ref_stride, \ + sad_array); \ + } - ref[0] = ref_array[0]; - ref[1] = ref_array[1]; - ref[2] = ref_array[2]; - ref[3] = ref_array[3]; +highbd_sadMxNx4d_avx2(16, 4); +highbd_sadMxNx4d_avx2(16, 8); +highbd_sadMxNx4d_avx2(16, 16); +highbd_sadMxNx4d_avx2(16, 32); +highbd_sadMxNx4d_avx2(16, 64); - aom_highbd_sad128x64x4d_avx2(src, src_stride, ref, ref_stride, first_half); - src += src_stride << shift_for_rows; - ref[0] += ref_stride << shift_for_rows; - ref[1] += ref_stride << shift_for_rows; - ref[2] += ref_stride << shift_for_rows; - ref[3] += ref_stride << shift_for_rows; - aom_highbd_sad128x64x4d_avx2(src, src_stride, ref, ref_stride, second_half); - sad_array[0] = first_half[0] + second_half[0]; - sad_array[1] = first_half[1] + second_half[1]; - sad_array[2] = first_half[2] + second_half[2]; - sad_array[3] = first_half[3] + second_half[3]; -} +highbd_sadMxNx4d_avx2(32, 8); +highbd_sadMxNx4d_avx2(32, 16); +highbd_sadMxNx4d_avx2(32, 32); +highbd_sadMxNx4d_avx2(32, 64); + +highbd_sadMxNx4d_avx2(64, 16); +highbd_sadMxNx4d_avx2(64, 32); +highbd_sadMxNx4d_avx2(64, 64); +highbd_sadMxNx4d_avx2(64, 128); + +highbd_sadMxNx4d_avx2(128, 64); +highbd_sadMxNx4d_avx2(128, 128); diff --git a/media/libaom/src/aom_dsp/x86/sad_impl_avx2.c b/media/libaom/src/aom_dsp/x86/sad_impl_avx2.c index c6fd62c9e2..f77a585b4c 100644 --- a/media/libaom/src/aom_dsp/x86/sad_impl_avx2.c +++ b/media/libaom/src/aom_dsp/x86/sad_impl_avx2.c @@ -84,81 +84,6 @@ unsigned int aom_sad128x128_avx2(const uint8_t *src_ptr, int src_stride, return sum; } -static void sad64x64x4d(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - __m128i *res) { - uint32_t sum[4]; - aom_sad64x64x4d_avx2(src, src_stride, ref, ref_stride, sum); - *res = _mm_loadu_si128((const __m128i *)sum); -} - -void aom_sad64x128x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - __m128i sum0, sum1; - const uint8_t *rf[4]; - - rf[0] = ref[0]; - rf[1] = ref[1]; - rf[2] = ref[2]; - rf[3] = ref[3]; - sad64x64x4d(src, src_stride, rf, ref_stride, &sum0); - src += src_stride << 6; - rf[0] += ref_stride << 6; - rf[1] += ref_stride << 6; - rf[2] += ref_stride << 6; - rf[3] += ref_stride << 6; - sad64x64x4d(src, src_stride, rf, ref_stride, &sum1); - sum0 = _mm_add_epi32(sum0, sum1); - _mm_storeu_si128((__m128i *)res, sum0); -} - -void aom_sad128x64x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - __m128i sum0, sum1; - unsigned int half_width = 64; - const uint8_t *rf[4]; - - rf[0] = ref[0]; - rf[1] = ref[1]; - rf[2] = ref[2]; - rf[3] = ref[3]; - sad64x64x4d(src, src_stride, rf, ref_stride, &sum0); - src += half_width; - rf[0] += half_width; - rf[1] += half_width; - rf[2] += half_width; - rf[3] += half_width; - sad64x64x4d(src, src_stride, rf, ref_stride, &sum1); - sum0 = _mm_add_epi32(sum0, sum1); - _mm_storeu_si128((__m128i *)res, sum0); -} - -void aom_sad128x128x4d_avx2(const uint8_t *src, int src_stride, - const uint8_t *const ref[4], int ref_stride, - uint32_t res[4]) { - const uint8_t *rf[4]; - uint32_t sum0[4]; - uint32_t sum1[4]; - - rf[0] = ref[0]; - rf[1] = ref[1]; - rf[2] = ref[2]; - rf[3] = ref[3]; - aom_sad128x64x4d_avx2(src, src_stride, rf, ref_stride, sum0); - src += src_stride << 6; - rf[0] += ref_stride << 6; - rf[1] += ref_stride << 6; - rf[2] += ref_stride << 6; - rf[3] += ref_stride << 6; - aom_sad128x64x4d_avx2(src, src_stride, rf, ref_stride, sum1); - res[0] = sum0[0] + sum1[0]; - res[1] = sum0[1] + sum1[1]; - res[2] = sum0[2] + sum1[2]; - res[3] = sum0[3] + sum1[3]; -} - static unsigned int sad_w64_avg_avx2(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const int h, const uint8_t *second_pred, diff --git a/media/libaom/src/aom_dsp/x86/sse_sse4.c b/media/libaom/src/aom_dsp/x86/sse_sse4.c index 1945eb400d..5f95eb9aeb 100644 --- a/media/libaom/src/aom_dsp/x86/sse_sse4.c +++ b/media/libaom/src/aom_dsp/x86/sse_sse4.c @@ -51,9 +51,8 @@ static INLINE void sse_w16_sse4_1(__m128i *sum, const uint8_t *a, *sum = _mm_add_epi32(*sum, _mm_madd_epi16(v_d01_w, v_d01_w)); } -static INLINE void aom_sse4x2_sse4_1(const uint8_t *a, int a_stride, - const uint8_t *b, int b_stride, - __m128i *sum) { +static INLINE void sse4x2_sse4_1(const uint8_t *a, int a_stride, + const uint8_t *b, int b_stride, __m128i *sum) { const __m128i v_a0 = xx_loadl_32(a); const __m128i v_a1 = xx_loadl_32(a + a_stride); const __m128i v_b0 = xx_loadl_32(b); @@ -63,8 +62,8 @@ static INLINE void aom_sse4x2_sse4_1(const uint8_t *a, int a_stride, const __m128i v_d_w = _mm_sub_epi16(v_a_w, v_b_w); *sum = _mm_add_epi32(*sum, _mm_madd_epi16(v_d_w, v_d_w)); } -static INLINE void aom_sse8_sse4_1(const uint8_t *a, const uint8_t *b, - __m128i *sum) { +static INLINE void sse8_sse4_1(const uint8_t *a, const uint8_t *b, + __m128i *sum) { const __m128i v_a0 = xx_loadl_64(a); const __m128i v_b0 = xx_loadl_64(b); const __m128i v_a_w = _mm_cvtepu8_epi16(v_a0); @@ -81,7 +80,7 @@ int64_t aom_sse_sse4_1(const uint8_t *a, int a_stride, const uint8_t *b, switch (width) { case 4: do { - aom_sse4x2_sse4_1(a, a_stride, b, b_stride, &sum); + sse4x2_sse4_1(a, a_stride, b, b_stride, &sum); a += a_stride << 1; b += b_stride << 1; y += 2; @@ -90,7 +89,7 @@ int64_t aom_sse_sse4_1(const uint8_t *a, int a_stride, const uint8_t *b, break; case 8: do { - aom_sse8_sse4_1(a, b, &sum); + sse8_sse4_1(a, b, &sum); a += a_stride; b += b_stride; y += 1; @@ -149,11 +148,11 @@ int64_t aom_sse_sse4_1(const uint8_t *a, int a_stride, const uint8_t *b, do { int i = 0; do { - aom_sse8_sse4_1(a + i, b + i, &sum); - aom_sse8_sse4_1(a + i + a_stride, b + i + b_stride, &sum); + sse8_sse4_1(a + i, b + i, &sum); + sse8_sse4_1(a + i + a_stride, b + i + b_stride, &sum); i += 8; } while (i + 4 < width); - aom_sse4x2_sse4_1(a + i, a_stride, b + i, b_stride, &sum); + sse4x2_sse4_1(a + i, a_stride, b + i, b_stride, &sum); a += (a_stride << 1); b += (b_stride << 1); y += 2; @@ -162,7 +161,7 @@ int64_t aom_sse_sse4_1(const uint8_t *a, int a_stride, const uint8_t *b, do { int i = 0; do { - aom_sse8_sse4_1(a + i, b + i, &sum); + sse8_sse4_1(a + i, b + i, &sum); i += 8; } while (i < width); a += a_stride; diff --git a/media/libaom/src/aom_dsp/x86/subtract_avx2.c b/media/libaom/src/aom_dsp/x86/subtract_avx2.c index 4389d123db..40831600a6 100644 --- a/media/libaom/src/aom_dsp/x86/subtract_avx2.c +++ b/media/libaom/src/aom_dsp/x86/subtract_avx2.c @@ -26,7 +26,7 @@ static INLINE void subtract32_avx2(int16_t *diff_ptr, const uint8_t *src_ptr, _mm256_store_si256((__m256i *)(diff_ptr + 16), d_1); } -static INLINE void aom_subtract_block_16xn_avx2( +static INLINE void subtract_block_16xn_avx2( int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) { for (int32_t j = 0; j < rows; ++j) { @@ -42,7 +42,7 @@ static INLINE void aom_subtract_block_16xn_avx2( } } -static INLINE void aom_subtract_block_32xn_avx2( +static INLINE void subtract_block_32xn_avx2( int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) { for (int32_t j = 0; j < rows; ++j) { @@ -53,7 +53,7 @@ static INLINE void aom_subtract_block_32xn_avx2( } } -static INLINE void aom_subtract_block_64xn_avx2( +static INLINE void subtract_block_64xn_avx2( int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) { for (int32_t j = 0; j < rows; ++j) { @@ -65,7 +65,7 @@ static INLINE void aom_subtract_block_64xn_avx2( } } -static INLINE void aom_subtract_block_128xn_avx2( +static INLINE void subtract_block_128xn_avx2( int rows, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride) { for (int32_t j = 0; j < rows; ++j) { @@ -85,20 +85,20 @@ void aom_subtract_block_avx2(int rows, int cols, int16_t *diff_ptr, ptrdiff_t pred_stride) { switch (cols) { case 16: - aom_subtract_block_16xn_avx2(rows, diff_ptr, diff_stride, src_ptr, - src_stride, pred_ptr, pred_stride); + subtract_block_16xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride, + pred_ptr, pred_stride); break; case 32: - aom_subtract_block_32xn_avx2(rows, diff_ptr, diff_stride, src_ptr, - src_stride, pred_ptr, pred_stride); + subtract_block_32xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride, + pred_ptr, pred_stride); break; case 64: - aom_subtract_block_64xn_avx2(rows, diff_ptr, diff_stride, src_ptr, - src_stride, pred_ptr, pred_stride); + subtract_block_64xn_avx2(rows, diff_ptr, diff_stride, src_ptr, src_stride, + pred_ptr, pred_stride); break; case 128: - aom_subtract_block_128xn_avx2(rows, diff_ptr, diff_stride, src_ptr, - src_stride, pred_ptr, pred_stride); + subtract_block_128xn_avx2(rows, diff_ptr, diff_stride, src_ptr, + src_stride, pred_ptr, pred_stride); break; default: aom_subtract_block_sse2(rows, cols, diff_ptr, diff_stride, src_ptr, diff --git a/media/libaom/src/aom_dsp/x86/sum_squares_avx2.c b/media/libaom/src/aom_dsp/x86/sum_squares_avx2.c index 0af44e3a4c..97d78b6842 100644 --- a/media/libaom/src/aom_dsp/x86/sum_squares_avx2.c +++ b/media/libaom/src/aom_dsp/x86/sum_squares_avx2.c @@ -77,3 +77,172 @@ uint64_t aom_sum_squares_2d_i16_avx2(const int16_t *src, int stride, int width, return aom_sum_squares_2d_i16_c(src, stride, width, height); } } + +// Accumulate sum of 16-bit elements in the vector +static AOM_INLINE int32_t mm256_accumulate_epi16(__m256i vec_a) { + __m128i vtmp1 = _mm256_extracti128_si256(vec_a, 1); + __m128i vtmp2 = _mm256_castsi256_si128(vec_a); + vtmp1 = _mm_add_epi16(vtmp1, vtmp2); + vtmp2 = _mm_srli_si128(vtmp1, 8); + vtmp1 = _mm_add_epi16(vtmp1, vtmp2); + vtmp2 = _mm_srli_si128(vtmp1, 4); + vtmp1 = _mm_add_epi16(vtmp1, vtmp2); + vtmp2 = _mm_srli_si128(vtmp1, 2); + vtmp1 = _mm_add_epi16(vtmp1, vtmp2); + return _mm_extract_epi16(vtmp1, 0); +} + +// Accumulate sum of 32-bit elements in the vector +static AOM_INLINE int32_t mm256_accumulate_epi32(__m256i vec_a) { + __m128i vtmp1 = _mm256_extracti128_si256(vec_a, 1); + __m128i vtmp2 = _mm256_castsi256_si128(vec_a); + vtmp1 = _mm_add_epi32(vtmp1, vtmp2); + vtmp2 = _mm_srli_si128(vtmp1, 8); + vtmp1 = _mm_add_epi32(vtmp1, vtmp2); + vtmp2 = _mm_srli_si128(vtmp1, 4); + vtmp1 = _mm_add_epi32(vtmp1, vtmp2); + return _mm_cvtsi128_si32(vtmp1); +} + +uint64_t aom_var_2d_u8_avx2(uint8_t *src, int src_stride, int width, + int height) { + uint8_t *srcp; + uint64_t s = 0, ss = 0; + __m256i vzero = _mm256_setzero_si256(); + __m256i v_acc_sum = vzero; + __m256i v_acc_sqs = vzero; + int i, j; + + // Process 32 elements in a row + for (i = 0; i < width - 31; i += 32) { + srcp = src + i; + // Process 8 columns at a time + for (j = 0; j < height - 7; j += 8) { + __m256i vsrc[8]; + for (int k = 0; k < 8; k++) { + vsrc[k] = _mm256_loadu_si256((__m256i *)srcp); + srcp += src_stride; + } + for (int k = 0; k < 8; k++) { + __m256i vsrc0 = _mm256_unpacklo_epi8(vsrc[k], vzero); + __m256i vsrc1 = _mm256_unpackhi_epi8(vsrc[k], vzero); + v_acc_sum = _mm256_add_epi16(v_acc_sum, vsrc0); + v_acc_sum = _mm256_add_epi16(v_acc_sum, vsrc1); + + __m256i vsqs0 = _mm256_madd_epi16(vsrc0, vsrc0); + __m256i vsqs1 = _mm256_madd_epi16(vsrc1, vsrc1); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs0); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs1); + } + + // Update total sum and clear the vectors + s += mm256_accumulate_epi16(v_acc_sum); + ss += mm256_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process remaining rows (height not a multiple of 8) + for (; j < height; j++) { + __m256i vsrc = _mm256_loadu_si256((__m256i *)srcp); + __m256i vsrc0 = _mm256_unpacklo_epi8(vsrc, vzero); + __m256i vsrc1 = _mm256_unpackhi_epi8(vsrc, vzero); + v_acc_sum = _mm256_add_epi16(v_acc_sum, vsrc0); + v_acc_sum = _mm256_add_epi16(v_acc_sum, vsrc1); + + __m256i vsqs0 = _mm256_madd_epi16(vsrc0, vsrc0); + __m256i vsqs1 = _mm256_madd_epi16(vsrc1, vsrc1); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs0); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs1); + + srcp += src_stride; + } + + // Update total sum and clear the vectors + s += mm256_accumulate_epi16(v_acc_sum); + ss += mm256_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process the remaining area using C + srcp = src; + for (int k = 0; k < height; k++) { + for (int m = i; m < width; m++) { + uint8_t val = srcp[m]; + s += val; + ss += val * val; + } + srcp += src_stride; + } + return (ss - s * s / (width * height)); +} + +uint64_t aom_var_2d_u16_avx2(uint8_t *src, int src_stride, int width, + int height) { + uint16_t *srcp1 = CONVERT_TO_SHORTPTR(src), *srcp; + uint64_t s = 0, ss = 0; + __m256i vzero = _mm256_setzero_si256(); + __m256i v_acc_sum = vzero; + __m256i v_acc_sqs = vzero; + int i, j; + + // Process 16 elements in a row + for (i = 0; i < width - 15; i += 16) { + srcp = srcp1 + i; + // Process 8 columns at a time + for (j = 0; j < height - 8; j += 8) { + __m256i vsrc[8]; + for (int k = 0; k < 8; k++) { + vsrc[k] = _mm256_loadu_si256((__m256i *)srcp); + srcp += src_stride; + } + for (int k = 0; k < 8; k++) { + __m256i vsrc0 = _mm256_unpacklo_epi16(vsrc[k], vzero); + __m256i vsrc1 = _mm256_unpackhi_epi16(vsrc[k], vzero); + v_acc_sum = _mm256_add_epi32(vsrc0, v_acc_sum); + v_acc_sum = _mm256_add_epi32(vsrc1, v_acc_sum); + + __m256i vsqs0 = _mm256_madd_epi16(vsrc[k], vsrc[k]); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs0); + } + + // Update total sum and clear the vectors + s += mm256_accumulate_epi32(v_acc_sum); + ss += mm256_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process remaining rows (height not a multiple of 8) + for (; j < height; j++) { + __m256i vsrc = _mm256_loadu_si256((__m256i *)srcp); + __m256i vsrc0 = _mm256_unpacklo_epi16(vsrc, vzero); + __m256i vsrc1 = _mm256_unpackhi_epi16(vsrc, vzero); + v_acc_sum = _mm256_add_epi32(vsrc0, v_acc_sum); + v_acc_sum = _mm256_add_epi32(vsrc1, v_acc_sum); + + __m256i vsqs0 = _mm256_madd_epi16(vsrc, vsrc); + v_acc_sqs = _mm256_add_epi32(v_acc_sqs, vsqs0); + srcp += src_stride; + } + + // Update total sum and clear the vectors + s += mm256_accumulate_epi32(v_acc_sum); + ss += mm256_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process the remaining area using C + srcp = srcp1; + for (int k = 0; k < height; k++) { + for (int m = i; m < width; m++) { + uint16_t val = srcp[m]; + s += val; + ss += val * val; + } + srcp += src_stride; + } + return (ss - s * s / (width * height)); +} diff --git a/media/libaom/src/aom_dsp/x86/sum_squares_sse2.c b/media/libaom/src/aom_dsp/x86/sum_squares_sse2.c index 22d7739ec4..85b301a88e 100644 --- a/media/libaom/src/aom_dsp/x86/sum_squares_sse2.c +++ b/media/libaom/src/aom_dsp/x86/sum_squares_sse2.c @@ -201,3 +201,166 @@ uint64_t aom_sum_squares_i16_sse2(const int16_t *src, uint32_t n) { return aom_sum_squares_i16_c(src, n); } } + +// Accumulate sum of 16-bit elements in the vector +static AOM_INLINE int32_t mm_accumulate_epi16(__m128i vec_a) { + __m128i vtmp = _mm_srli_si128(vec_a, 8); + vec_a = _mm_add_epi16(vec_a, vtmp); + vtmp = _mm_srli_si128(vec_a, 4); + vec_a = _mm_add_epi16(vec_a, vtmp); + vtmp = _mm_srli_si128(vec_a, 2); + vec_a = _mm_add_epi16(vec_a, vtmp); + return _mm_extract_epi16(vec_a, 0); +} + +// Accumulate sum of 32-bit elements in the vector +static AOM_INLINE int32_t mm_accumulate_epi32(__m128i vec_a) { + __m128i vtmp = _mm_srli_si128(vec_a, 8); + vec_a = _mm_add_epi32(vec_a, vtmp); + vtmp = _mm_srli_si128(vec_a, 4); + vec_a = _mm_add_epi32(vec_a, vtmp); + return _mm_cvtsi128_si32(vec_a); +} + +uint64_t aom_var_2d_u8_sse2(uint8_t *src, int src_stride, int width, + int height) { + uint8_t *srcp; + uint64_t s = 0, ss = 0; + __m128i vzero = _mm_setzero_si128(); + __m128i v_acc_sum = vzero; + __m128i v_acc_sqs = vzero; + int i, j; + + // Process 16 elements in a row + for (i = 0; i < width - 15; i += 16) { + srcp = src + i; + // Process 8 columns at a time + for (j = 0; j < height - 7; j += 8) { + __m128i vsrc[8]; + for (int k = 0; k < 8; k++) { + vsrc[k] = _mm_loadu_si128((__m128i *)srcp); + srcp += src_stride; + } + for (int k = 0; k < 8; k++) { + __m128i vsrc0 = _mm_unpacklo_epi8(vsrc[k], vzero); + __m128i vsrc1 = _mm_unpackhi_epi8(vsrc[k], vzero); + v_acc_sum = _mm_add_epi16(v_acc_sum, vsrc0); + v_acc_sum = _mm_add_epi16(v_acc_sum, vsrc1); + + __m128i vsqs0 = _mm_madd_epi16(vsrc0, vsrc0); + __m128i vsqs1 = _mm_madd_epi16(vsrc1, vsrc1); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs0); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs1); + } + + // Update total sum and clear the vectors + s += mm_accumulate_epi16(v_acc_sum); + ss += mm_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process remaining rows (height not a multiple of 8) + for (; j < height; j++) { + __m128i vsrc = _mm_loadu_si128((__m128i *)srcp); + __m128i vsrc0 = _mm_unpacklo_epi8(vsrc, vzero); + __m128i vsrc1 = _mm_unpackhi_epi8(vsrc, vzero); + v_acc_sum = _mm_add_epi16(v_acc_sum, vsrc0); + v_acc_sum = _mm_add_epi16(v_acc_sum, vsrc1); + + __m128i vsqs0 = _mm_madd_epi16(vsrc0, vsrc0); + __m128i vsqs1 = _mm_madd_epi16(vsrc1, vsrc1); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs0); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs1); + + srcp += src_stride; + } + + // Update total sum and clear the vectors + s += mm_accumulate_epi16(v_acc_sum); + ss += mm_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process the remaining area using C + srcp = src; + for (int k = 0; k < height; k++) { + for (int m = i; m < width; m++) { + uint8_t val = srcp[m]; + s += val; + ss += val * val; + } + srcp += src_stride; + } + return (ss - s * s / (width * height)); +} + +uint64_t aom_var_2d_u16_sse2(uint8_t *src, int src_stride, int width, + int height) { + uint16_t *srcp1 = CONVERT_TO_SHORTPTR(src), *srcp; + uint64_t s = 0, ss = 0; + __m128i vzero = _mm_setzero_si128(); + __m128i v_acc_sum = vzero; + __m128i v_acc_sqs = vzero; + int i, j; + + // Process 8 elements in a row + for (i = 0; i < width - 8; i += 8) { + srcp = srcp1 + i; + // Process 8 columns at a time + for (j = 0; j < height - 8; j += 8) { + __m128i vsrc[8]; + for (int k = 0; k < 8; k++) { + vsrc[k] = _mm_loadu_si128((__m128i *)srcp); + srcp += src_stride; + } + for (int k = 0; k < 8; k++) { + __m128i vsrc0 = _mm_unpacklo_epi16(vsrc[k], vzero); + __m128i vsrc1 = _mm_unpackhi_epi16(vsrc[k], vzero); + v_acc_sum = _mm_add_epi32(vsrc0, v_acc_sum); + v_acc_sum = _mm_add_epi32(vsrc1, v_acc_sum); + + __m128i vsqs0 = _mm_madd_epi16(vsrc[k], vsrc[k]); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs0); + } + + // Update total sum and clear the vectors + s += mm_accumulate_epi32(v_acc_sum); + ss += mm_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process remaining rows (height not a multiple of 8) + for (; j < height; j++) { + __m128i vsrc = _mm_loadu_si128((__m128i *)srcp); + __m128i vsrc0 = _mm_unpacklo_epi16(vsrc, vzero); + __m128i vsrc1 = _mm_unpackhi_epi16(vsrc, vzero); + v_acc_sum = _mm_add_epi32(vsrc0, v_acc_sum); + v_acc_sum = _mm_add_epi32(vsrc1, v_acc_sum); + + __m128i vsqs0 = _mm_madd_epi16(vsrc, vsrc); + v_acc_sqs = _mm_add_epi32(v_acc_sqs, vsqs0); + srcp += src_stride; + } + + // Update total sum and clear the vectors + s += mm_accumulate_epi32(v_acc_sum); + ss += mm_accumulate_epi32(v_acc_sqs); + v_acc_sum = vzero; + v_acc_sqs = vzero; + } + + // Process the remaining area using C + srcp = srcp1; + for (int k = 0; k < height; k++) { + for (int m = i; m < width; m++) { + uint16_t val = srcp[m]; + s += val; + ss += val * val; + } + srcp += src_stride; + } + return (ss - s * s / (width * height)); +} diff --git a/media/libaom/src/aom_dsp/x86/transpose_sse2.h b/media/libaom/src/aom_dsp/x86/transpose_sse2.h index d0d1ee6845..7ac692c78b 100644 --- a/media/libaom/src/aom_dsp/x86/transpose_sse2.h +++ b/media/libaom/src/aom_dsp/x86/transpose_sse2.h @@ -17,7 +17,7 @@ #include "config/aom_config.h" static INLINE __m128i transpose_8bit_4x4(const __m128i *const in) { - // Unpack 16 bit elements. Goes from: + // Unpack 8 bit elements. Goes from: // in[0]: 00 01 02 03 // in[1]: 10 11 12 13 // in[2]: 20 21 22 23 @@ -28,7 +28,7 @@ static INLINE __m128i transpose_8bit_4x4(const __m128i *const in) { const __m128i a0 = _mm_unpacklo_epi8(in[0], in[1]); const __m128i a1 = _mm_unpacklo_epi8(in[2], in[3]); - // Unpack 32 bit elements resulting in: + // Unpack 16 bit elements resulting in: // 00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33 return _mm_unpacklo_epi16(a0, a1); } diff --git a/media/libaom/src/aom_dsp/x86/txfm_common_sse2.h b/media/libaom/src/aom_dsp/x86/txfm_common_sse2.h index ed82eee962..9c99eb93bd 100644 --- a/media/libaom/src/aom_dsp/x86/txfm_common_sse2.h +++ b/media/libaom/src/aom_dsp/x86/txfm_common_sse2.h @@ -26,4 +26,8 @@ static INLINE __m128i mm_reverse_epi16(const __m128i x) { return _mm_shuffle_epi32(b, 0x4e); } +#define octa_set_epi16(a, b, c, d, e, f, g, h) \ + _mm_setr_epi16((int16_t)(a), (int16_t)(b), (int16_t)(c), (int16_t)(d), \ + (int16_t)(e), (int16_t)(f), (int16_t)(g), (int16_t)(h)) + #endif // AOM_AOM_DSP_X86_TXFM_COMMON_SSE2_H_ diff --git a/media/libaom/src/aom_dsp/x86/variance_avx2.c b/media/libaom/src/aom_dsp/x86/variance_avx2.c index 6371e2e41e..c4919ba9b4 100644 --- a/media/libaom/src/aom_dsp/x86/variance_avx2.c +++ b/media/libaom/src/aom_dsp/x86/variance_avx2.c @@ -234,6 +234,10 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, int x_offset, int y_offset, const uint8_t *dst, int dst_stride, int height, unsigned int *sse); +unsigned int aom_sub_pixel_variance16xh_avx2(const uint8_t *src, int src_stride, + int x_offset, int y_offset, + const uint8_t *dst, int dst_stride, + int height, unsigned int *sse); unsigned int aom_sub_pixel_avg_variance32xh_avx2( const uint8_t *src, int src_stride, int x_offset, int y_offset, @@ -276,6 +280,11 @@ AOM_SUB_PIXEL_VAR_AVX2(64, 32, 32, 6, 5); AOM_SUB_PIXEL_VAR_AVX2(32, 64, 32, 5, 6); AOM_SUB_PIXEL_VAR_AVX2(32, 32, 32, 5, 5); AOM_SUB_PIXEL_VAR_AVX2(32, 16, 32, 5, 4); +AOM_SUB_PIXEL_VAR_AVX2(16, 64, 16, 4, 6); +AOM_SUB_PIXEL_VAR_AVX2(16, 32, 16, 4, 5); +AOM_SUB_PIXEL_VAR_AVX2(16, 16, 16, 4, 4); +AOM_SUB_PIXEL_VAR_AVX2(16, 8, 16, 4, 3); +AOM_SUB_PIXEL_VAR_AVX2(16, 4, 16, 4, 2); #define AOM_SUB_PIXEL_AVG_VAR_AVX2(w, h, wf, wlog2, hlog2) \ unsigned int aom_sub_pixel_avg_variance##w##x##h##_avx2( \ diff --git a/media/libaom/src/aom_dsp/x86/variance_impl_avx2.c b/media/libaom/src/aom_dsp/x86/variance_impl_avx2.c index 88e27aef3a..f779270ae3 100644 --- a/media/libaom/src/aom_dsp/x86/variance_impl_avx2.c +++ b/media/libaom/src/aom_dsp/x86/variance_impl_avx2.c @@ -104,6 +104,65 @@ DECLARE_ALIGNED(32, static const uint8_t, bilinear_filters_avx2[512]) = { sum = _mm_cvtsi128_si32(_mm256_castsi256_si128(sum_reg)) + \ _mm_cvtsi128_si32(_mm256_extractf128_si256(sum_reg, 1)); +// Functions related to sub pixel variance width 16 +#define LOAD_SRC_DST_INSERT(src_stride, dst_stride) \ + /* load source and destination of 2 rows and insert*/ \ + src_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(src))), \ + _mm_loadu_si128((__m128i *)(src + src_stride)), 1); \ + dst_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(dst))), \ + _mm_loadu_si128((__m128i *)(dst + dst_stride)), 1); + +#define AVG_NEXT_SRC_INSERT(src_reg, size_stride) \ + src_next_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(src + size_stride))), \ + _mm_loadu_si128((__m128i *)(src + (size_stride << 1))), 1); \ + /* average between current and next stride source */ \ + src_reg = _mm256_avg_epu8(src_reg, src_next_reg); + +#define MERGE_NEXT_SRC_INSERT(src_reg, size_stride) \ + src_next_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(src + size_stride))), \ + _mm_loadu_si128((__m128i *)(src + (src_stride + size_stride))), 1); \ + MERGE_WITH_SRC(src_reg, src_next_reg) + +#define LOAD_SRC_NEXT_BYTE_INSERT \ + /* load source and another source from next row */ \ + src_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(src))), \ + _mm_loadu_si128((__m128i *)(src + src_stride)), 1); \ + /* load source and next row source from 1 byte onwards */ \ + src_next_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(src + 1))), \ + _mm_loadu_si128((__m128i *)(src + src_stride + 1)), 1); + +#define LOAD_DST_INSERT \ + dst_reg = _mm256_inserti128_si256( \ + _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)(dst))), \ + _mm_loadu_si128((__m128i *)(dst + dst_stride)), 1); + +#define LOAD_SRC_MERGE_128BIT(filter) \ + __m128i src_reg_0 = _mm_loadu_si128((__m128i *)(src)); \ + __m128i src_reg_1 = _mm_loadu_si128((__m128i *)(src + 1)); \ + __m128i src_lo = _mm_unpacklo_epi8(src_reg_0, src_reg_1); \ + __m128i src_hi = _mm_unpackhi_epi8(src_reg_0, src_reg_1); \ + __m128i filter_128bit = _mm256_castsi256_si128(filter); \ + __m128i pw8_128bit = _mm256_castsi256_si128(pw8); + +#define FILTER_SRC_128BIT(filter) \ + /* filter the source */ \ + src_lo = _mm_maddubs_epi16(src_lo, filter); \ + src_hi = _mm_maddubs_epi16(src_hi, filter); \ + \ + /* add 8 to source */ \ + src_lo = _mm_add_epi16(src_lo, pw8_128bit); \ + src_hi = _mm_add_epi16(src_hi, pw8_128bit); \ + \ + /* divide source by 16 */ \ + src_lo = _mm_srai_epi16(src_lo, 4); \ + src_hi = _mm_srai_epi16(src_hi, 4); + unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, int x_offset, int y_offset, const uint8_t *dst, int dst_stride, @@ -127,8 +186,8 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, src += src_stride; dst += dst_stride; } - // x_offset = 0 and y_offset = 8 - } else if (y_offset == 8) { + // x_offset = 0 and y_offset = 4 + } else if (y_offset == 4) { __m256i src_next_reg; for (i = 0; i < height; i++) { LOAD_SRC_DST @@ -156,8 +215,8 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, dst += dst_stride; } } - // x_offset = 8 and y_offset = 0 - } else if (x_offset == 8) { + // x_offset = 4 and y_offset = 0 + } else if (x_offset == 4) { if (y_offset == 0) { __m256i src_next_reg; for (i = 0; i < height; i++) { @@ -169,8 +228,8 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, src += src_stride; dst += dst_stride; } - // x_offset = 8 and y_offset = 8 - } else if (y_offset == 8) { + // x_offset = 4 and y_offset = 4 + } else if (y_offset == 4) { __m256i src_next_reg, src_avg; // load source and another source starting from the next // following byte @@ -189,7 +248,7 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, CALC_SUM_SSE_INSIDE_LOOP dst += dst_stride; } - // x_offset = 8 and y_offset = bilin interpolation + // x_offset = 4 and y_offset = bilin interpolation } else { __m256i filter, pw8, src_next_reg, src_avg; y_offset <<= 5; @@ -228,8 +287,8 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, src += src_stride; dst += dst_stride; } - // x_offset = bilin interpolation and y_offset = 8 - } else if (y_offset == 8) { + // x_offset = bilin interpolation and y_offset = 4 + } else if (y_offset == 4) { __m256i filter, pw8, src_next_reg, src_pack; x_offset <<= 5; filter = _mm256_load_si256( @@ -292,6 +351,244 @@ unsigned int aom_sub_pixel_variance32xh_avx2(const uint8_t *src, int src_stride, return sum; } +unsigned int aom_sub_pixel_variance16xh_avx2(const uint8_t *src, int src_stride, + int x_offset, int y_offset, + const uint8_t *dst, int dst_stride, + int height, unsigned int *sse) { + __m256i src_reg, dst_reg, exp_src_lo, exp_src_hi, exp_dst_lo, exp_dst_hi; + __m256i sse_reg, sum_reg, sse_reg_hi, res_cmp, sum_reg_lo, sum_reg_hi; + __m256i zero_reg; + int i, sum; + sum_reg = _mm256_set1_epi16(0); + sse_reg = _mm256_set1_epi16(0); + zero_reg = _mm256_set1_epi16(0); + + // x_offset = 0 and y_offset = 0 + if (x_offset == 0) { + if (y_offset == 0) { + for (i = 0; i < height; i += 2) { + LOAD_SRC_DST_INSERT(src_stride, dst_stride) + // expend each byte to 2 bytes + MERGE_WITH_SRC(src_reg, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + src += (src_stride << 1); + dst += (dst_stride << 1); + } + // x_offset = 0 and y_offset = 4 + } else if (y_offset == 4) { + __m256i src_next_reg; + for (i = 0; i < height; i += 2) { + LOAD_SRC_DST_INSERT(src_stride, dst_stride) + AVG_NEXT_SRC_INSERT(src_reg, src_stride) + // expend each byte to 2 bytes + MERGE_WITH_SRC(src_reg, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + src += (src_stride << 1); + dst += (dst_stride << 1); + } + // x_offset = 0 and y_offset = bilin interpolation + } else { + __m256i filter, pw8, src_next_reg; + y_offset <<= 5; + filter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + y_offset)); + pw8 = _mm256_set1_epi16(8); + for (i = 0; i < height; i += 2) { + LOAD_SRC_DST_INSERT(src_stride, dst_stride) + MERGE_NEXT_SRC_INSERT(src_reg, src_stride) + FILTER_SRC(filter) + CALC_SUM_SSE_INSIDE_LOOP + src += (src_stride << 1); + dst += (dst_stride << 1); + } + } + // x_offset = 4 and y_offset = 0 + } else if (x_offset == 4) { + if (y_offset == 0) { + __m256i src_next_reg; + for (i = 0; i < height; i += 2) { + LOAD_SRC_NEXT_BYTE_INSERT + LOAD_DST_INSERT + /* average between current and next stride source */ + src_reg = _mm256_avg_epu8(src_reg, src_next_reg); + // expand each byte to 2 bytes + MERGE_WITH_SRC(src_reg, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + src += (src_stride << 1); + dst += (dst_stride << 1); + } + // x_offset = 4 and y_offset = 4 + } else if (y_offset == 4) { + __m256i src_next_reg, src_avg, src_temp; + // load and insert source and next row source + LOAD_SRC_NEXT_BYTE_INSERT + src_avg = _mm256_avg_epu8(src_reg, src_next_reg); + src += src_stride << 1; + for (i = 0; i < height - 2; i += 2) { + LOAD_SRC_NEXT_BYTE_INSERT + src_next_reg = _mm256_avg_epu8(src_reg, src_next_reg); + src_temp = _mm256_permute2x128_si256(src_avg, src_next_reg, 0x21); + src_temp = _mm256_avg_epu8(src_avg, src_temp); + LOAD_DST_INSERT + // expand each byte to 2 bytes + MERGE_WITH_SRC(src_temp, zero_reg) + // save current source average + src_avg = src_next_reg; + CALC_SUM_SSE_INSIDE_LOOP + dst += dst_stride << 1; + src += src_stride << 1; + } + // last 2 rows processing happens here + __m128i src_reg_0 = _mm_loadu_si128((__m128i *)(src)); + __m128i src_reg_1 = _mm_loadu_si128((__m128i *)(src + 1)); + src_reg_0 = _mm_avg_epu8(src_reg_0, src_reg_1); + src_next_reg = _mm256_permute2x128_si256( + src_avg, _mm256_castsi128_si256(src_reg_0), 0x21); + LOAD_DST_INSERT + src_avg = _mm256_avg_epu8(src_avg, src_next_reg); + MERGE_WITH_SRC(src_avg, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + } else { + // x_offset = 4 and y_offset = bilin interpolation + __m256i filter, pw8, src_next_reg, src_avg, src_temp; + y_offset <<= 5; + filter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + y_offset)); + pw8 = _mm256_set1_epi16(8); + // load and insert source and next row source + LOAD_SRC_NEXT_BYTE_INSERT + src_avg = _mm256_avg_epu8(src_reg, src_next_reg); + src += src_stride << 1; + for (i = 0; i < height - 2; i += 2) { + LOAD_SRC_NEXT_BYTE_INSERT + src_next_reg = _mm256_avg_epu8(src_reg, src_next_reg); + src_temp = _mm256_permute2x128_si256(src_avg, src_next_reg, 0x21); + LOAD_DST_INSERT + MERGE_WITH_SRC(src_avg, src_temp) + // save current source average + src_avg = src_next_reg; + FILTER_SRC(filter) + CALC_SUM_SSE_INSIDE_LOOP + dst += dst_stride << 1; + src += src_stride << 1; + } + // last 2 rows processing happens here + __m128i src_reg_0 = _mm_loadu_si128((__m128i *)(src)); + __m128i src_reg_1 = _mm_loadu_si128((__m128i *)(src + 1)); + src_reg_0 = _mm_avg_epu8(src_reg_0, src_reg_1); + src_next_reg = _mm256_permute2x128_si256( + src_avg, _mm256_castsi128_si256(src_reg_0), 0x21); + LOAD_DST_INSERT + MERGE_WITH_SRC(src_avg, src_next_reg) + FILTER_SRC(filter) + CALC_SUM_SSE_INSIDE_LOOP + } + // x_offset = bilin interpolation and y_offset = 0 + } else { + if (y_offset == 0) { + __m256i filter, pw8, src_next_reg; + x_offset <<= 5; + filter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + x_offset)); + pw8 = _mm256_set1_epi16(8); + for (i = 0; i < height; i += 2) { + LOAD_SRC_DST_INSERT(src_stride, dst_stride) + MERGE_NEXT_SRC_INSERT(src_reg, 1) + FILTER_SRC(filter) + CALC_SUM_SSE_INSIDE_LOOP + src += (src_stride << 1); + dst += (dst_stride << 1); + } + // x_offset = bilin interpolation and y_offset = 4 + } else if (y_offset == 4) { + __m256i filter, pw8, src_next_reg, src_pack; + x_offset <<= 5; + filter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + x_offset)); + pw8 = _mm256_set1_epi16(8); + // load and insert source and next row source + LOAD_SRC_NEXT_BYTE_INSERT + MERGE_WITH_SRC(src_reg, src_next_reg) + FILTER_SRC(filter) + // convert each 16 bit to 8 bit to each low and high lane source + src_pack = _mm256_packus_epi16(exp_src_lo, exp_src_hi); + src += src_stride << 1; + for (i = 0; i < height - 2; i += 2) { + LOAD_SRC_NEXT_BYTE_INSERT + LOAD_DST_INSERT + MERGE_WITH_SRC(src_reg, src_next_reg) + FILTER_SRC(filter) + src_reg = _mm256_packus_epi16(exp_src_lo, exp_src_hi); + src_next_reg = _mm256_permute2x128_si256(src_pack, src_reg, 0x21); + // average between previous pack to the current + src_pack = _mm256_avg_epu8(src_pack, src_next_reg); + MERGE_WITH_SRC(src_pack, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + src_pack = src_reg; + src += src_stride << 1; + dst += dst_stride << 1; + } + // last 2 rows processing happens here + LOAD_SRC_MERGE_128BIT(filter) + LOAD_DST_INSERT + FILTER_SRC_128BIT(filter_128bit) + src_reg_0 = _mm_packus_epi16(src_lo, src_hi); + src_next_reg = _mm256_permute2x128_si256( + src_pack, _mm256_castsi128_si256(src_reg_0), 0x21); + // average between previous pack to the current + src_pack = _mm256_avg_epu8(src_pack, src_next_reg); + MERGE_WITH_SRC(src_pack, zero_reg) + CALC_SUM_SSE_INSIDE_LOOP + } else { + // x_offset = bilin interpolation and y_offset = bilin interpolation + __m256i xfilter, yfilter, pw8, src_next_reg, src_pack; + x_offset <<= 5; + xfilter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + x_offset)); + y_offset <<= 5; + yfilter = _mm256_load_si256( + (__m256i const *)(bilinear_filters_avx2 + y_offset)); + pw8 = _mm256_set1_epi16(8); + // load and insert source and next row source + LOAD_SRC_NEXT_BYTE_INSERT + MERGE_WITH_SRC(src_reg, src_next_reg) + FILTER_SRC(xfilter) + // convert each 16 bit to 8 bit to each low and high lane source + src_pack = _mm256_packus_epi16(exp_src_lo, exp_src_hi); + src += src_stride << 1; + for (i = 0; i < height - 2; i += 2) { + LOAD_SRC_NEXT_BYTE_INSERT + LOAD_DST_INSERT + MERGE_WITH_SRC(src_reg, src_next_reg) + FILTER_SRC(xfilter) + src_reg = _mm256_packus_epi16(exp_src_lo, exp_src_hi); + src_next_reg = _mm256_permute2x128_si256(src_pack, src_reg, 0x21); + // average between previous pack to the current + MERGE_WITH_SRC(src_pack, src_next_reg) + // filter the source + FILTER_SRC(yfilter) + src_pack = src_reg; + CALC_SUM_SSE_INSIDE_LOOP + src += src_stride << 1; + dst += dst_stride << 1; + } + // last 2 rows processing happens here + LOAD_SRC_MERGE_128BIT(xfilter) + LOAD_DST_INSERT + FILTER_SRC_128BIT(filter_128bit) + src_reg_0 = _mm_packus_epi16(src_lo, src_hi); + src_next_reg = _mm256_permute2x128_si256( + src_pack, _mm256_castsi128_si256(src_reg_0), 0x21); + MERGE_WITH_SRC(src_pack, src_next_reg) + FILTER_SRC(yfilter) + CALC_SUM_SSE_INSIDE_LOOP + } + } + CALC_SUM_AND_SSE + _mm256_zeroupper(); + return sum; +} + unsigned int aom_sub_pixel_avg_variance32xh_avx2( const uint8_t *src, int src_stride, int x_offset, int y_offset, const uint8_t *dst, int dst_stride, const uint8_t *sec, int sec_stride, diff --git a/media/libaom/src/aom_dsp/x86/variance_sse2.c b/media/libaom/src/aom_dsp/x86/variance_sse2.c index 986b3f2793..4e2b5a1aa0 100644 --- a/media/libaom/src/aom_dsp/x86/variance_sse2.c +++ b/media/libaom/src/aom_dsp/x86/variance_sse2.c @@ -21,9 +21,10 @@ #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/filter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" +#include "av1/encoder/reconinter_enc.h" unsigned int aom_get_mb_ss_sse2(const int16_t *src) { __m128i vsum = _mm_setzero_si128(); @@ -507,68 +508,24 @@ void aom_upsampled_pred_sse2(MACROBLOCKD *xd, const struct AV1Common *const cm, const int is_scaled = av1_is_scaled(sf); if (is_scaled) { - // Note: This is mostly a copy from the >=8X8 case in - // build_inter_predictors() function, with some small tweaks. - - // Some assumptions. - const int plane = 0; - - // Get pre-requisites. + int plane = 0; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int ssx = pd->subsampling_x; - const int ssy = pd->subsampling_y; - assert(ssx == 0 && ssy == 0); const struct buf_2d *const dst_buf = &pd->dst; const struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref_num]; - const int mi_x = mi_col * MI_SIZE; - const int mi_y = mi_row * MI_SIZE; - - // Calculate subpel_x/y and x/y_step. - const int row_start = 0; // Because ss_y is 0. - const int col_start = 0; // Because ss_x is 0. - const int pre_x = (mi_x + MI_SIZE * col_start) >> ssx; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ssy; - int orig_pos_y = pre_y << SUBPEL_BITS; - orig_pos_y += mv->row * (1 << (1 - ssy)); - int orig_pos_x = pre_x << SUBPEL_BITS; - orig_pos_x += mv->col * (1 << (1 - ssx)); - int pos_y = sf->scale_value_y(orig_pos_y, sf); - int pos_x = sf->scale_value_x(orig_pos_x, sf); - pos_x += SCALE_EXTRA_OFF; - pos_y += SCALE_EXTRA_OFF; - - const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); - const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); - const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - const int right = (pre_buf->width + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - pos_y = clamp(pos_y, top, bottom); - pos_x = clamp(pos_x, left, right); - - const uint8_t *const pre = - pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + - (pos_x >> SCALE_SUBPEL_BITS); InterPredParams inter_pred_params; - const SubpelParams subpel_params = { sf->x_step_q4, sf->y_step_q4, - pos_x & SCALE_SUBPEL_MASK, - pos_y & SCALE_SUBPEL_MASK }; - - // Get convolve parameters. inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); const int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); av1_init_inter_params( &inter_pred_params, width, height, mi_y >> pd->subsampling_y, mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, filters); - - // Get the inter predictor. - av1_make_inter_predictor(pre, pre_buf->stride, comp_pred, width, - &inter_pred_params, &subpel_params); - + xd->bd, is_cur_buf_hbd(xd), is_intrabc, sf, pre_buf, filters); + av1_enc_build_one_inter_predictor(comp_pred, width, mv, + &inter_pred_params); return; } } diff --git a/media/libaom/src/aom_mem/aom_mem.cmake b/media/libaom/src/aom_mem/aom_mem.cmake index eaee8440b8..346588d2db 100644 --- a/media/libaom/src/aom_mem/aom_mem.cmake +++ b/media/libaom/src/aom_mem/aom_mem.cmake @@ -23,4 +23,7 @@ function(setup_aom_mem_targets) add_library(aom_mem OBJECT ${AOM_MEM_SOURCES}) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_mem PARENT_SCOPE) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endfunction() diff --git a/media/libaom/src/aom_mem/aom_mem.h b/media/libaom/src/aom_mem/aom_mem.h index f533ab9f8b..bc5d8bca35 100644 --- a/media/libaom/src/aom_mem/aom_mem.h +++ b/media/libaom/src/aom_mem/aom_mem.h @@ -40,7 +40,7 @@ void *aom_memset16(void *dest, int val, size_t length); /*returns an addr aligned to the byte boundary specified by align*/ #define aom_align_addr(addr, align) \ - (void *)(((size_t)(addr) + ((align)-1)) & ~(size_t)((align)-1)) + (void *)(((uintptr_t)(addr) + ((align)-1)) & ~(uintptr_t)((align)-1)) #include diff --git a/media/libaom/src/aom_ports/aom_ports.cmake b/media/libaom/src/aom_ports/aom_ports.cmake index 8897fff2a0..d579896549 100644 --- a/media/libaom/src/aom_ports/aom_ports.cmake +++ b/media/libaom/src/aom_ports/aom_ports.cmake @@ -49,16 +49,21 @@ list(APPEND AOM_PORTS_SOURCES_PPC "${AOM_ROOT}/aom_ports/ppc.h" # * The libaom target must exist before this function is called. function(setup_aom_ports_targets) if("${AOM_TARGET_CPU}" MATCHES "^x86") - add_asm_library("aom_ports" "AOM_PORTS_ASM_X86" "aom") + add_asm_library("aom_ports" "AOM_PORTS_ASM_X86") set(aom_ports_has_symbols 1) elseif("${AOM_TARGET_CPU}" MATCHES "arm") add_library(aom_ports OBJECT ${AOM_PORTS_SOURCES_ARM}) set(aom_ports_has_symbols 1) - target_sources(aom PRIVATE $) elseif("${AOM_TARGET_CPU}" MATCHES "ppc") add_library(aom_ports OBJECT ${AOM_PORTS_SOURCES_PPC}) set(aom_ports_has_symbols 1) + endif() + + if("${AOM_TARGET_CPU}" MATCHES "arm|ppc") target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endif() if(aom_ports_has_symbols) @@ -72,10 +77,16 @@ function(setup_aom_ports_targets) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE) else() target_sources(aom PRIVATE ${AOM_PORTS_INCLUDES}) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE ${AOM_PORTS_INCLUDES}) + endif() if("${AOM_TARGET_CPU}" STREQUAL "x86" OR "${AOM_TARGET_CPU}" STREQUAL "x86_64") target_sources(aom PRIVATE ${AOM_PORTS_INCLUDES_X86}) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE ${AOM_PORTS_INCLUDES_X86}) + endif() endif() endif() endfunction() diff --git a/media/libaom/src/aom_ports/ppc_cpudetect.c b/media/libaom/src/aom_ports/ppc_cpudetect.c index 82b4f58ccc..ce4d5ae231 100644 --- a/media/libaom/src/aom_ports/ppc_cpudetect.c +++ b/media/libaom/src/aom_ports/ppc_cpudetect.c @@ -45,7 +45,7 @@ int ppc_simd_caps(void) { unsigned int i; uint64_t buf[64]; - // If VPX_SIMD_CAPS is set then allow only those capabilities. + // If AOM_SIMD_CAPS_MASK is set then allow only those capabilities. if (!cpu_env_flags(&flags)) { return flags; } diff --git a/media/libaom/src/aom_ports/x86_abi_support.asm b/media/libaom/src/aom_ports/x86_abi_support.asm index 0e7c262873..64489908f0 100644 --- a/media/libaom/src/aom_ports/x86_abi_support.asm +++ b/media/libaom/src/aom_ports/x86_abi_support.asm @@ -122,6 +122,13 @@ ; http://www.tortall.net/projects/yasm/ticket/236 ; %ifdef CHROMIUM + %ifdef __NASM_VER__ + %if __NASM_VERSION_ID__ < 0x020e0000 ; 2.14 + ; nasm < 2.14 does not support :private_extern directive + %fatal Must use nasm 2.14 or newer + %endif + %endif + %ifidn __OUTPUT_FORMAT__,elf32 %define PRIVATE :hidden %elifidn __OUTPUT_FORMAT__,elf64 diff --git a/media/libaom/src/aom_scale/aom_scale.cmake b/media/libaom/src/aom_scale/aom_scale.cmake index 31997333ea..e83299320f 100644 --- a/media/libaom/src/aom_scale/aom_scale.cmake +++ b/media/libaom/src/aom_scale/aom_scale.cmake @@ -31,10 +31,13 @@ function(setup_aom_scale_targets) if(HAVE_DSPR2) add_intrinsics_object_library("" "dspr2" "aom_scale" - "AOM_SCALE_INTRIN_DSPR2" "aom") + "AOM_SCALE_INTRIN_DSPR2") endif() target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() # Pass the new lib targets up to the parent scope instance of # $AOM_LIB_TARGETS. diff --git a/media/libaom/src/aom_scale/generic/yv12config.c b/media/libaom/src/aom_scale/generic/yv12config.c index 8de35316c1..1f80d7ba72 100644 --- a/media/libaom/src/aom_scale/generic/yv12config.c +++ b/media/libaom/src/aom_scale/generic/yv12config.c @@ -11,6 +11,7 @@ #include +#include "aom/internal/aom_image_internal.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" #include "aom_scale/yv12config.h" @@ -228,54 +229,6 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, return AOM_CODEC_MEM_ERROR; } -// 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 AOM_CODEC_MEM_ERROR; -} - 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) { @@ -288,25 +241,23 @@ int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, return AOM_CODEC_MEM_ERROR; } -size_t aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf) { +void aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf) { if (ybf && ybf->metadata) { - size_t sz = aom_img_metadata_array_free(ybf->metadata); + aom_img_metadata_array_free(ybf->metadata); ybf->metadata = NULL; - return sz; } - return 0; } int aom_copy_metadata_to_frame_buffer(YV12_BUFFER_CONFIG *ybf, - aom_metadata_array_t *arr) { + const aom_metadata_array_t *arr) { if (!ybf || !arr || !arr->metadata_array) return -1; aom_remove_metadata_from_frame_buffer(ybf); ybf->metadata = aom_img_metadata_array_alloc(arr->sz); - if (!ybf->metadata) return 0; + if (!ybf->metadata) return -1; for (size_t i = 0; i < ybf->metadata->sz; i++) { ybf->metadata->metadata_array[i] = aom_img_metadata_alloc( arr->metadata_array[i]->type, arr->metadata_array[i]->payload, - arr->metadata_array[i]->sz); + arr->metadata_array[i]->sz, arr->metadata_array[i]->insert_flag); if (ybf->metadata->metadata_array[i] == NULL) { aom_img_metadata_array_free(ybf->metadata); ybf->metadata = NULL; diff --git a/media/libaom/src/aom_scale/yv12config.h b/media/libaom/src/aom_scale/yv12config.h index 43856f0bdb..3642bb7f37 100644 --- a/media/libaom/src/aom_scale/yv12config.h +++ b/media/libaom/src/aom_scale/yv12config.h @@ -27,7 +27,6 @@ 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 { @@ -128,24 +127,16 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, 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); /*!\brief Removes metadata from YUV_BUFFER_CONFIG struct. * * Frees metadata in frame buffer. * Frame buffer metadata pointer will be set to NULL. - * Returns the number of deleted metadata structs. * * \param[in] ybf Frame buffer struct pointer */ -size_t aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf); +void aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf); /*!\brief Copy metadata to YUV_BUFFER_CONFIG struct. * @@ -159,7 +150,7 @@ size_t aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf); * \param[in] arr Metadata array struct pointer */ int aom_copy_metadata_to_frame_buffer(YV12_BUFFER_CONFIG *ybf, - aom_metadata_array_t *arr); + const aom_metadata_array_t *arr); #ifdef __cplusplus } diff --git a/media/libaom/src/aom_util/aom_thread.c b/media/libaom/src/aom_util/aom_thread.c index 244ac3bc29..a749a22401 100644 --- a/media/libaom/src/aom_util/aom_thread.c +++ b/media/libaom/src/aom_util/aom_thread.c @@ -48,7 +48,7 @@ static THREADFN thread_loop(void *ptr) { // thread_name is too long, pthread_setname_np returns -1 with errno // ENAMETOOLONG (63). char thread_name[64]; - strncpy(thread_name, worker->thread_name, sizeof(thread_name)); + strncpy(thread_name, worker->thread_name, sizeof(thread_name) - 1); thread_name[sizeof(thread_name) - 1] = '\0'; pthread_setname_np(thread_name); } @@ -57,7 +57,7 @@ static THREADFN thread_loop(void *ptr) { // Linux and Android require names (with nul) fit in 16 chars, otherwise // pthread_setname_np() returns ERANGE (34). char thread_name[16]; - strncpy(thread_name, worker->thread_name, sizeof(thread_name)); + strncpy(thread_name, worker->thread_name, sizeof(thread_name) - 1); thread_name[sizeof(thread_name) - 1] = '\0'; pthread_setname_np(pthread_self(), thread_name); } diff --git a/media/libaom/src/aom_util/aom_thread.h b/media/libaom/src/aom_util/aom_thread.h index bda8b756ec..8d0431258f 100644 --- a/media/libaom/src/aom_util/aom_thread.h +++ b/media/libaom/src/aom_util/aom_thread.h @@ -23,9 +23,6 @@ extern "C" { #endif -// Set maximum decode threads to be 8 due to the limit of frame buffers -// and not enough semaphores in the emulation layer on windows. -#define MAX_DECODE_THREADS 8 #define MAX_NUM_THREADS 64 #if CONFIG_MULTITHREAD @@ -37,16 +34,10 @@ extern "C" { typedef HANDLE pthread_t; typedef CRITICAL_SECTION pthread_mutex_t; -#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater -#define USE_WINDOWS_CONDITION_VARIABLE +#if _WIN32_WINNT < 0x0600 +#error _WIN32_WINNT must target Windows Vista / Server 2008 or newer. +#endif typedef CONDITION_VARIABLE pthread_cond_t; -#else -typedef struct { - HANDLE waiting_sem_; - HANDLE received_sem_; - HANDLE signal_event_; -} pthread_cond_t; -#endif // _WIN32_WINNT >= 0x600 #ifndef WINAPI_FAMILY_PARTITION #define WINAPI_PARTITION_DESKTOP 1 @@ -64,11 +55,6 @@ typedef struct { #define THREADFN unsigned int __stdcall #define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) -#if _WIN32_WINNT >= 0x0501 // Windows XP or greater -#define WaitForSingleObject(obj, timeout) \ - WaitForSingleObjectEx(obj, timeout, FALSE /*bAlertable*/) -#endif - static INLINE int pthread_create(pthread_t *const thread, const void *attr, unsigned int(__stdcall *start)(void *), void *arg) { @@ -91,7 +77,8 @@ static INLINE int pthread_create(pthread_t *const thread, const void *attr, static INLINE int pthread_join(pthread_t thread, void **value_ptr) { (void)value_ptr; - return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || + return (WaitForSingleObjectEx(thread, INFINITE, FALSE /*bAlertable*/) != + WAIT_OBJECT_0 || CloseHandle(thread) == 0); } @@ -99,11 +86,7 @@ static INLINE int pthread_join(pthread_t thread, void **value_ptr) { static INLINE int pthread_mutex_init(pthread_mutex_t *const mutex, void *mutexattr) { (void)mutexattr; -#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/); -#else - InitializeCriticalSection(mutex); -#endif return 0; } @@ -128,85 +111,31 @@ static INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) { // Condition static INLINE int pthread_cond_destroy(pthread_cond_t *const condition) { - int ok = 1; -#ifdef USE_WINDOWS_CONDITION_VARIABLE (void)condition; -#else - ok &= (CloseHandle(condition->waiting_sem_) != 0); - ok &= (CloseHandle(condition->received_sem_) != 0); - ok &= (CloseHandle(condition->signal_event_) != 0); -#endif - return !ok; + return 0; } static INLINE int pthread_cond_init(pthread_cond_t *const condition, void *cond_attr) { (void)cond_attr; -#ifdef USE_WINDOWS_CONDITION_VARIABLE InitializeConditionVariable(condition); -#else - condition->waiting_sem_ = CreateSemaphore(NULL, 0, MAX_DECODE_THREADS, NULL); - condition->received_sem_ = CreateSemaphore(NULL, 0, MAX_DECODE_THREADS, NULL); - condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); - if (condition->waiting_sem_ == NULL || condition->received_sem_ == NULL || - condition->signal_event_ == NULL) { - pthread_cond_destroy(condition); - return 1; - } -#endif return 0; } static INLINE int pthread_cond_signal(pthread_cond_t *const condition) { - int ok = 1; -#ifdef USE_WINDOWS_CONDITION_VARIABLE WakeConditionVariable(condition); -#else - if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { - // a thread is waiting in pthread_cond_wait: allow it to be notified - ok = SetEvent(condition->signal_event_); - // wait until the event is consumed so the signaler cannot consume - // the event via its own pthread_cond_wait. - ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != - WAIT_OBJECT_0); - } -#endif - return !ok; + return 0; } static INLINE int pthread_cond_broadcast(pthread_cond_t *const condition) { - int ok = 1; -#ifdef USE_WINDOWS_CONDITION_VARIABLE WakeAllConditionVariable(condition); -#else - while (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { - // a thread is waiting in pthread_cond_wait: allow it to be notified - ok &= SetEvent(condition->signal_event_); - // wait until the event is consumed so the signaler cannot consume - // the event via its own pthread_cond_wait. - ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != - WAIT_OBJECT_0); - } -#endif - return !ok; + return 0; } static INLINE int pthread_cond_wait(pthread_cond_t *const condition, pthread_mutex_t *const mutex) { int ok; -#ifdef USE_WINDOWS_CONDITION_VARIABLE ok = SleepConditionVariableCS(condition, mutex, INFINITE); -#else - // note that there is a consumer available so the signal isn't dropped in - // pthread_cond_signal - if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1; - // now unlock the mutex so pthread_cond_signal may be issued - pthread_mutex_unlock(mutex); - ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == - WAIT_OBJECT_0); - ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); - pthread_mutex_lock(mutex); -#endif return !ok; } #elif defined(__OS2__) diff --git a/media/libaom/src/aom_util/aom_util.cmake b/media/libaom/src/aom_util/aom_util.cmake index d4f3bce74d..1a1bfe1e67 100644 --- a/media/libaom/src/aom_util/aom_util.cmake +++ b/media/libaom/src/aom_util/aom_util.cmake @@ -25,4 +25,7 @@ function(setup_aom_util_targets) add_library(aom_util OBJECT ${AOM_UTIL_SOURCES}) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_util PARENT_SCOPE) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endfunction() diff --git a/media/libaom/src/apps/aomdec.c b/media/libaom/src/apps/aomdec.c index acecc90b55..2591d41a6c 100644 --- a/media/libaom/src/apps/aomdec.c +++ b/media/libaom/src/apps/aomdec.c @@ -76,8 +76,6 @@ static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames"); static const arg_def_t skiparg = ARG_DEF(NULL, "skip", 1, "Skip the first n input frames"); -static const arg_def_t postprocarg = - ARG_DEF(NULL, "postproc", 0, "Postprocess decoded frames"); static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0, "Show timing summary"); static const arg_def_t outputfile = @@ -108,13 +106,11 @@ static const arg_def_t skipfilmgrain = ARG_DEF(NULL, "skip-film-grain", 0, "Skip film grain application"); static const arg_def_t *all_args[] = { - &help, &codecarg, &use_yv12, &use_i420, - &flipuvarg, &rawvideo, &noblitarg, &progressarg, - &limitarg, &skiparg, &postprocarg, &summaryarg, - &outputfile, &threadsarg, &verbosearg, &scalearg, - &fb_arg, &md5arg, &framestatsarg, &continuearg, - &outbitdeptharg, &isannexb, &oppointarg, &outallarg, - &skipfilmgrain, NULL + &help, &codecarg, &use_yv12, &use_i420, &flipuvarg, + &rawvideo, &noblitarg, &progressarg, &limitarg, &skiparg, + &summaryarg, &outputfile, &threadsarg, &verbosearg, &scalearg, + &fb_arg, &md5arg, &framestatsarg, &continuearg, &outbitdeptharg, + &isannexb, &oppointarg, &outallarg, &skipfilmgrain, NULL }; #if CONFIG_LIBYUV @@ -437,7 +433,7 @@ static int main_loop(int argc, const char **argv_) { FILE *infile; int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0; int do_md5 = 0, progress = 0; - int stop_after = 0, postproc = 0, summary = 0, quiet = 1; + int stop_after = 0, summary = 0, quiet = 1; int arg_skip = 0; int keep_going = 0; const AvxInterface *interface = NULL; @@ -536,8 +532,6 @@ static int main_loop(int argc, const char **argv_) { stop_after = arg_parse_uint(&arg); } else if (arg_match(&arg, &skiparg, argi)) { arg_skip = arg_parse_uint(&arg); - } else if (arg_match(&arg, &postprocarg, argi)) { - postproc = 1; } else if (arg_match(&arg, &md5arg, argi)) { do_md5 = 1; } else if (arg_match(&arg, &framestatsarg, argi)) { @@ -628,6 +622,7 @@ static int main_loop(int argc, const char **argv_) { #if !CONFIG_WEBM_IO fprintf(stderr, "aomdec was built without WebM container support.\n"); #endif + free(argv); return EXIT_FAILURE; } @@ -675,7 +670,7 @@ static int main_loop(int argc, const char **argv_) { if (!interface) interface = get_aom_decoder_by_index(0); - dec_flags = (postproc ? AOM_CODEC_USE_POSTPROC : 0); + dec_flags = 0; if (aom_codec_dec_init(&decoder, interface->codec_interface(), &cfg, dec_flags)) { fprintf(stderr, "Failed to initialize decoder: %s\n", @@ -685,25 +680,27 @@ static int main_loop(int argc, const char **argv_) { if (!quiet) fprintf(stderr, "%s\n", decoder.name); - if (aom_codec_control(&decoder, AV1D_SET_IS_ANNEXB, is_annexb)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AV1D_SET_IS_ANNEXB, is_annexb)) { fprintf(stderr, "Failed to set is_annexb: %s\n", aom_codec_error(&decoder)); goto fail; } - if (aom_codec_control(&decoder, AV1D_SET_OPERATING_POINT, operating_point)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AV1D_SET_OPERATING_POINT, + operating_point)) { fprintf(stderr, "Failed to set operating_point: %s\n", aom_codec_error(&decoder)); goto fail; } - if (aom_codec_control(&decoder, AV1D_SET_OUTPUT_ALL_LAYERS, - output_all_layers)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AV1D_SET_OUTPUT_ALL_LAYERS, + output_all_layers)) { fprintf(stderr, "Failed to set output_all_layers: %s\n", aom_codec_error(&decoder)); goto fail; } - if (aom_codec_control(&decoder, AV1D_SET_SKIP_FILM_GRAIN, skip_film_grain)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AV1D_SET_SKIP_FILM_GRAIN, + skip_film_grain)) { fprintf(stderr, "Failed to set skip_film_grain: %s\n", aom_codec_error(&decoder)); goto fail; @@ -759,7 +756,8 @@ static int main_loop(int argc, const char **argv_) { if (framestats_file) { int qp; - if (aom_codec_control(&decoder, AOMD_GET_LAST_QUANTIZER, &qp)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AOMD_GET_LAST_QUANTIZER, + &qp)) { warn("Failed AOMD_GET_LAST_QUANTIZER: %s", aom_codec_error(&decoder)); if (!keep_going) goto fail; @@ -793,7 +791,8 @@ static int main_loop(int argc, const char **argv_) { ++frame_out; got_data = 1; - if (aom_codec_control(&decoder, AOMD_GET_FRAME_CORRUPTED, &corrupted)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AOMD_GET_FRAME_CORRUPTED, + &corrupted)) { warn("Failed AOM_GET_FRAME_CORRUPTED: %s", aom_codec_error(&decoder)); if (!keep_going) goto fail; } @@ -817,8 +816,8 @@ static int main_loop(int argc, const char **argv_) { int render_height = aom_input_ctx.height; if (!render_width || !render_height) { int render_size[2]; - if (aom_codec_control(&decoder, AV1D_GET_DISPLAY_SIZE, - render_size)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AV1D_GET_DISPLAY_SIZE, + render_size)) { // As last resort use size of first frame as display size. render_width = img->d_w; render_height = img->d_h; diff --git a/media/libaom/src/apps/aomenc.c b/media/libaom/src/apps/aomenc.c index 4e23aebe80..bb57726b4d 100644 --- a/media/libaom/src/apps/aomenc.c +++ b/media/libaom/src/apps/aomenc.c @@ -158,6 +158,7 @@ static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, "Show encoder parameters"); static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, "Show PSNR in status line"); +static const arg_def_t use_cfg = ARG_DEF("c", "cfg", 1, "Config file to use"); static const struct arg_enum_list test_decode_enum[] = { { "off", TEST_DECODE_OFF }, @@ -200,6 +201,7 @@ static const arg_def_t input_chroma_subsampling_y = ARG_DEF( NULL, "input-chroma-subsampling-y", 1, "chroma subsampling y value."); static const arg_def_t *main_args[] = { &help, + &use_cfg, &debugmode, &outputfile, &codecarg, @@ -232,9 +234,9 @@ static const arg_def_t profile = static const arg_def_t width = ARG_DEF("w", "width", 1, "Frame width"); static const arg_def_t height = ARG_DEF("h", "height", 1, "Frame height"); static const arg_def_t forced_max_frame_width = ARG_DEF( - NULL, "forced_max_frame_width", 0, "Maximum frame width value to force"); + NULL, "forced_max_frame_width", 1, "Maximum frame width value to force"); static const arg_def_t forced_max_frame_height = ARG_DEF( - NULL, "forced_max_frame_height", 0, "Maximum frame height value to force"); + NULL, "forced_max_frame_height", 1, "Maximum frame height value to force"); #if CONFIG_WEBM_IO static const struct arg_enum_list stereo_mode_enum[] = { { "mono", STEREO_FORMAT_MONO }, @@ -388,10 +390,9 @@ static const arg_def_t arnr_strength = static const struct arg_enum_list tuning_enum[] = { { "psnr", AOM_TUNE_PSNR }, { "ssim", AOM_TUNE_SSIM }, -#if CONFIG_DIST_8X8 - { "cdef-dist", AOM_TUNE_CDEF_DIST }, - { "daala-dist", AOM_TUNE_DAALA_DIST }, -#endif + { "vmaf_with_preprocessing", AOM_TUNE_VMAF_WITH_PREPROCESSING }, + { "vmaf_without_preprocessing", AOM_TUNE_VMAF_WITHOUT_PREPROCESSING }, + { "vmaf", AOM_TUNE_VMAF_MAX_GAIN }, { NULL, 0 } }; static const arg_def_t tune_metric = @@ -403,7 +404,8 @@ static const arg_def_t max_intra_rate_pct = #if CONFIG_AV1_ENCODER static const arg_def_t cpu_used_av1 = - ARG_DEF(NULL, "cpu-used", 1, "CPU Used (0..5)"); + ARG_DEF(NULL, "cpu-used", 1, + "Speed setting (0..6 in good mode, 6..8 in realtime mode)"); static const arg_def_t rowmtarg = ARG_DEF(NULL, "row-mt", 1, "Enable row based multi-threading (0: off, 1: on (default))"); @@ -414,7 +416,8 @@ static const arg_def_t tile_rows = static const arg_def_t enable_tpl_model = ARG_DEF(NULL, "enable-tpl-model", 1, "RDO based on frame temporal dependency " - "(0: off, 1: backward source based, 2: forward 2-pass"); + "(0: off, 1: backward source based). " + "This is required for deltaq mode."); static const arg_def_t enable_keyframe_filtering = ARG_DEF(NULL, "enable-keyframe-filtering", 1, "Apply temporal filtering on key frame " @@ -447,7 +450,7 @@ static const arg_def_t enable_1to4_partitions = 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)." + "(4:4x4, 8:8x8, 16:16x16, 32:32x32, 64:64x64, 128:128x128). " "On frame with 4k+ resolutions or higher speed settings, the min " "partition size will have a minimum of 8."); static const arg_def_t max_partition_size = @@ -473,10 +476,6 @@ 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", 1, - "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)) " @@ -591,11 +590,6 @@ static const arg_def_t mv_cost_upd_freq = ARG_DEF(NULL, "mv-cost-upd-freq", 1, "Update freq for mv costs" "0: SB, 1: SB Row per Tile, 2: Tile, 3: Off"); -#if CONFIG_DIST_8X8 -static const arg_def_t enable_dist_8x8 = - ARG_DEF(NULL, "enable-dist-8x8", 1, - "Enable dist-8x8 (0: false (default), 1: true)"); -#endif // CONFIG_DIST_8X8 static const arg_def_t num_tg = ARG_DEF( NULL, "num-tile-groups", 1, "Maximum number of tile groups, default is 1"); static const arg_def_t mtu_size = @@ -613,6 +607,10 @@ static const arg_def_t timing_info = "Signal timing info in the bitstream (model unly works for no " "hidden frames, no super-res yet):", timing_info_enum); +#if CONFIG_TUNE_VMAF +static const arg_def_t vmaf_model_path = + ARG_DEF(NULL, "vmaf-model-path", 1, "Path to the VMAF model file"); +#endif static const arg_def_t film_grain_test = ARG_DEF(NULL, "film-grain-test", 1, "Film grain test vectors (0: none (default), 1: test-1 2: test-2, " @@ -644,8 +642,9 @@ static const arg_def_t aq_mode = ARG_DEF( "3: cyclic refresh)"); static const arg_def_t deltaq_mode = ARG_DEF(NULL, "deltaq-mode", 1, - "Delta qindex mode (0: off, 1: deltaq pred efficiency (default), " - "2: deltaq perceptual)"); + "Delta qindex mode (0: off, 1: deltaq objective (default), " + "2: deltaq perceptual). " + "Currently this requires enable-tpl-model as a prerequisite."); static const arg_def_t deltalf_mode = ARG_DEF( NULL, "delta-lf-mode", 1, "Enable delta-lf-mode (0: off (default), 1: on)"); static const arg_def_t frame_periodic_boost = @@ -661,9 +660,12 @@ static const arg_def_t min_gf_interval = ARG_DEF( static const arg_def_t max_gf_interval = ARG_DEF( NULL, "max-gf-interval", 1, "max gf/arf frame interval (default 0, indicating in-built behavior)"); +static const arg_def_t gf_min_pyr_height = + ARG_DEF(NULL, "gf-min-pyr-height", 1, + "Min height for GF group pyramid structure (0 (default) to 5)"); static const arg_def_t gf_max_pyr_height = ARG_DEF(NULL, "gf-max-pyr-height", 1, - "maximum height for GF group pyramid structure (0 to 4 (default))"); + "maximum height for GF group pyramid structure (0 to 5 (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))"); @@ -796,6 +798,22 @@ static const arg_def_t set_tier_mask = "operating points conforms to. " "Bit value 0(defualt): Main Tier; 1: High Tier."); +static const arg_def_t use_fixed_qp_offsets = + ARG_DEF(NULL, "use-fixed-qp-offsets", 1, + "Enable fixed QP offsets for frames at different levels of the " + "pyramid. Selected automatically from --cq-level if " + "--fixed-qp-offsets is not provided. If this option is not " + "specified (default), offsets are adaptively chosen by the " + "encoder."); + +static const arg_def_t fixed_qp_offsets = + ARG_DEF(NULL, "fixed-qp-offsets", 1, + "Set fixed QP offsets for frames at different levels of the " + "pyramid. Comma-separated list of 5 offsets for keyframe, ALTREF, " + "and 3 levels of internal alt-refs. If this option is not " + "specified (default), offsets are adaptively chosen by the " + "encoder."); + static const arg_def_t *av1_args[] = { &cpu_used_av1, &auto_altref, &sharpness, @@ -825,7 +843,6 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &enable_intra_edge_filter, &enable_order_hint, &enable_tx64, - &tx_size_search_method, &enable_flip_idtx, &enable_dist_wtd_comp, &enable_masked_comp, @@ -859,9 +876,6 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &coeff_cost_upd_freq, &mode_cost_upd_freq, &mv_cost_upd_freq, -#if CONFIG_DIST_8X8 - &enable_dist_8x8, -#endif &frame_parallel_decoding, &error_resilient_mode, &aq_mode, @@ -877,6 +891,7 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &input_chroma_sample_position, &min_gf_interval, &max_gf_interval, + &gf_min_pyr_height, &gf_max_pyr_height, &superblock_size, &num_tg, @@ -901,6 +916,9 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1, &sframe_dist, &sframe_mode, &save_as_annexb, +#if CONFIG_TUNE_VMAF + &vmaf_model_path, +#endif NULL }; static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AOME_SET_ENABLEAUTOALTREF, @@ -931,7 +949,6 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, 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, @@ -965,9 +982,6 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_COEFF_COST_UPD_FREQ, AV1E_SET_MODE_COST_UPD_FREQ, AV1E_SET_MV_COST_UPD_FREQ, -#if CONFIG_DIST_8X8 - AV1E_SET_ENABLE_DIST_8X8, -#endif AV1E_SET_FRAME_PARALLEL_DECODING, AV1E_SET_ERROR_RESILIENT_MODE, AV1E_SET_AQ_MODE, @@ -983,6 +997,7 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_CHROMA_SAMPLE_POSITION, AV1E_SET_MIN_GF_INTERVAL, AV1E_SET_MAX_GF_INTERVAL, + AV1E_SET_GF_MIN_PYRAMID_HEIGHT, AV1E_SET_GF_MAX_PYRAMID_HEIGHT, AV1E_SET_SUPERBLOCK_SIZE, AV1E_SET_NUM_TG, @@ -1000,6 +1015,9 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED, AV1E_SET_TARGET_SEQ_LEVEL_IDX, AV1E_SET_TIER_MASK, AV1E_SET_MIN_CR, +#if CONFIG_TUNE_VMAF + AV1E_SET_VMAF_MODEL_PATH, +#endif 0 }; #endif // CONFIG_AV1_ENCODER @@ -1074,6 +1092,9 @@ struct stream_config { int write_ivf; // whether to use 16bit internal buffers int use_16bit_internal; +#if CONFIG_TUNE_VMAF + const char *vmaf_model_path; +#endif }; struct stream_state { @@ -1112,6 +1133,14 @@ static void validate_positive_rational(const char *msg, if (!rat->den) die("Error: %s has zero denominator\n", msg); } +static void init_config(cfg_options_t *config) { + memset(config, 0, sizeof(cfg_options_t)); + config->super_block_size = 0; // Dynamic + config->max_partition_size = 128; + config->min_partition_size = 4; + config->disable_trellis_quant = 3; +} + /* Parses global config arguments into the AvxEncoderConfig. Note that * argv is modified and overwrites all parsed arguments. */ @@ -1129,8 +1158,18 @@ static void parse_global_config(struct AvxEncoderConfig *global, char ***argv) { global->color_type = I420; global->csp = AOM_CSP_UNKNOWN; + int cfg_included = 0; + init_config(&global->encoder_config); + for (argi = argj = argv_local; (*argj = *argi); argi += arg.argv_step) { arg.argv_step = 1; + + if (arg_match(&arg, &use_cfg, argi)) { + if (cfg_included) continue; + parse_cfg(arg.val, &global->encoder_config); + cfg_included = 1; + continue; + } if (arg_match(&arg, &help, argi)) { show_help(stdout, 0); exit(EXIT_SUCCESS); @@ -1322,6 +1361,8 @@ static struct stream_state *new_stream(struct AvxEncoderConfig *global, /* Allows removal of the application version from the EBML tags */ stream->webm_ctx.debug = global->debug; + memcpy(&stream->config.cfg.encoder_cfg, &global->encoder_config, + sizeof(stream->config.cfg.encoder_cfg)); } /* Output files must be specified for each stream */ @@ -1546,6 +1587,21 @@ static int parse_stream_params(struct AvxEncoderConfig *global, } else if (arg_match(&arg, &tile_height, argi)) { config->cfg.tile_height_count = arg_parse_list(&arg, config->cfg.tile_heights, MAX_TILE_HEIGHTS); +#if CONFIG_TUNE_VMAF + } else if (arg_match(&arg, &vmaf_model_path, argi)) { + config->vmaf_model_path = arg.val; +#endif + } else if (arg_match(&arg, &use_fixed_qp_offsets, argi)) { + config->cfg.use_fixed_qp_offsets = arg_parse_uint(&arg); + } else if (arg_match(&arg, &fixed_qp_offsets, argi)) { + const int fixed_qp_offset_count = arg_parse_list( + &arg, config->cfg.fixed_qp_offsets, FIXED_QP_OFFSET_COUNT); + if (fixed_qp_offset_count < FIXED_QP_OFFSET_COUNT) { + die("Option --fixed_qp_offsets requires %d comma-separated values, but " + "only %d values were provided.\n", + FIXED_QP_OFFSET_COUNT, fixed_qp_offset_count); + } + config->cfg.use_fixed_qp_offsets = 1; } else if (global->usage == AOM_USAGE_REALTIME && arg_match(&arg, &enable_restoration, argi)) { if (arg_parse_uint(&arg) == 1) { @@ -1709,6 +1765,44 @@ static void show_stream_config(struct stream_state *stream, SHOW(kf_mode); SHOW(kf_min_dist); SHOW(kf_max_dist); + +#define SHOW_PARAMS(field) \ + fprintf(stderr, " %-28s = %d\n", #field, \ + stream->config.cfg.encoder_cfg.field) + SHOW_PARAMS(super_block_size); + SHOW_PARAMS(max_partition_size); + SHOW_PARAMS(min_partition_size); + SHOW_PARAMS(disable_ab_partition_type); + SHOW_PARAMS(disable_rect_partition_type); + SHOW_PARAMS(disable_1to4_partition_type); + SHOW_PARAMS(disable_flip_idtx); + SHOW_PARAMS(disable_cdef); + SHOW_PARAMS(disable_lr); + SHOW_PARAMS(disable_obmc); + SHOW_PARAMS(disable_warp_motion); + SHOW_PARAMS(disable_global_motion); + SHOW_PARAMS(disable_dist_wtd_comp); + SHOW_PARAMS(disable_diff_wtd_comp); + SHOW_PARAMS(disable_inter_intra_comp); + SHOW_PARAMS(disable_masked_comp); + SHOW_PARAMS(disable_one_sided_comp); + SHOW_PARAMS(disable_palette); + SHOW_PARAMS(disable_intrabc); + SHOW_PARAMS(disable_cfl); + SHOW_PARAMS(disable_smooth_intra); + SHOW_PARAMS(disable_filter_intra); + SHOW_PARAMS(disable_dual_filter); + SHOW_PARAMS(disable_intra_angle_delta); + SHOW_PARAMS(disable_intra_edge_filter); + SHOW_PARAMS(disable_tx_64x64); + SHOW_PARAMS(disable_smooth_inter_intra); + SHOW_PARAMS(disable_inter_inter_wedge); + SHOW_PARAMS(disable_inter_intra_wedge); + SHOW_PARAMS(disable_paeth_intra); + SHOW_PARAMS(disable_trellis_quant); + SHOW_PARAMS(disable_ref_frame_mv); + SHOW_PARAMS(reduced_reference_set); + SHOW_PARAMS(reduced_tx_type_set); } static void open_output_file(struct stream_state *stream, @@ -1802,21 +1896,25 @@ static void initialize_encoder(struct stream_state *stream, &stream->config.cfg, flags); ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); - /* Note that we bypass the aom_codec_control wrapper macro because - * we're being clever to store the control IDs in an array. Real - * applications will want to make use of the enumerations directly - */ for (i = 0; i < stream->config.arg_ctrl_cnt; i++) { int ctrl = stream->config.arg_ctrls[i][0]; int value = stream->config.arg_ctrls[i][1]; - if (aom_codec_control_(&stream->encoder, ctrl, value)) + if (aom_codec_control(&stream->encoder, ctrl, value)) fprintf(stderr, "Error: Tried to set control %d = %d\n", ctrl, value); ctx_exit_on_error(&stream->encoder, "Failed to control codec"); } + +#if CONFIG_TUNE_VMAF + if (stream->config.vmaf_model_path) { + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_VMAF_MODEL_PATH, + stream->config.vmaf_model_path); + } +#endif + if (stream->config.film_grain_filename) { - aom_codec_control_(&stream->encoder, AV1E_SET_FILM_GRAIN_TABLE, - stream->config.film_grain_filename); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_FILM_GRAIN_TABLE, + stream->config.film_grain_filename); } #if CONFIG_AV1_DECODER @@ -1826,18 +1924,20 @@ static void initialize_encoder(struct stream_state *stream, aom_codec_dec_init(&stream->decoder, decoder->codec_interface(), &cfg, 0); if (strcmp(global->codec->name, "av1") == 0) { - aom_codec_control(&stream->decoder, AV1_SET_TILE_MODE, - stream->config.cfg.large_scale_tile); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_TILE_MODE, + stream->config.cfg.large_scale_tile); ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_mode"); - aom_codec_control(&stream->decoder, AV1D_SET_IS_ANNEXB, - stream->config.cfg.save_as_annexb); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1D_SET_IS_ANNEXB, + stream->config.cfg.save_as_annexb); ctx_exit_on_error(&stream->decoder, "Failed to set is_annexb"); - aom_codec_control(&stream->decoder, AV1_SET_DECODE_TILE_ROW, -1); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_DECODE_TILE_ROW, + -1); ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_row"); - aom_codec_control(&stream->decoder, AV1_SET_DECODE_TILE_COL, -1); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_DECODE_TILE_COL, + -1); ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_col"); } } @@ -1936,7 +2036,8 @@ static void update_quantizer_histogram(struct stream_state *stream) { if (stream->config.cfg.g_pass != AOM_RC_FIRST_PASS) { int q; - aom_codec_control(&stream->encoder, AOME_GET_LAST_QUANTIZER_64, &q); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AOME_GET_LAST_QUANTIZER_64, + &q); ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); stream->counts[q]++; } @@ -2063,8 +2164,10 @@ static void test_decode(struct stream_state *stream, if (stream->mismatch_seen) return; /* Get the internal reference frame */ - aom_codec_control(&stream->encoder, AV1_GET_NEW_FRAME_IMAGE, &enc_img); - aom_codec_control(&stream->decoder, AV1_GET_NEW_FRAME_IMAGE, &dec_img); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1_GET_NEW_FRAME_IMAGE, + &enc_img); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_GET_NEW_FRAME_IMAGE, + &dec_img); if ((enc_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) != (dec_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH)) { @@ -2162,7 +2265,7 @@ int main(int argc, const char **argv_) { argv = argv_dup(argc - 1, argv_ + 1); parse_global_config(&global, &argv); - if (argc < 3) usage_exit(); + if (argc < 2) usage_exit(); switch (global.color_type) { case I420: input.fmt = AOM_IMG_FMT_I420; break; @@ -2301,16 +2404,20 @@ int main(int argc, const char **argv_) { input.file_type == FILE_TYPE_Y4M) { // Note that here the input file values for chroma subsampling // are used instead of those from the command line. - aom_codec_control(&stream->encoder, AV1E_SET_CHROMA_SUBSAMPLING_X, - input.y4m.dst_c_dec_h >> 1); - aom_codec_control(&stream->encoder, AV1E_SET_CHROMA_SUBSAMPLING_Y, - input.y4m.dst_c_dec_v >> 1); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, + AV1E_SET_CHROMA_SUBSAMPLING_X, + input.y4m.dst_c_dec_h >> 1); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, + AV1E_SET_CHROMA_SUBSAMPLING_Y, + input.y4m.dst_c_dec_v >> 1); } else if (input.bit_depth == 12 && input.file_type == FILE_TYPE_RAW) { - aom_codec_control(&stream->encoder, AV1E_SET_CHROMA_SUBSAMPLING_X, - stream->chroma_subsampling_x); - aom_codec_control(&stream->encoder, AV1E_SET_CHROMA_SUBSAMPLING_Y, - stream->chroma_subsampling_y); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, + AV1E_SET_CHROMA_SUBSAMPLING_X, + stream->chroma_subsampling_x); + AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, + AV1E_SET_CHROMA_SUBSAMPLING_Y, + stream->chroma_subsampling_y); } break; default: break; diff --git a/media/libaom/src/apps/aomenc.h b/media/libaom/src/apps/aomenc.h index 5e59c1ac5d..a38258b872 100644 --- a/media/libaom/src/apps/aomenc.h +++ b/media/libaom/src/apps/aomenc.h @@ -11,6 +11,7 @@ #ifndef AOM_APPS_AOMENC_H_ #define AOM_APPS_AOMENC_H_ +#include "aom/aom_codec.h" #include "aom/aom_encoder.h" #ifdef __cplusplus @@ -37,7 +38,7 @@ struct AvxEncoderConfig { const struct AvxInterface *codec; int passes; int pass; - int usage; + unsigned int usage; ColorInputType color_type; int quiet; int verbose; @@ -54,6 +55,7 @@ struct AvxEncoderConfig { int disable_warning_prompt; int experimental_bitstream; aom_chroma_sample_position_t csp; + cfg_options_t encoder_config; }; #ifdef __cplusplus diff --git a/media/libaom/src/av1/av1.cmake b/media/libaom/src/av1/av1.cmake index 16d1e346ef..2ab3496303 100644 --- a/media/libaom/src/av1/av1.cmake +++ b/media/libaom/src/av1/av1.cmake @@ -17,6 +17,7 @@ list(APPEND AOM_AV1_COMMON_SOURCES "${AOM_ROOT}/av1/av1_iface_common.h" "${AOM_ROOT}/av1/common/alloccommon.c" "${AOM_ROOT}/av1/common/alloccommon.h" + "${AOM_ROOT}/av1/common/av1_common_int.h" "${AOM_ROOT}/av1/common/av1_inv_txfm1d.c" "${AOM_ROOT}/av1/common/av1_inv_txfm1d.h" "${AOM_ROOT}/av1/common/av1_inv_txfm1d_cfg.h" @@ -57,7 +58,6 @@ list(APPEND AOM_AV1_COMMON_SOURCES "${AOM_ROOT}/av1/common/obu_util.h" "${AOM_ROOT}/av1/common/odintrin.c" "${AOM_ROOT}/av1/common/odintrin.h" - "${AOM_ROOT}/av1/common/onyxc_int.h" "${AOM_ROOT}/av1/common/pred_common.c" "${AOM_ROOT}/av1/common/pred_common.h" "${AOM_ROOT}/av1/common/quant_common.c" @@ -130,6 +130,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/block.h" "${AOM_ROOT}/av1/encoder/cnn.c" "${AOM_ROOT}/av1/encoder/cnn.h" + "${AOM_ROOT}/av1/encoder/compound_type.c" + "${AOM_ROOT}/av1/encoder/compound_type.h" "${AOM_ROOT}/av1/encoder/context_tree.c" "${AOM_ROOT}/av1/encoder/context_tree.h" "${AOM_ROOT}/av1/encoder/corner_detect.c" @@ -167,16 +169,21 @@ 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/interp_search.c" + "${AOM_ROOT}/av1/encoder/interp_search.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" - "${AOM_ROOT}/av1/encoder/mbgraph.h" "${AOM_ROOT}/av1/encoder/mcomp.c" "${AOM_ROOT}/av1/encoder/mcomp.h" "${AOM_ROOT}/av1/encoder/ml.c" "${AOM_ROOT}/av1/encoder/ml.h" + "${AOM_ROOT}/av1/encoder/model_rd.h" + "${AOM_ROOT}/av1/encoder/motion_search_facade.c" + "${AOM_ROOT}/av1/encoder/motion_search_facade.h" + "${AOM_ROOT}/av1/encoder/mv_prec.c" + "${AOM_ROOT}/av1/encoder/mv_prec.h" "${AOM_ROOT}/av1/encoder/palette.c" "${AOM_ROOT}/av1/encoder/palette.h" "${AOM_ROOT}/av1/encoder/partition_strategy.h" @@ -197,6 +204,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/rdopt.c" "${AOM_ROOT}/av1/encoder/nonrd_pickmode.c" "${AOM_ROOT}/av1/encoder/rdopt.h" + "${AOM_ROOT}/av1/encoder/rdopt_data_defs.h" + "${AOM_ROOT}/av1/encoder/rdopt_utils.h" "${AOM_ROOT}/av1/encoder/reconinter_enc.c" "${AOM_ROOT}/av1/encoder/reconinter_enc.h" "${AOM_ROOT}/av1/encoder/segmentation.c" @@ -211,6 +220,10 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/tokenize.h" "${AOM_ROOT}/av1/encoder/tpl_model.c" "${AOM_ROOT}/av1/encoder/tpl_model.h" + "${AOM_ROOT}/av1/encoder/tx_search.c" + "${AOM_ROOT}/av1/encoder/tx_search.h" + "${AOM_ROOT}/av1/encoder/intra_mode_search.c" + "${AOM_ROOT}/av1/encoder/intra_mode_search.h" "${AOM_ROOT}/av1/encoder/wedge_utils.c" "${AOM_ROOT}/av1/encoder/var_based_part.c" "${AOM_ROOT}/av1/encoder/var_based_part.h" @@ -223,6 +236,11 @@ list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/dwt.c" "${AOM_ROOT}/av1/encoder/dwt.h") +if(CONFIG_TUNE_VMAF) + list(APPEND AOM_AV1_ENCODER_SOURCES "${AOM_ROOT}/av1/encoder/tune_vmaf.c" + "${AOM_ROOT}/av1/encoder/tune_vmaf.h") +endif() + list(APPEND AOM_AV1_COMMON_INTRIN_SSE2 "${AOM_ROOT}/av1/common/cdef_block_sse2.c" "${AOM_ROOT}/av1/common/x86/cfl_sse2.c" @@ -307,6 +325,7 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_SSE2 "${AOM_ROOT}/av1/encoder/x86/av1_quantize_sse2.c" "${AOM_ROOT}/av1/encoder/x86/encodetxb_sse2.c" "${AOM_ROOT}/av1/encoder/x86/highbd_block_error_intrin_sse2.c" + "${AOM_ROOT}/av1/encoder/x86/temporal_filter_sse2.c" "${AOM_ROOT}/av1/encoder/x86/wedge_utils_sse2.c") if(NOT CONFIG_AV1_HIGHBITDEPTH) @@ -330,7 +349,6 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_SSE4_1 "${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 @@ -345,6 +363,7 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2 "${AOM_ROOT}/av1/encoder/x86/wedge_utils_avx2.c" "${AOM_ROOT}/av1/encoder/x86/encodetxb_avx2.c" "${AOM_ROOT}/av1/encoder/x86/rdopt_avx2.c" + "${AOM_ROOT}/av1/encoder/x86/temporal_filter_avx2.c" "${AOM_ROOT}/av1/encoder/x86/pickrst_avx2.c") if(NOT CONFIG_AV1_HIGHBITDEPTH) @@ -407,8 +426,7 @@ if(CONFIG_REALTIME_ONLY) "${AOM_ROOT}/av1/encoder/firstpass.h" "${AOM_ROOT}/av1/encoder/gop_structure.c" "${AOM_ROOT}/av1/encoder/gop_structure.h" - "${AOM_ROOT}/av1/encoder/mbgraph.c" - "${AOM_ROOT}/av1/encoder/mbgraph.h" + "${AOM_ROOT}/av1/encoder/misc_model_weights.h" "${AOM_ROOT}/av1/encoder/partition_cnn_weights.h" "${AOM_ROOT}/av1/encoder/partition_model_weights.h" "${AOM_ROOT}/av1/encoder/pass2_strategy.c" @@ -417,8 +435,7 @@ if(CONFIG_REALTIME_ONLY) "${AOM_ROOT}/av1/encoder/temporal_filter_constants.h" "${AOM_ROOT}/av1/encoder/tpl_model.c" "${AOM_ROOT}/av1/encoder/tpl_model.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/temporal_filter_sse4.c") endif() # Setup AV1 common/decoder/encoder targets. The libaom target must exist before @@ -427,38 +444,47 @@ function(setup_av1_targets) add_library(aom_av1_common OBJECT ${AOM_AV1_COMMON_SOURCES}) list(APPEND AOM_LIB_TARGETS aom_av1_common) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() if(CONFIG_AV1_DECODER) add_library(aom_av1_decoder OBJECT ${AOM_AV1_DECODER_SOURCES}) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_av1_decoder) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endif() if(CONFIG_AV1_ENCODER) add_library(aom_av1_encoder OBJECT ${AOM_AV1_ENCODER_SOURCES}) set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_av1_encoder) target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() endif() if(HAVE_SSE2) require_compiler_flag_nomsvc("-msse2" NO) add_intrinsics_object_library("-msse2" "sse2" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_SSE2" "aom") + "AOM_AV1_COMMON_INTRIN_SSE2") if(CONFIG_AV1_DECODER) if(AOM_AV1_DECODER_ASM_SSE2) - add_asm_library("aom_av1_decoder_sse2" "AOM_AV1_DECODER_ASM_SSE2" "aom") + add_asm_library("aom_av1_decoder_sse2" "AOM_AV1_DECODER_ASM_SSE2") endif() if(AOM_AV1_DECODER_INTRIN_SSE2) add_intrinsics_object_library("-msse2" "sse2" "aom_av1_decoder" - "AOM_AV1_DECODER_INTRIN_SSE2" "aom") + "AOM_AV1_DECODER_INTRIN_SSE2") endif() endif() if(CONFIG_AV1_ENCODER) - add_asm_library("aom_av1_encoder_sse2" "AOM_AV1_ENCODER_ASM_SSE2" "aom") + add_asm_library("aom_av1_encoder_sse2" "AOM_AV1_ENCODER_ASM_SSE2") add_intrinsics_object_library("-msse2" "sse2" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_SSE2" "aom") + "AOM_AV1_ENCODER_INTRIN_SSE2") endif() endif() @@ -466,19 +492,19 @@ function(setup_av1_targets) require_compiler_flag_nomsvc("-msse3" NO) if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("-msse3" "sse3" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_SSE3" "aom") + "AOM_AV1_ENCODER_INTRIN_SSE3") endif() endif() if(HAVE_SSSE3) require_compiler_flag_nomsvc("-mssse3" NO) add_intrinsics_object_library("-mssse3" "ssse3" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_SSSE3" "aom") + "AOM_AV1_COMMON_INTRIN_SSSE3") if(CONFIG_AV1_DECODER) if(AOM_AV1_DECODER_INTRIN_SSSE3) add_intrinsics_object_library("-mssse3" "ssse3" "aom_av1_decoder" - "AOM_AV1_DECODER_INTRIN_SSSE3" "aom") + "AOM_AV1_DECODER_INTRIN_SSSE3") endif() endif() endif() @@ -486,17 +512,17 @@ function(setup_av1_targets) if(HAVE_SSE4_1) require_compiler_flag_nomsvc("-msse4.1" NO) add_intrinsics_object_library("-msse4.1" "sse4" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_SSE4_1" "aom") + "AOM_AV1_COMMON_INTRIN_SSE4_1") if(CONFIG_AV1_ENCODER) if("${AOM_TARGET_CPU}" STREQUAL "x86_64") add_asm_library("aom_av1_encoder_ssse3" - "AOM_AV1_ENCODER_ASM_SSSE3_X86_64" "aom") + "AOM_AV1_ENCODER_ASM_SSSE3_X86_64") endif() if(AOM_AV1_ENCODER_INTRIN_SSE4_1) add_intrinsics_object_library("-msse4.1" "sse4" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_SSE4_1" "aom") + "AOM_AV1_ENCODER_INTRIN_SSE4_1") endif() endif() endif() @@ -506,7 +532,7 @@ function(setup_av1_targets) if(CONFIG_AV1_ENCODER) if(AOM_AV1_ENCODER_INTRIN_SSE4_2) add_intrinsics_object_library("-msse4.2" "sse42" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_SSE4_2" "aom") + "AOM_AV1_ENCODER_INTRIN_SSE4_2") endif() endif() endif() @@ -514,11 +540,11 @@ function(setup_av1_targets) if(HAVE_AVX2) require_compiler_flag_nomsvc("-mavx2" NO) add_intrinsics_object_library("-mavx2" "avx2" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_AVX2" "aom") + "AOM_AV1_COMMON_INTRIN_AVX2") if(CONFIG_AV1_ENCODER) add_intrinsics_object_library("-mavx2" "avx2" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_AVX2" "aom") + "AOM_AV1_ENCODER_INTRIN_AVX2") endif() endif() @@ -526,26 +552,26 @@ function(setup_av1_targets) if(AOM_AV1_COMMON_INTRIN_NEON) add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_NEON" "aom") + "AOM_AV1_COMMON_INTRIN_NEON") endif() if(AOM_AV1_ENCODER_INTRIN_NEON) add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_NEON" "aom") + "AOM_AV1_ENCODER_INTRIN_NEON") endif() endif() if(HAVE_VSX) if(AOM_AV1_COMMON_INTRIN_VSX) add_intrinsics_object_library("-mvsx -maltivec" "vsx" "aom_av1_common" - "AOM_AV1_COMMON_INTRIN_VSX" "aom") + "AOM_AV1_COMMON_INTRIN_VSX") endif() endif() if(HAVE_MSA) add_intrinsics_object_library("" "msa" "aom_av1_encoder" - "AOM_AV1_ENCODER_INTRIN_MSA" "aom") + "AOM_AV1_ENCODER_INTRIN_MSA") endif() # Pass the new lib targets up to the parent scope instance of diff --git a/media/libaom/src/av1/av1_cx_iface.c b/media/libaom/src/av1/av1_cx_iface.c index db4cb36557..676eaa0adb 100644 --- a/media/libaom/src/av1/av1_cx_iface.c +++ b/media/libaom/src/av1/av1_cx_iface.c @@ -27,7 +27,6 @@ #include "av1/encoder/firstpass.h" #define MAG_SIZE (4) -#define MAX_NUM_ENHANCEMENT_LAYERS 3 struct av1_extracfg { int cpu_used; @@ -45,8 +44,10 @@ struct av1_extracfg { unsigned int arnr_strength; unsigned int min_gf_interval; unsigned int max_gf_interval; + unsigned int gf_min_pyr_height; unsigned int gf_max_pyr_height; aom_tune_metric tuning; + const char *vmaf_model_path; unsigned int cq_level; // constrained quality level unsigned int rc_max_intra_bitrate_pct; unsigned int rc_max_inter_bitrate_pct; @@ -63,9 +64,6 @@ struct av1_extracfg { unsigned int qm_v; unsigned int qm_min; unsigned int qm_max; -#if CONFIG_DIST_8X8 - unsigned int enable_dist_8x8; -#endif unsigned int num_tg; unsigned int mtu_size; @@ -103,7 +101,6 @@ struct av1_extracfg { 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 @@ -150,47 +147,48 @@ struct av1_extracfg { COST_UPDATE_TYPE coeff_cost_upd_freq; COST_UPDATE_TYPE mode_cost_upd_freq; COST_UPDATE_TYPE mv_cost_upd_freq; + unsigned int ext_tile_debug; + unsigned int sb_multipass_unit_test; }; static struct av1_extracfg default_extra_cfg = { - 0, // cpu_used - 1, // enable_auto_alt_ref - 0, // enable_auto_bwd_ref - 0, // noise_sensitivity - CONFIG_SHARP_SETTINGS, // sharpness - 0, // static_thresh - 1, // row_mt - 0, // tile_columns - 0, // tile_rows - 1, // enable_tpl_model - 1, // enable_keyframe_filtering - 7, // arnr_max_frames - 5, // arnr_strength - 0, // min_gf_interval; 0 -> default decision - 0, // max_gf_interval; 0 -> default decision - 4, // gf_max_pyr_height - AOM_TUNE_PSNR, // tuning - 10, // cq_level - 0, // rc_max_intra_bitrate_pct - 0, // rc_max_inter_bitrate_pct - 0, // gf_cbr_boost_pct - 0, // lossless - !CONFIG_SHARP_SETTINGS, // enable_cdef - 1, // enable_restoration - 1, // force_video_mode - 1, // enable_obmc - 3, // disable_trellis_quant - 0, // enable_qm - DEFAULT_QM_Y, // qm_y - DEFAULT_QM_U, // qm_u - DEFAULT_QM_V, // qm_v - DEFAULT_QM_FIRST, // qm_min - DEFAULT_QM_LAST, // qm_max -#if CONFIG_DIST_8X8 - 0, -#endif - 1, // max number of tile groups - 0, // mtu_size + 0, // cpu_used + 1, // enable_auto_alt_ref + 0, // enable_auto_bwd_ref + 0, // noise_sensitivity + 0, // sharpness + 0, // static_thresh + 1, // row_mt + 0, // tile_columns + 0, // tile_rows + 1, // enable_tpl_model + 1, // enable_keyframe_filtering + 7, // arnr_max_frames + 5, // arnr_strength + 0, // min_gf_interval; 0 -> default decision + 0, // max_gf_interval; 0 -> default decision + 0, // gf_min_pyr_height + 5, // gf_max_pyr_height + AOM_TUNE_PSNR, // tuning + "/usr/local/share/model/vmaf_v0.6.1.pkl", // VMAF model path + 10, // cq_level + 0, // rc_max_intra_bitrate_pct + 0, // rc_max_inter_bitrate_pct + 0, // gf_cbr_boost_pct + 0, // lossless + 1, // enable_cdef + 1, // enable_restoration + 0, // force_video_mode + 1, // enable_obmc + 3, // disable_trellis_quant + 0, // enable_qm + DEFAULT_QM_Y, // qm_y + DEFAULT_QM_U, // qm_u + DEFAULT_QM_V, // qm_v + DEFAULT_QM_FIRST, // qm_min + DEFAULT_QM_LAST, // qm_max + 1, // max number of tile groups + 0, // mtu_size AOM_TIMING_UNSPECIFIED, // No picture timing signaling in bitstream 0, // frame_parallel_decoding_mode 1, // enable dual filter @@ -224,7 +222,6 @@ static struct av1_extracfg default_extra_cfg = { 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 @@ -275,6 +272,8 @@ static struct av1_extracfg default_extra_cfg = { COST_UPD_SB, // coeff_cost_upd_freq COST_UPD_SB, // mode_cost_upd_freq COST_UPD_SB, // mv_cost_upd_freq + 0, // ext_tile_debug + 0, // sb_multipass_unit_test }; struct aom_codec_alg_priv { @@ -294,11 +293,18 @@ struct aom_codec_alg_priv { size_t pending_frame_sizes[8]; aom_image_t preview_img; aom_enc_frame_flags_t next_frame_flags; - aom_postproc_cfg_t preview_ppcfg; aom_codec_pkt_list_decl(256) pkt_list; unsigned int fixed_kf_cntr; // BufferPool that holds all reference frames. BufferPool *buffer_pool; + + // lookahead instance variables + BufferPool *buffer_pool_lap; + AV1_COMP *cpi_lap; + FIRSTPASS_STATS *frame_stats_buffer; + // Number of stats buffers required for look ahead + int num_lap_buffers; + STATS_BUFFER_CTX stats_buf_context; }; static INLINE int gcd(int64_t a, int b) { @@ -369,7 +375,6 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, 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); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 100); @@ -377,13 +382,24 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, RANGE_CHECK(cfg, kf_mode, AOM_KF_DISABLED, AOM_KF_AUTO); RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100); RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_LAST_PASS); + if (cfg->g_pass == AOM_RC_ONE_PASS) { + RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_TOTAL_BUFFERS); + } else { + RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS); + } RANGE_CHECK_HI(extra_cfg, min_gf_interval, MAX_LAG_BUFFERS - 1); RANGE_CHECK_HI(extra_cfg, max_gf_interval, MAX_LAG_BUFFERS - 1); if (extra_cfg->max_gf_interval > 0) { RANGE_CHECK(extra_cfg, max_gf_interval, AOMMAX(2, extra_cfg->min_gf_interval), (MAX_LAG_BUFFERS - 1)); } - RANGE_CHECK_HI(extra_cfg, gf_max_pyr_height, 4); + RANGE_CHECK_HI(extra_cfg, gf_min_pyr_height, 5); + RANGE_CHECK_HI(extra_cfg, gf_max_pyr_height, 5); + if (extra_cfg->gf_min_pyr_height > extra_cfg->gf_max_pyr_height) { + ERROR( + "gf_min_pyr_height must be less than or equal to " + "gf_max_pyramid_height"); + } RANGE_CHECK_HI(cfg, rc_resize_mode, RESIZE_MODES - 1); RANGE_CHECK(cfg, rc_resize_denominator, SCALE_NUMERATOR, @@ -408,6 +424,8 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, "or kf_max_dist instead."); RANGE_CHECK_HI(extra_cfg, motion_vector_unit_test, 2); + RANGE_CHECK_HI(extra_cfg, sb_multipass_unit_test, 1); + RANGE_CHECK_HI(extra_cfg, ext_tile_debug, 1); RANGE_CHECK_HI(extra_cfg, enable_auto_alt_ref, 1); RANGE_CHECK_HI(extra_cfg, enable_auto_bwd_ref, 2); RANGE_CHECK(extra_cfg, cpu_used, 0, 8); @@ -467,6 +485,22 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, ERROR("Source bit-depth 12 not supported in profile < 2"); } + if (cfg->rc_end_usage == AOM_Q) { + RANGE_CHECK_HI(cfg, use_fixed_qp_offsets, 1); + for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { + RANGE_CHECK_HI(cfg, fixed_qp_offsets[i], 63); + } + } else { + if (cfg->use_fixed_qp_offsets > 0) { + ERROR("--use_fixed_qp_offsets can only be used with --end-usage=q"); + } + for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { + if (cfg->fixed_qp_offsets[i] >= 0) { + ERROR("--fixed_qp_offsets can only be used with --end-usage=q"); + } + } + } + RANGE_CHECK(extra_cfg, color_primaries, AOM_CICP_CP_BT_709, AOM_CICP_CP_EBU_3213); // Need to check range more precisely to // check for reserved values? @@ -476,8 +510,18 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, AOM_CICP_MC_ICTCP); RANGE_CHECK(extra_cfg, color_range, 0, 1); -#if CONFIG_DIST_8X8 - RANGE_CHECK(extra_cfg, tuning, AOM_TUNE_PSNR, AOM_TUNE_DAALA_DIST); +#if !CONFIG_TUNE_VMAF + if (extra_cfg->tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + extra_cfg->tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + extra_cfg->tuning == AOM_TUNE_VMAF_MAX_GAIN) { + ERROR( + "This error may be related to the wrong configuration options: try to " + "set -DCONFIG_TUNE_VMAF=1 at the time CMake is run."); + } +#endif + +#if CONFIG_TUNE_VMAF + RANGE_CHECK(extra_cfg, tuning, AOM_TUNE_PSNR, AOM_TUNE_VMAF_MAX_GAIN); #else RANGE_CHECK(extra_cfg, tuning, AOM_TUNE_PSNR, AOM_TUNE_SSIM); #endif @@ -492,10 +536,6 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, ERROR("Only --aq_mode=0 can be used with --lossless=1."); if (extra_cfg->enable_chroma_deltaq) ERROR("Only --enable_chroma_deltaq=0 can be used with --lossless=1."); -#if CONFIG_DIST_8X8 - if (extra_cfg->enable_dist_8x8) - ERROR("dist-8x8 cannot be used with lossless compression."); -#endif } if (cfg->rc_resize_mode != RESIZE_NONE && @@ -517,8 +557,6 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx, 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) { const int level_idx = extra_cfg->target_seq_level_idx[i]; if (!is_valid_seq_level_idx(level_idx) && level_idx != SEQ_LEVELS) { @@ -559,6 +597,10 @@ static aom_codec_err_t validate_img(aom_codec_alg_priv_t *ctx, if (img->d_w != ctx->cfg.g_w || img->d_h != ctx->cfg.g_h) ERROR("Image size must match encoder init configuration size"); + if (img->fmt != AOM_IMG_FMT_I420 && !ctx->extra_cfg.enable_tx64) { + ERROR("TX64 can only be disabled on I420 images."); + } + return AOM_CODEC_OK; } @@ -586,9 +628,73 @@ static void disable_superres(AV1EncoderConfig *const oxcf) { oxcf->superres_kf_qthresh = 255; } -static aom_codec_err_t set_encoder_config( - AV1EncoderConfig *oxcf, const aom_codec_enc_cfg_t *cfg, - const struct av1_extracfg *extra_cfg) { +static void update_default_encoder_config(const cfg_options_t *cfg, + struct av1_extracfg *extra_cfg) { + extra_cfg->enable_cdef = (cfg->disable_cdef == 0); + extra_cfg->enable_restoration = (cfg->disable_lr == 0); + extra_cfg->superblock_size = (cfg->super_block_size == 64) + ? AOM_SUPERBLOCK_SIZE_64X64 + : (cfg->super_block_size == 128) + ? AOM_SUPERBLOCK_SIZE_128X128 + : AOM_SUPERBLOCK_SIZE_DYNAMIC; + extra_cfg->enable_warped_motion = (cfg->disable_warp_motion == 0); + extra_cfg->enable_dist_wtd_comp = (cfg->disable_dist_wtd_comp == 0); + extra_cfg->enable_diff_wtd_comp = (cfg->disable_diff_wtd_comp == 0); + extra_cfg->enable_dual_filter = (cfg->disable_dual_filter == 0); + extra_cfg->enable_angle_delta = (cfg->disable_intra_angle_delta == 0); + extra_cfg->enable_rect_partitions = (cfg->disable_rect_partition_type == 0); + extra_cfg->enable_ab_partitions = (cfg->disable_ab_partition_type == 0); + extra_cfg->enable_1to4_partitions = (cfg->disable_1to4_partition_type == 0); + extra_cfg->max_partition_size = cfg->max_partition_size; + extra_cfg->min_partition_size = cfg->min_partition_size; + extra_cfg->enable_intra_edge_filter = (cfg->disable_intra_edge_filter == 0); + extra_cfg->enable_tx64 = (cfg->disable_tx_64x64 == 0); + extra_cfg->enable_flip_idtx = (cfg->disable_flip_idtx == 0); + extra_cfg->enable_masked_comp = (cfg->disable_masked_comp == 0); + extra_cfg->enable_interintra_comp = (cfg->disable_inter_intra_comp == 0); + extra_cfg->enable_smooth_interintra = (cfg->disable_smooth_inter_intra == 0); + extra_cfg->enable_interinter_wedge = (cfg->disable_inter_inter_wedge == 0); + extra_cfg->enable_interintra_wedge = (cfg->disable_inter_intra_wedge == 0); + extra_cfg->enable_global_motion = (cfg->disable_global_motion == 0); + extra_cfg->enable_filter_intra = (cfg->disable_filter_intra == 0); + extra_cfg->enable_smooth_intra = (cfg->disable_smooth_intra == 0); + extra_cfg->enable_paeth_intra = (cfg->disable_paeth_intra == 0); + extra_cfg->enable_cfl_intra = (cfg->disable_cfl == 0); + extra_cfg->enable_obmc = (cfg->disable_obmc == 0); + extra_cfg->enable_palette = (cfg->disable_palette == 0); + extra_cfg->enable_intrabc = (cfg->disable_intrabc == 0); + extra_cfg->disable_trellis_quant = cfg->disable_trellis_quant; + extra_cfg->allow_ref_frame_mvs = (cfg->disable_ref_frame_mv == 0); + extra_cfg->enable_ref_frame_mvs = (cfg->disable_ref_frame_mv == 0); + extra_cfg->enable_onesided_comp = (cfg->disable_one_sided_comp == 0); + extra_cfg->enable_reduced_reference_set = cfg->reduced_reference_set; + extra_cfg->reduced_tx_type_set = cfg->reduced_tx_type_set; +} + +static double convert_qp_offset(int cq_level, int q_offset, int bit_depth) { + const double base_q_val = av1_convert_qindex_to_q(cq_level, bit_depth); + const int new_q_index_offset = av1_quantizer_to_qindex(q_offset); + const int new_q_index = AOMMAX(cq_level - new_q_index_offset, 0); + const double new_q_val = av1_convert_qindex_to_q(new_q_index, bit_depth); + return (base_q_val - new_q_val); +} + +static double get_modeled_qp_offset(int cq_level, int level, int bit_depth) { + // 80% for keyframe was derived empirically. + // 40% similar to rc_pick_q_and_bounds_one_pass_vbr() for Q mode ARF. + // Rest derived similar to rc_pick_q_and_bounds_two_pass() + static const int percents[FIXED_QP_OFFSET_COUNT] = { 76, 60, 30, 15, 8 }; + const double q_val = av1_convert_qindex_to_q(cq_level, bit_depth); + return q_val * percents[level] / 100; +} + +static aom_codec_err_t set_encoder_config(AV1EncoderConfig *oxcf, + const aom_codec_enc_cfg_t *cfg, + struct av1_extracfg *extra_cfg) { + if (cfg->encoder_cfg.init_by_cfg_file) { + update_default_encoder_config(&cfg->encoder_cfg, extra_cfg); + } + const int is_vbr = cfg->rc_end_usage == AOM_VBR; oxcf->profile = cfg->g_profile; oxcf->fwd_kf_enabled = cfg->fwd_kf_enabled; @@ -636,6 +742,7 @@ static aom_codec_err_t set_encoder_config( oxcf->init_framerate = 30; oxcf->timing_info_present = 0; } + oxcf->encoder_cfg = &cfg->encoder_cfg; switch (cfg->g_pass) { case AOM_RC_ONE_PASS: oxcf->pass = 0; break; @@ -643,7 +750,7 @@ static aom_codec_err_t set_encoder_config( case AOM_RC_LAST_PASS: oxcf->pass = 2; break; } - oxcf->lag_in_frames = cfg->g_lag_in_frames; + oxcf->lag_in_frames = clamp(cfg->g_lag_in_frames, 0, MAX_LAG_BUFFERS); oxcf->rc_mode = cfg->rc_end_usage; // Convert target bandwidth from Kbit/s to Bit/s @@ -669,6 +776,7 @@ static aom_codec_err_t set_encoder_config( oxcf->enable_intrabc = extra_cfg->enable_intrabc; oxcf->enable_angle_delta = extra_cfg->enable_angle_delta; oxcf->disable_trellis_quant = extra_cfg->disable_trellis_quant; + oxcf->allow_ref_frame_mvs = extra_cfg->enable_ref_frame_mvs; oxcf->using_qm = extra_cfg->enable_qm; oxcf->qm_y = extra_cfg->qm_y; oxcf->qm_u = extra_cfg->qm_u; @@ -683,12 +791,6 @@ static aom_codec_err_t set_encoder_config( 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; oxcf->mv_cost_upd_freq = (COST_UPDATE_TYPE)extra_cfg->mv_cost_upd_freq; -#if CONFIG_DIST_8X8 - oxcf->using_dist_8x8 = extra_cfg->enable_dist_8x8; - if (extra_cfg->tuning == AOM_TUNE_CDEF_DIST || - extra_cfg->tuning == AOM_TUNE_DAALA_DIST) - oxcf->using_dist_8x8 = 1; -#endif oxcf->num_tile_groups = extra_cfg->num_tg; // In large-scale tile encoding mode, num_tile_groups is always 1. if (cfg->large_scale_tile) oxcf->num_tile_groups = 1; @@ -766,15 +868,14 @@ static aom_codec_err_t set_encoder_config( oxcf->render_width = extra_cfg->render_width; oxcf->render_height = extra_cfg->render_height; oxcf->arnr_max_frames = extra_cfg->arnr_max_frames; - // Adjust g_lag_in_frames down if not needed - oxcf->lag_in_frames = - AOMMIN(MAX_GF_INTERVAL + oxcf->arnr_max_frames / 2, oxcf->lag_in_frames); oxcf->arnr_strength = extra_cfg->arnr_strength; oxcf->min_gf_interval = extra_cfg->min_gf_interval; oxcf->max_gf_interval = extra_cfg->max_gf_interval; + oxcf->gf_min_pyr_height = extra_cfg->gf_min_pyr_height; oxcf->gf_max_pyr_height = extra_cfg->gf_max_pyr_height; oxcf->tuning = extra_cfg->tuning; + oxcf->vmaf_model_path = extra_cfg->vmaf_model_path; oxcf->content = extra_cfg->content; oxcf->cdf_update_mode = (uint8_t)extra_cfg->cdf_update_mode; oxcf->superblock_size = extra_cfg->superblock_size; @@ -817,7 +918,6 @@ static aom_codec_err_t set_encoder_config( 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 = @@ -887,12 +987,6 @@ static aom_codec_err_t set_encoder_config( oxcf->enable_chroma_deltaq = extra_cfg->enable_chroma_deltaq; oxcf->aq_mode = extra_cfg->aq_mode; oxcf->deltaq_mode = extra_cfg->deltaq_mode; - // Turn on tpl model for deltaq_mode == DELTA_Q_OBJECTIVE and no - // superres. If superres is being used on the other hand, turn - // delta_q off. - if (oxcf->deltaq_mode == DELTA_Q_OBJECTIVE && !oxcf->enable_tpl_model) { - oxcf->enable_tpl_model = 1; - } oxcf->deltalf_mode = (oxcf->deltaq_mode != NO_DELTA_Q) && extra_cfg->deltalf_mode; @@ -901,6 +995,8 @@ static aom_codec_err_t set_encoder_config( oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost; oxcf->motion_vector_unit_test = extra_cfg->motion_vector_unit_test; + oxcf->sb_multipass_unit_test = extra_cfg->sb_multipass_unit_test; + oxcf->ext_tile_debug = extra_cfg->ext_tile_debug; oxcf->chroma_subsampling_x = extra_cfg->chroma_subsampling_x; oxcf->chroma_subsampling_y = extra_cfg->chroma_subsampling_y; @@ -910,6 +1006,23 @@ static aom_codec_err_t set_encoder_config( 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; + + oxcf->use_fixed_qp_offsets = + cfg->use_fixed_qp_offsets && (oxcf->rc_mode == AOM_Q); + for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { + if (oxcf->use_fixed_qp_offsets) { + if (cfg->fixed_qp_offsets[i] >= 0) { // user-provided qp offset + oxcf->fixed_qp_offsets[i] = convert_qp_offset( + oxcf->cq_level, cfg->fixed_qp_offsets[i], oxcf->bit_depth); + } else { // auto-selected qp offset + oxcf->fixed_qp_offsets[i] = + get_modeled_qp_offset(oxcf->cq_level, i, oxcf->bit_depth); + } + } else { + oxcf->fixed_qp_offsets[i] = -1.0; + } + } + oxcf->min_cr = extra_cfg->min_cr; return AOM_CODEC_OK; } @@ -934,6 +1047,10 @@ static aom_codec_err_t encoder_set_config(aom_codec_alg_priv_t *ctx, // config. if (cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames) ERROR("Cannot increase lag_in_frames"); + // Prevent changing lag_in_frames if Lookahead Processing is enabled + if (cfg->g_lag_in_frames != ctx->cfg.g_lag_in_frames && + ctx->num_lap_buffers > 0) + ERROR("Cannot change lag_in_frames if LAP is enabled"); res = validate_config(ctx, cfg, &ctx->extra_cfg); @@ -971,7 +1088,7 @@ static aom_codec_err_t ctrl_get_quantizer64(aom_codec_alg_priv_t *ctx, } static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx, - const struct av1_extracfg *extra_cfg) { + struct av1_extracfg *extra_cfg) { const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg); if (res == AOM_CODEC_OK) { ctx->extra_cfg = *extra_cfg; @@ -1186,14 +1303,7 @@ static aom_codec_err_t ctrl_set_qm_max(aom_codec_alg_priv_t *ctx, extra_cfg.qm_max = CAST(AV1E_SET_QM_MAX, args); return update_extra_cfg(ctx, &extra_cfg); } -#if CONFIG_DIST_8X8 -static aom_codec_err_t ctrl_set_enable_dist_8x8(aom_codec_alg_priv_t *ctx, - va_list args) { - struct av1_extracfg extra_cfg = ctx->extra_cfg; - extra_cfg.enable_dist_8x8 = CAST(AV1E_SET_ENABLE_DIST_8X8, args); - return update_extra_cfg(ctx, &extra_cfg); -} -#endif + static aom_codec_err_t ctrl_set_num_tg(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1286,13 +1396,6 @@ 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; @@ -1566,6 +1669,13 @@ static aom_codec_err_t ctrl_set_mv_cost_upd_freq(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_vmaf_model_path(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.vmaf_model_path = CAST(AV1E_SET_VMAF_MODEL_PATH, 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; @@ -1636,6 +1746,13 @@ static aom_codec_err_t ctrl_set_max_gf_interval(aom_codec_alg_priv_t *ctx, return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_set_gf_min_pyr_height(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.gf_min_pyr_height = CAST(AV1E_SET_GF_MIN_PYRAMID_HEIGHT, args); + return update_extra_cfg(ctx, &extra_cfg); +} + static aom_codec_err_t ctrl_set_gf_max_pyr_height(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; @@ -1658,6 +1775,13 @@ static aom_codec_err_t ctrl_enable_motion_vector_unit_test( return update_extra_cfg(ctx, &extra_cfg); } +static aom_codec_err_t ctrl_enable_ext_tile_debug(aom_codec_alg_priv_t *ctx, + va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.ext_tile_debug = CAST(AV1E_ENABLE_EXT_TILE_DEBUG, args); + 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; @@ -1685,10 +1809,68 @@ static aom_codec_err_t ctrl_set_min_cr(aom_codec_alg_priv_t *ctx, 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) { +static aom_codec_err_t ctrl_enable_sb_multipass_unit_test( + aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.sb_multipass_unit_test = + CAST(AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +#if !CONFIG_REALTIME_ONLY +static aom_codec_err_t create_stats_buffer(FIRSTPASS_STATS **frame_stats_buffer, + STATS_BUFFER_CTX *stats_buf_context, + int num_lap_buffers) { + aom_codec_err_t res = AOM_CODEC_OK; + + int size = get_stats_buf_size(num_lap_buffers, MAX_LAG_BUFFERS); + *frame_stats_buffer = + (FIRSTPASS_STATS *)aom_calloc(size, sizeof(FIRSTPASS_STATS)); + if (*frame_stats_buffer == NULL) return AOM_CODEC_MEM_ERROR; + + stats_buf_context->stats_in_start = *frame_stats_buffer; + stats_buf_context->stats_in_end = stats_buf_context->stats_in_start; + stats_buf_context->stats_in_buf_end = + stats_buf_context->stats_in_start + size; + + stats_buf_context->total_left_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); + if (stats_buf_context->total_left_stats == NULL) return AOM_CODEC_MEM_ERROR; + av1_twopass_zero_stats(stats_buf_context->total_left_stats); + stats_buf_context->total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS)); + if (stats_buf_context->total_stats == NULL) return AOM_CODEC_MEM_ERROR; + av1_twopass_zero_stats(stats_buf_context->total_stats); + return res; +} +#endif + +static aom_codec_err_t create_context_and_bufferpool( + AV1_COMP **p_cpi, BufferPool **p_buffer_pool, AV1EncoderConfig *oxcf, + struct aom_codec_pkt_list *pkt_list_head, FIRSTPASS_STATS *frame_stats_buf, + COMPRESSOR_STAGE stage, int num_lap_buffers, int lap_lag_in_frames, + STATS_BUFFER_CTX *stats_buf_context) { + aom_codec_err_t res = AOM_CODEC_OK; + + *p_buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool)); + if (*p_buffer_pool == NULL) return AOM_CODEC_MEM_ERROR; + +#if CONFIG_MULTITHREAD + if (pthread_mutex_init(&((*p_buffer_pool)->pool_mutex), NULL)) { + return AOM_CODEC_MEM_ERROR; + } +#endif + *p_cpi = av1_create_compressor(oxcf, *p_buffer_pool, frame_stats_buf, stage, + num_lap_buffers, lap_lag_in_frames, + stats_buf_context); + if (*p_cpi == NULL) + res = AOM_CODEC_MEM_ERROR; + else + (*p_cpi)->output_pkt_list = pkt_list_head; + + return res; +} + +static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx) { aom_codec_err_t res = AOM_CODEC_OK; - (void)data; if (ctx->priv == NULL) { aom_codec_alg_priv_t *const priv = aom_calloc(1, sizeof(*priv)); @@ -1696,15 +1878,6 @@ static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx, ctx->priv = (aom_codec_priv_t *)priv; ctx->priv->init_flags = ctx->init_flags; - ctx->priv->enc.total_encoders = 1; - priv->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool)); - if (priv->buffer_pool == NULL) return AOM_CODEC_MEM_ERROR; - -#if CONFIG_MULTITHREAD - if (pthread_mutex_init(&priv->buffer_pool->pool_mutex, NULL)) { - return AOM_CODEC_MEM_ERROR; - } -#endif if (ctx->config.enc) { // Update the reference to the config structure to an internal copy. @@ -1718,32 +1891,83 @@ static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx, res = validate_config(priv, &priv->cfg, &priv->extra_cfg); if (res == AOM_CODEC_OK) { + int *num_lap_buffers = &priv->num_lap_buffers; + int lap_lag_in_frames = 0; + *num_lap_buffers = 0; priv->timestamp_ratio.den = priv->cfg.g_timebase.den; priv->timestamp_ratio.num = (int64_t)priv->cfg.g_timebase.num * TICKS_PER_SEC; reduce_ratio(&priv->timestamp_ratio); set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg); + if (priv->oxcf.rc_mode == AOM_Q && priv->oxcf.pass == 0 && + priv->oxcf.mode == GOOD) { + // Enable look ahead + *num_lap_buffers = priv->cfg.g_lag_in_frames; + *num_lap_buffers = + clamp(*num_lap_buffers, 1, + AOMMIN(MAX_LAP_BUFFERS, + priv->oxcf.key_freq + SCENE_CUT_KEY_TEST_INTERVAL)); + if ((int)priv->cfg.g_lag_in_frames - (*num_lap_buffers) >= + LAP_LAG_IN_FRAMES) { + lap_lag_in_frames = LAP_LAG_IN_FRAMES; + } + } priv->oxcf.use_highbitdepth = (ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) ? 1 : 0; - priv->cpi = av1_create_compressor(&priv->oxcf, priv->buffer_pool); - if (priv->cpi == NULL) - res = AOM_CODEC_MEM_ERROR; - else - priv->cpi->output_pkt_list = &priv->pkt_list.head; + +#if !CONFIG_REALTIME_ONLY + res = create_stats_buffer(&priv->frame_stats_buffer, + &priv->stats_buf_context, *num_lap_buffers); + if (res != AOM_CODEC_OK) return AOM_CODEC_MEM_ERROR; +#endif + + res = create_context_and_bufferpool( + &priv->cpi, &priv->buffer_pool, &priv->oxcf, &priv->pkt_list.head, + priv->frame_stats_buffer, ENCODE_STAGE, *num_lap_buffers, -1, + &priv->stats_buf_context); + + // Create another compressor if look ahead is enabled + if (res == AOM_CODEC_OK && *num_lap_buffers) { + res = create_context_and_bufferpool( + &priv->cpi_lap, &priv->buffer_pool_lap, &priv->oxcf, NULL, + priv->frame_stats_buffer, LAP_STAGE, *num_lap_buffers, + clamp(lap_lag_in_frames, 0, MAX_LAG_BUFFERS), + &priv->stats_buf_context); + } } } return res; } +static void destroy_context_and_bufferpool(AV1_COMP *cpi, + BufferPool *buffer_pool) { + av1_remove_compressor(cpi); +#if CONFIG_MULTITHREAD + if (buffer_pool) pthread_mutex_destroy(&buffer_pool->pool_mutex); +#endif + aom_free(buffer_pool); +} + +static void destroy_stats_buffer(STATS_BUFFER_CTX *stats_buf_context, + FIRSTPASS_STATS *frame_stats_buffer) { + aom_free(stats_buf_context->total_left_stats); + aom_free(stats_buf_context->total_stats); + aom_free(frame_stats_buffer); +} + static aom_codec_err_t encoder_destroy(aom_codec_alg_priv_t *ctx) { free(ctx->cx_data); - av1_remove_compressor(ctx->cpi); -#if CONFIG_MULTITHREAD - pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex); -#endif - aom_free(ctx->buffer_pool); + destroy_context_and_bufferpool(ctx->cpi, ctx->buffer_pool); + if (ctx->cpi_lap) { + // As both cpi and cpi_lap have the same lookahead_ctx, it is already freed + // when destroy is called on cpi. Thus, setting lookahead_ctx to null here, + // so that it doesn't attempt to free it again. + ctx->cpi_lap->lookahead = NULL; + destroy_context_and_bufferpool(ctx->cpi_lap, ctx->buffer_pool_lap); + } + destroy_stats_buffer(&ctx->stats_buf_context, ctx->frame_stats_buffer); aom_free(ctx); return AOM_CODEC_OK; } @@ -1762,6 +1986,8 @@ static aom_codec_frame_flags_t get_frame_pkt_flags(const AV1_COMP *cpi, return flags; } +// TODO(Mufaddal): Check feasibility of abstracting functions related to LAP +// into a separate function. static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, const aom_image_t *img, aom_codec_pts_t pts, @@ -1772,9 +1998,14 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, AV1_COMP *const cpi = ctx->cpi; const aom_rational64_t *const timestamp_ratio = &ctx->timestamp_ratio; volatile aom_codec_pts_t ptsvol = pts; + // LAP context + AV1_COMP *cpi_lap = ctx->cpi_lap; if (cpi == NULL) return AOM_CODEC_INVALID_PARAM; + if (cpi->lap_enabled && cpi_lap == NULL && cpi->oxcf.pass == 0) + return AOM_CODEC_INVALID_PARAM; + if (img != NULL) { res = validate_img(ctx, img); // TODO(jzern) the checks related to cpi's validity should be treated as a @@ -1818,19 +2049,33 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, return res; } cpi->common.error.setjmp = 1; + if (cpi_lap != NULL) { + if (setjmp(cpi_lap->common.error.jmp)) { + cpi_lap->common.error.setjmp = 0; + res = update_error_state(ctx, &cpi_lap->common.error); + aom_clear_system_state(); + return res; + } + cpi_lap->common.error.setjmp = 1; + } // Note(yunqing): While applying encoding flags, always start from enabling // all, and then modifying according to the flags. Previous frame's flags are // overwritten. av1_apply_encoding_flags(cpi, flags); + if (cpi_lap != NULL) { + av1_apply_encoding_flags(cpi_lap, flags); + } // Handle fixed keyframe intervals - if (ctx->cfg.kf_mode == AOM_KF_AUTO && - ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) { - if (cpi->common.spatial_layer_id == 0 && - ++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) { - flags |= AOM_EFLAG_FORCE_KF; - ctx->fixed_kf_cntr = 1; + if (is_stat_generation_stage(cpi)) { + if (ctx->cfg.kf_mode == AOM_KF_AUTO && + ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) { + if (cpi->common.spatial_layer_id == 0 && + ++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) { + flags |= AOM_EFLAG_FORCE_KF; + ctx->fixed_kf_cntr = 1; + } } } @@ -1844,7 +2089,32 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, if (img != NULL) { YV12_BUFFER_CONFIG sd; + int use_highbitdepth, subsampling_x, subsampling_y; res = image2yuvconfig(img, &sd); + use_highbitdepth = (sd.flags & YV12_FLAG_HIGHBITDEPTH) != 0; + subsampling_x = sd.subsampling_x; + subsampling_y = sd.subsampling_y; + + if (!cpi->lookahead) { + int lag_in_frames = cpi_lap != NULL ? cpi_lap->oxcf.lag_in_frames + : cpi->oxcf.lag_in_frames; + + cpi->lookahead = av1_lookahead_init( + cpi->oxcf.width, cpi->oxcf.height, subsampling_x, subsampling_y, + use_highbitdepth, lag_in_frames, cpi->oxcf.border_in_pixels, + cpi->common.features.byte_alignment, ctx->num_lap_buffers); + } + if (!cpi->lookahead) + aom_internal_error(&cpi->common.error, AOM_CODEC_MEM_ERROR, + "Failed to allocate lag buffers"); + + av1_check_initial_width(cpi, use_highbitdepth, subsampling_x, + subsampling_y); + if (cpi_lap != NULL) { + cpi_lap->lookahead = cpi->lookahead; + av1_check_initial_width(cpi_lap, use_highbitdepth, subsampling_x, + subsampling_y); + } // Store the original flags in to the frame buffer. Will extract the // key frame flag when we actually encode this frame. @@ -1881,6 +2151,26 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, int is_frame_visible = 0; int index_size = 0; int has_fwd_keyframe = 0; + + // Call for LAP stage + if (cpi_lap != NULL) { + int status; + aom_rational64_t timestamp_ratio_la = *timestamp_ratio; + int64_t dst_time_stamp_la = dst_time_stamp; + int64_t dst_end_time_stamp_la = dst_end_time_stamp; + status = av1_get_compressed_data( + cpi_lap, &lib_flags, &frame_size, NULL, &dst_time_stamp_la, + &dst_end_time_stamp_la, !img, ×tamp_ratio_la); + if (status != -1) { + if (status != AOM_CODEC_OK) { + aom_internal_error(&cpi_lap->common.error, AOM_CODEC_ERROR, NULL); + } + cpi_lap->seq_params_locked = 1; + } + lib_flags = 0; + frame_size = 0; + } + // invisible frames get packed with the next visible frame while (cx_data_sz - index_size >= ctx->cx_data_sz / 2 && !is_frame_visible) { @@ -1912,7 +2202,7 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx, } const uint32_t obu_header_offset = 0; obu_header_size = av1_write_obu_header( - cpi, OBU_TEMPORAL_DELIMITER, 0, + &cpi->level_params, OBU_TEMPORAL_DELIMITER, 0, (uint8_t *)(ctx->pending_cx_data + obu_header_offset)); // OBUs are preceded/succeeded by an unsigned leb128 coded integer. @@ -2097,13 +2387,6 @@ static aom_codec_err_t ctrl_copy_new_frame_image(aom_codec_alg_priv_t *ctx, } } -static aom_codec_err_t ctrl_set_previewpp(aom_codec_alg_priv_t *ctx, - va_list args) { - (void)ctx; - (void)args; - return AOM_CODEC_INCAPABLE; -} - static aom_image_t *encoder_get_preview(aom_codec_alg_priv_t *ctx) { YV12_BUFFER_CONFIG sd; @@ -2119,7 +2402,7 @@ static aom_codec_err_t ctrl_use_reference(aom_codec_alg_priv_t *ctx, va_list args) { const int reference_flag = va_arg(args, int); - av1_use_as_reference(ctx->cpi, reference_flag); + av1_use_as_reference(&ctx->cpi->ext_flags.ref_frame_flags, reference_flag); return AOM_CODEC_OK; } @@ -2167,9 +2450,9 @@ static aom_codec_err_t ctrl_set_scale_mode(aom_codec_alg_priv_t *ctx, aom_scaling_mode_t *const mode = va_arg(args, aom_scaling_mode_t *); if (mode) { - const int res = - av1_set_internal_size(ctx->cpi, (AOM_SCALING)mode->h_scaling_mode, - (AOM_SCALING)mode->v_scaling_mode); + const int res = av1_set_internal_size( + &ctx->cpi->oxcf, &ctx->cpi->resize_pending_params, + (AOM_SCALING)mode->h_scaling_mode, (AOM_SCALING)mode->v_scaling_mode); return (res == 0) ? AOM_CODEC_OK : AOM_CODEC_INVALID_PARAM; } else { return AOM_CODEC_INVALID_PARAM; @@ -2179,7 +2462,7 @@ static aom_codec_err_t ctrl_set_scale_mode(aom_codec_alg_priv_t *ctx, static aom_codec_err_t ctrl_set_spatial_layer_id(aom_codec_alg_priv_t *ctx, va_list args) { const int spatial_layer_id = va_arg(args, int); - if (spatial_layer_id > MAX_NUM_ENHANCEMENT_LAYERS) + if (spatial_layer_id >= MAX_NUM_SPATIAL_LAYERS) return AOM_CODEC_INVALID_PARAM; ctx->cpi->common.spatial_layer_id = spatial_layer_id; return AOM_CODEC_OK; @@ -2188,7 +2471,7 @@ static aom_codec_err_t ctrl_set_spatial_layer_id(aom_codec_alg_priv_t *ctx, static aom_codec_err_t ctrl_set_number_spatial_layers(aom_codec_alg_priv_t *ctx, va_list args) { const int number_spatial_layers = va_arg(args, int); - if (number_spatial_layers > MAX_NUM_ENHANCEMENT_LAYERS) + if (number_spatial_layers > MAX_NUM_SPATIAL_LAYERS) return AOM_CODEC_INVALID_PARAM; ctx->cpi->common.number_spatial_layers = number_spatial_layers; return AOM_CODEC_OK; @@ -2243,8 +2526,10 @@ static aom_codec_err_t ctrl_set_svc_ref_frame_config(aom_codec_alg_priv_t *ctx, aom_svc_ref_frame_config_t *const data = va_arg(args, aom_svc_ref_frame_config_t *); cpi->svc.external_ref_frame_config = 1; - for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; ++i) + for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; ++i) { + cpi->svc.reference[i] = data->reference[i]; cpi->svc.ref_idx[i] = data->ref_idx[i]; + } for (unsigned int i = 0; i < REF_FRAMES; ++i) cpi->svc.refresh[i] = data->refresh[i]; return AOM_CODEC_OK; @@ -2334,8 +2619,10 @@ static aom_codec_err_t ctrl_set_chroma_subsampling_y(aom_codec_alg_priv_t *ctx, 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 *); + const AV1_COMP *const cpi = ctx->cpi; if (arg == NULL) return AOM_CODEC_INVALID_PARAM; - return av1_get_seq_level_idx(ctx->cpi, arg); + return av1_get_seq_level_idx(&cpi->common.seq_params, &cpi->level_params, + arg); } static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { @@ -2344,7 +2631,6 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { // Setters { AV1_SET_REFERENCE, ctrl_set_reference }, - { AOM_SET_POSTPROC, ctrl_set_previewpp }, { AOME_SET_ROI_MAP, ctrl_set_roi_map }, { AOME_SET_ACTIVEMAP, ctrl_set_active_map }, { AOME_SET_SCALEMODE, ctrl_set_scale_mode }, @@ -2379,9 +2665,6 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1E_SET_QM_V, ctrl_set_qm_v }, { AV1E_SET_QM_MIN, ctrl_set_qm_min }, { AV1E_SET_QM_MAX, ctrl_set_qm_max }, -#if CONFIG_DIST_8X8 - { AV1E_SET_ENABLE_DIST_8X8, ctrl_set_enable_dist_8x8 }, -#endif { AV1E_SET_NUM_TG, ctrl_set_num_tg }, { AV1E_SET_MTU, ctrl_set_mtu }, { AV1E_SET_TIMING_INFO_TYPE, ctrl_set_timing_info_type }, @@ -2398,7 +2681,6 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { 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 }, @@ -2446,21 +2728,25 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { AV1E_SET_NOISE_SENSITIVITY, ctrl_set_noise_sensitivity }, { AV1E_SET_MIN_GF_INTERVAL, ctrl_set_min_gf_interval }, { AV1E_SET_MAX_GF_INTERVAL, ctrl_set_max_gf_interval }, + { AV1E_SET_GF_MIN_PYRAMID_HEIGHT, ctrl_set_gf_min_pyr_height }, { AV1E_SET_GF_MAX_PYRAMID_HEIGHT, ctrl_set_gf_max_pyr_height }, { AV1E_SET_RENDER_SIZE, ctrl_set_render_size }, { AV1E_SET_SUPERBLOCK_SIZE, ctrl_set_superblock_size }, { AV1E_SET_SINGLE_TILE_DECODING, ctrl_set_single_tile_decoding }, + { AV1E_SET_VMAF_MODEL_PATH, ctrl_set_vmaf_model_path }, { AV1E_SET_FILM_GRAIN_TEST_VECTOR, ctrl_set_film_grain_test_vector }, { AV1E_SET_FILM_GRAIN_TABLE, ctrl_set_film_grain_table }, { AV1E_SET_DENOISE_NOISE_LEVEL, ctrl_set_denoise_noise_level }, { AV1E_SET_DENOISE_BLOCK_SIZE, ctrl_set_denoise_block_size }, { AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test }, + { AV1E_ENABLE_EXT_TILE_DEBUG, ctrl_enable_ext_tile_debug }, { AV1E_SET_TARGET_SEQ_LEVEL_IDX, ctrl_set_target_seq_level_idx }, { AV1E_SET_TIER_MASK, ctrl_set_tier_mask }, { AV1E_SET_MIN_CR, ctrl_set_min_cr }, { AV1E_SET_SVC_LAYER_ID, ctrl_set_layer_id }, { AV1E_SET_SVC_PARAMS, ctrl_set_svc_params }, { AV1E_SET_SVC_REF_FRAME_CONFIG, ctrl_set_svc_ref_frame_config }, + { AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST, ctrl_enable_sb_multipass_unit_test }, // Getters { AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer }, @@ -2475,141 +2761,147 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { -1, NULL }, }; -static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { - { 0, - { - // NOLINT - AOM_USAGE_GOOD_QUALITY, // g_usage - non-realtime usage - 0, // g_threads - 0, // g_profile +static const aom_codec_enc_cfg_t encoder_usage_cfg[] = { + { + // NOLINT + AOM_USAGE_GOOD_QUALITY, // g_usage - non-realtime 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 + 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 + { 1, 30 }, // g_timebase - 0, // g_error_resilient + 0, // g_error_resilient - AOM_RC_ONE_PASS, // g_pass + AOM_RC_ONE_PASS, // g_pass - 19, // g_lag_in_frames + 19, // 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_dropframe_thresh + RESIZE_NONE, // rc_resize_mode + SCALE_NUMERATOR, // rc_resize_denominator + SCALE_NUMERATOR, // rc_resize_kf_denominator - SUPERRES_NONE, // rc_superres_mode - SCALE_NUMERATOR, // rc_superres_denominator - SCALE_NUMERATOR, // rc_superres_kf_denominator - 63, // rc_superres_qthresh - 32, // rc_superres_kf_qthresh + SUPERRES_NONE, // rc_superres_mode + SCALE_NUMERATOR, // rc_superres_denominator + SCALE_NUMERATOR, // rc_superres_kf_denominator + 63, // rc_superres_qthresh + 32, // rc_superres_kf_qthresh - AOM_VBR, // 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 + AOM_VBR, // 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 + 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 + 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 - 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, - { - // NOLINT - AOM_USAGE_REALTIME, // g_usage - real-time usage - 0, // g_threads - 0, // g_profile + // 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 + 0, // use_fixed_qp_offsets + { -1, -1, -1, -1, -1 }, // fixed_qp_offsets + { 0, 128, 128, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // cfg + }, + { + // NOLINT + AOM_USAGE_REALTIME, // 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 + 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 + { 1, 30 }, // g_timebase - 0, // g_error_resilient + 0, // g_error_resilient - AOM_RC_ONE_PASS, // g_pass + AOM_RC_ONE_PASS, // g_pass - 1, // g_lag_in_frames + 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_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 + 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 + 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 + 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 + 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 - 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 - } }, + // 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 + 0, // use_fixed_qp_offsets + { -1, -1, -1, -1, -1 }, // fixed_qp_offsets + { 0, 128, 128, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // cfg + }, }; #ifndef VERSION_STRING @@ -2633,13 +2925,12 @@ CODEC_INTERFACE(aom_codec_av1_cx) = { }, { // NOLINT - 2, // 2 cfg map - encoder_usage_cfg_map, // aom_codec_enc_cfg_map_t + 2, // 2 cfg + encoder_usage_cfg, // aom_codec_enc_cfg_t encoder_encode, // aom_codec_encode_fn_t encoder_get_cxdata, // aom_codec_get_cx_data_fn_t encoder_set_config, // aom_codec_enc_config_set_fn_t encoder_get_global_headers, // aom_codec_get_global_headers_fn_t - encoder_get_preview, // aom_codec_get_preview_frame_fn_t - NULL // aom_codec_enc_mr_get_mem_loc_fn_t + encoder_get_preview // aom_codec_get_preview_frame_fn_t } }; diff --git a/media/libaom/src/av1/av1_dx_iface.c b/media/libaom/src/av1/av1_dx_iface.c index 6b06ad4bf1..d821a52f6e 100644 --- a/media/libaom/src/av1/av1_dx_iface.c +++ b/media/libaom/src/av1/av1_dx_iface.c @@ -39,8 +39,6 @@ struct aom_codec_alg_priv { aom_codec_priv_t base; aom_codec_dec_cfg_t cfg; aom_codec_stream_info_t si; - int postproc_cfg_set; - aom_postproc_cfg_t postproc_cfg; aom_image_t img; int img_avail; int flushed; @@ -59,12 +57,7 @@ struct aom_codec_alg_priv { int operating_point; int output_all_layers; - // TODO(wtc): This can be simplified. num_frame_workers is always 1, and - // next_output_worker_id is always 0. The frame_workers array of size 1 can - // be replaced by a single AVxWorker. - AVxWorker *frame_workers; - int num_frame_workers; - int next_output_worker_id; + AVxWorker *frame_worker; aom_image_t image_with_grain; aom_codec_frame_buffer_t grain_image_frame_buffers[MAX_NUM_SPATIAL_LAYERS]; @@ -84,13 +77,10 @@ struct aom_codec_alg_priv { #endif }; -static aom_codec_err_t decoder_init(aom_codec_ctx_t *ctx, - aom_codec_priv_enc_mr_cfg_t *data) { +static aom_codec_err_t decoder_init(aom_codec_ctx_t *ctx) { // This function only allocates space for the aom_codec_alg_priv_t // structure. More memory may be required at the time the stream // information becomes known. - (void)data; - if (!ctx->priv) { aom_codec_alg_priv_t *const priv = (aom_codec_alg_priv_t *)aom_calloc(1, sizeof(*priv)); @@ -122,20 +112,16 @@ static aom_codec_err_t decoder_init(aom_codec_ctx_t *ctx, } static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) { - if (ctx->frame_workers != NULL) { - int i; - for (i = 0; i < ctx->num_frame_workers; ++i) { - AVxWorker *const worker = &ctx->frame_workers[i]; - FrameWorkerData *const frame_worker_data = - (FrameWorkerData *)worker->data1; - aom_get_worker_interface()->end(worker); - aom_free(frame_worker_data->pbi->common.tpl_mvs); - frame_worker_data->pbi->common.tpl_mvs = NULL; - av1_remove_common(&frame_worker_data->pbi->common); - av1_free_restoration_buffers(&frame_worker_data->pbi->common); - av1_decoder_remove(frame_worker_data->pbi); - aom_free(frame_worker_data); - } + if (ctx->frame_worker != NULL) { + AVxWorker *const worker = ctx->frame_worker; + FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; + aom_get_worker_interface()->end(worker); + aom_free(frame_worker_data->pbi->common.tpl_mvs); + frame_worker_data->pbi->common.tpl_mvs = NULL; + av1_remove_common(&frame_worker_data->pbi->common); + av1_free_restoration_buffers(&frame_worker_data->pbi->common); + av1_decoder_remove(frame_worker_data->pbi); + aom_free(frame_worker_data); #if CONFIG_MULTITHREAD pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex); #endif @@ -150,8 +136,9 @@ static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) { av1_free_internal_frame_buffers(&ctx->buffer_pool->int_frame_buffers); } - aom_free(ctx->frame_workers); + aom_free(ctx->frame_worker); aom_free(ctx->buffer_pool); + aom_img_free(&ctx->img); aom_free(ctx); return AOM_CODEC_OK; } @@ -383,42 +370,33 @@ static aom_codec_err_t update_error_state( } static void init_buffer_callbacks(aom_codec_alg_priv_t *ctx) { - int i; + AVxWorker *const worker = ctx->frame_worker; + FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; + AV1Decoder *const pbi = frame_worker_data->pbi; + AV1_COMMON *const cm = &pbi->common; + BufferPool *const pool = cm->buffer_pool; - for (i = 0; i < ctx->num_frame_workers; ++i) { - AVxWorker *const worker = &ctx->frame_workers[i]; - FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; - AV1_COMMON *const cm = &frame_worker_data->pbi->common; - BufferPool *const pool = cm->buffer_pool; + cm->cur_frame = NULL; + cm->features.byte_alignment = ctx->byte_alignment; + pbi->skip_loop_filter = ctx->skip_loop_filter; + pbi->skip_film_grain = ctx->skip_film_grain; - cm->cur_frame = NULL; - cm->byte_alignment = ctx->byte_alignment; - cm->skip_loop_filter = ctx->skip_loop_filter; - cm->skip_film_grain = ctx->skip_film_grain; + if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { + pool->get_fb_cb = ctx->get_ext_fb_cb; + pool->release_fb_cb = ctx->release_ext_fb_cb; + pool->cb_priv = ctx->ext_priv; + } else { + pool->get_fb_cb = av1_get_frame_buffer; + pool->release_fb_cb = av1_release_frame_buffer; - if (ctx->get_ext_fb_cb != NULL && ctx->release_ext_fb_cb != NULL) { - pool->get_fb_cb = ctx->get_ext_fb_cb; - pool->release_fb_cb = ctx->release_ext_fb_cb; - pool->cb_priv = ctx->ext_priv; - } else { - pool->get_fb_cb = av1_get_frame_buffer; - pool->release_fb_cb = av1_release_frame_buffer; + if (av1_alloc_internal_frame_buffers(&pool->int_frame_buffers)) + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Failed to initialize internal frame buffers"); - if (av1_alloc_internal_frame_buffers(&pool->int_frame_buffers)) - aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, - "Failed to initialize internal frame buffers"); - - pool->cb_priv = &pool->int_frame_buffers; - } + pool->cb_priv = &pool->int_frame_buffers; } } -static void set_default_ppflags(aom_postproc_cfg_t *cfg) { - cfg->post_proc_flag = AOM_DEBLOCK | AOM_DEMACROBLOCK; - cfg->deblocking_level = 4; - cfg->noise_level = 0; -} - static int frame_worker_hook(void *arg1, void *arg2) { FrameWorkerData *const frame_worker_data = (FrameWorkerData *)arg1; const uint8_t *data = frame_worker_data->data; @@ -436,15 +414,10 @@ static int frame_worker_hook(void *arg1, void *arg2) { } static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) { - int i; const AVxWorkerInterface *const winterface = aom_get_worker_interface(); ctx->last_show_frame = NULL; - ctx->next_output_worker_id = 0; ctx->need_resync = 1; - ctx->num_frame_workers = 1; - if (ctx->num_frame_workers > MAX_DECODE_THREADS) - ctx->num_frame_workers = MAX_DECODE_THREADS; ctx->flushed = 0; ctx->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool)); @@ -457,59 +430,45 @@ static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) { } #endif - ctx->frame_workers = (AVxWorker *)aom_malloc(ctx->num_frame_workers * - sizeof(*ctx->frame_workers)); - if (ctx->frame_workers == NULL) { - set_error_detail(ctx, "Failed to allocate frame_workers"); + ctx->frame_worker = (AVxWorker *)aom_malloc(sizeof(*ctx->frame_worker)); + if (ctx->frame_worker == NULL) { + set_error_detail(ctx, "Failed to allocate frame_worker"); return AOM_CODEC_MEM_ERROR; } - for (i = 0; i < ctx->num_frame_workers; ++i) { - AVxWorker *const worker = &ctx->frame_workers[i]; - FrameWorkerData *frame_worker_data = NULL; - winterface->init(worker); - worker->thread_name = "aom frameworker"; - worker->data1 = aom_memalign(32, sizeof(FrameWorkerData)); - if (worker->data1 == NULL) { - set_error_detail(ctx, "Failed to allocate frame_worker_data"); - return AOM_CODEC_MEM_ERROR; - } - frame_worker_data = (FrameWorkerData *)worker->data1; - frame_worker_data->pbi = av1_decoder_create(ctx->buffer_pool); - if (frame_worker_data->pbi == NULL) { - set_error_detail(ctx, "Failed to allocate frame_worker_data"); - return AOM_CODEC_MEM_ERROR; - } - frame_worker_data->worker_id = i; - frame_worker_data->frame_context_ready = 0; - frame_worker_data->received_frame = 0; - frame_worker_data->pbi->allow_lowbitdepth = ctx->cfg.allow_lowbitdepth; - - // If decoding in serial mode, FrameWorker thread could create tile worker - // thread or loopfilter thread. - frame_worker_data->pbi->max_threads = ctx->cfg.threads; - frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order; - frame_worker_data->pbi->common.large_scale_tile = ctx->tile_mode; - frame_worker_data->pbi->common.is_annexb = ctx->is_annexb; - frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row; - frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col; - frame_worker_data->pbi->operating_point = ctx->operating_point; - frame_worker_data->pbi->output_all_layers = ctx->output_all_layers; - frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug; - frame_worker_data->pbi->row_mt = ctx->row_mt; - - worker->hook = frame_worker_hook; - // The main thread acts as Frame Worker 0. - if (i != 0 && !winterface->reset(worker)) { - set_error_detail(ctx, "Frame Worker thread creation failed"); - return AOM_CODEC_MEM_ERROR; - } + AVxWorker *const worker = ctx->frame_worker; + FrameWorkerData *frame_worker_data = NULL; + winterface->init(worker); + worker->thread_name = "aom frameworker"; + worker->data1 = aom_memalign(32, sizeof(FrameWorkerData)); + if (worker->data1 == NULL) { + set_error_detail(ctx, "Failed to allocate frame_worker_data"); + return AOM_CODEC_MEM_ERROR; } + frame_worker_data = (FrameWorkerData *)worker->data1; + frame_worker_data->pbi = av1_decoder_create(ctx->buffer_pool); + if (frame_worker_data->pbi == NULL) { + set_error_detail(ctx, "Failed to allocate frame_worker_data"); + return AOM_CODEC_MEM_ERROR; + } + frame_worker_data->frame_context_ready = 0; + frame_worker_data->received_frame = 0; + frame_worker_data->pbi->allow_lowbitdepth = ctx->cfg.allow_lowbitdepth; - // If postprocessing was enabled by the application and a - // configuration has not been provided, default it. - if (!ctx->postproc_cfg_set && (ctx->base.init_flags & AOM_CODEC_USE_POSTPROC)) - set_default_ppflags(&ctx->postproc_cfg); + // If decoding in serial mode, FrameWorker thread could create tile worker + // thread or loopfilter thread. + frame_worker_data->pbi->max_threads = ctx->cfg.threads; + frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order; + frame_worker_data->pbi->common.tiles.large_scale = ctx->tile_mode; + frame_worker_data->pbi->is_annexb = ctx->is_annexb; + frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row; + frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col; + frame_worker_data->pbi->operating_point = ctx->operating_point; + frame_worker_data->pbi->output_all_layers = ctx->output_all_layers; + frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug; + frame_worker_data->pbi->row_mt = ctx->row_mt; + + worker->hook = frame_worker_hook; init_buffer_callbacks(ctx); @@ -542,21 +501,21 @@ static aom_codec_err_t decode_one(aom_codec_alg_priv_t *ctx, if (!ctx->si.is_kf && !is_intra_only) return AOM_CODEC_ERROR; } - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; frame_worker_data->data = *data; frame_worker_data->data_size = data_sz; frame_worker_data->user_priv = user_priv; frame_worker_data->received_frame = 1; - frame_worker_data->pbi->common.large_scale_tile = ctx->tile_mode; + frame_worker_data->pbi->common.tiles.large_scale = ctx->tile_mode; frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row; frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col; frame_worker_data->pbi->ext_tile_debug = ctx->ext_tile_debug; frame_worker_data->pbi->row_mt = ctx->row_mt; frame_worker_data->pbi->ext_refs = ctx->ext_refs; - frame_worker_data->pbi->common.is_annexb = ctx->is_annexb; + frame_worker_data->pbi->is_annexb = ctx->is_annexb; worker->had_error = 0; winterface->execute(worker); @@ -582,12 +541,12 @@ static aom_codec_err_t decoder_inspect(aom_codec_alg_priv_t *ctx, const uint8_t *const data_end = data + data_sz; Av1DecodeReturn *data2 = (Av1DecodeReturn *)user_priv; - if (ctx->frame_workers == NULL) { + if (ctx->frame_worker == NULL) { res = init_decoder(ctx); if (res != AOM_CODEC_OK) return res; } FrameWorkerData *const frame_worker_data = - (FrameWorkerData *)ctx->frame_workers[0].data1; + (FrameWorkerData *)ctx->frame_worker->data1; AV1Decoder *const pbi = frame_worker_data->pbi; AV1_COMMON *const cm = &pbi->common; frame_worker_data->pbi->inspect_cb = ctx->inspect_cb; @@ -595,7 +554,7 @@ static aom_codec_err_t decoder_inspect(aom_codec_alg_priv_t *ctx, res = av1_receive_compressed_data(frame_worker_data->pbi, data_sz, &data); check_resync(ctx, frame_worker_data->pbi); - if (ctx->frame_workers->had_error) + if (ctx->frame_worker->had_error) return update_error_state(ctx, &frame_worker_data->pbi->common.error); // Allow extra zero bytes after the frame end @@ -627,19 +586,16 @@ static aom_codec_err_t decoder_decode(aom_codec_alg_priv_t *ctx, // Release any pending output frames from the previous decoder_decode call. // We need to do this even if the decoder is being flushed or the input // arguments are invalid. - if (ctx->frame_workers) { + if (ctx->frame_worker) { BufferPool *const pool = ctx->buffer_pool; lock_buffer_pool(pool); - for (int i = 0; i < ctx->num_frame_workers; ++i) { - AVxWorker *const worker = &ctx->frame_workers[i]; - FrameWorkerData *const frame_worker_data = - (FrameWorkerData *)worker->data1; - struct AV1Decoder *pbi = frame_worker_data->pbi; - for (size_t j = 0; j < pbi->num_output_frames; j++) { - decrease_ref_count(pbi->output_frames[j], pool); - } - pbi->num_output_frames = 0; + AVxWorker *const worker = ctx->frame_worker; + FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; + struct AV1Decoder *pbi = frame_worker_data->pbi; + for (size_t j = 0; j < pbi->num_output_frames; j++) { + decrease_ref_count(pbi->output_frames[j], pool); } + pbi->num_output_frames = 0; unlock_buffer_pool(pool); for (size_t j = 0; j < ctx->num_grain_image_frame_buffers; j++) { pool->release_fb_cb(pool->cb_priv, &ctx->grain_image_frame_buffers[j]); @@ -661,8 +617,8 @@ static aom_codec_err_t decoder_decode(aom_codec_alg_priv_t *ctx, // Reset flushed when receiving a valid frame. ctx->flushed = 0; - // Initialize the decoder workers on the first frame. - if (ctx->frame_workers == NULL) { + // Initialize the decoder worker on the first frame. + if (ctx->frame_worker == NULL) { res = init_decoder(ctx); if (res != AOM_CODEC_OK) return res; } @@ -761,6 +717,15 @@ static aom_image_t *add_grain_if_needed(aom_codec_alg_priv_t *ctx, return grain_img; } +// Copies and clears the metadata from AV1Decoder. +static void move_decoder_metadata_to_img(AV1Decoder *pbi, aom_image_t *img) { + if (pbi->metadata && img) { + assert(!img->metadata); + img->metadata = pbi->metadata; + pbi->metadata = NULL; + } +} + static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx, aom_codec_iter_t *iter) { aom_image_t *img = NULL; @@ -773,103 +738,100 @@ static aom_image_t *decoder_get_frame(aom_codec_alg_priv_t *ctx, // simply a pointer to an integer index uintptr_t *index = (uintptr_t *)iter; - if (ctx->frame_workers != NULL) { - do { - // NOTE(david.barker): This code does not support multiple worker threads - // yet. We should probably move the iteration over threads into *iter - // instead of using ctx->next_output_worker_id. - const AVxWorkerInterface *const winterface = aom_get_worker_interface(); - AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; - FrameWorkerData *const frame_worker_data = - (FrameWorkerData *)worker->data1; - AV1Decoder *const pbi = frame_worker_data->pbi; - AV1_COMMON *const cm = &pbi->common; - ctx->next_output_worker_id = - (ctx->next_output_worker_id + 1) % ctx->num_frame_workers; - // Wait for the frame from worker thread. - if (winterface->sync(worker)) { - // Check if worker has received any frames. - if (frame_worker_data->received_frame == 1) { - frame_worker_data->received_frame = 0; - check_resync(ctx, frame_worker_data->pbi); - } - YV12_BUFFER_CONFIG *sd; - aom_film_grain_t *grain_params; - if (av1_get_raw_frame(frame_worker_data->pbi, *index, &sd, - &grain_params) == 0) { - RefCntBuffer *const output_frame_buf = pbi->output_frames[*index]; - ctx->last_show_frame = output_frame_buf; - if (ctx->need_resync) return NULL; - yuvconfig2image(&ctx->img, sd, frame_worker_data->user_priv); - - if (!pbi->ext_tile_debug && cm->large_scale_tile) { - *index += 1; // Advance the iterator to point to the next image - - yuvconfig2image(&ctx->img, &pbi->tile_list_outbuf, NULL); - img = &ctx->img; - return img; - } - - const int num_planes = av1_num_planes(cm); - if (pbi->ext_tile_debug && cm->single_tile_decoding && - pbi->dec_tile_row >= 0) { - int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); - const int tile_row = AOMMIN(pbi->dec_tile_row, cm->tile_rows - 1); - const int mi_row = tile_row * tile_height; - const int ssy = ctx->img.y_chroma_shift; - int plane; - ctx->img.planes[0] += mi_row * MI_SIZE * ctx->img.stride[0]; - if (num_planes > 1) { - for (plane = 1; plane < MAX_MB_PLANE; ++plane) { - ctx->img.planes[plane] += - mi_row * (MI_SIZE >> ssy) * ctx->img.stride[plane]; - } - } - ctx->img.d_h = AOMMIN(tile_height, cm->mi_rows - mi_row) * MI_SIZE; - } - - if (pbi->ext_tile_debug && cm->single_tile_decoding && - pbi->dec_tile_col >= 0) { - int tile_width, tile_height; - av1_get_uniform_tile_size(cm, &tile_width, &tile_height); - const int tile_col = AOMMIN(pbi->dec_tile_col, cm->tile_cols - 1); - const int mi_col = tile_col * tile_width; - const int ssx = ctx->img.x_chroma_shift; - const int is_hbd = - (ctx->img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 1 : 0; - int plane; - ctx->img.planes[0] += mi_col * MI_SIZE * (1 + is_hbd); - if (num_planes > 1) { - for (plane = 1; plane < MAX_MB_PLANE; ++plane) { - ctx->img.planes[plane] += - mi_col * (MI_SIZE >> ssx) * (1 + is_hbd); - } - } - ctx->img.d_w = AOMMIN(tile_width, cm->mi_cols - mi_col) * MI_SIZE; - } - - ctx->img.fb_priv = output_frame_buf->raw_frame_buffer.priv; - img = &ctx->img; - img->temporal_id = cm->temporal_layer_id; - img->spatial_id = cm->spatial_layer_id; - if (cm->skip_film_grain) grain_params->apply_grain = 0; - aom_image_t *res = add_grain_if_needed( - ctx, img, &ctx->image_with_grain, grain_params); - if (!res) { - aom_internal_error(&pbi->common.error, AOM_CODEC_CORRUPT_FRAME, - "Grain systhesis failed\n"); - } - *index += 1; // Advance the iterator to point to the next image - return res; - } - } else { - // Decoding failed. Release the worker thread. + if (ctx->frame_worker != NULL) { + const AVxWorkerInterface *const winterface = aom_get_worker_interface(); + AVxWorker *const worker = ctx->frame_worker; + FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; + AV1Decoder *const pbi = frame_worker_data->pbi; + AV1_COMMON *const cm = &pbi->common; + CommonTileParams *const tiles = &cm->tiles; + // Wait for the frame from worker thread. + if (winterface->sync(worker)) { + // Check if worker has received any frames. + if (frame_worker_data->received_frame == 1) { frame_worker_data->received_frame = 0; - ctx->need_resync = 1; - if (ctx->flushed != 1) return NULL; + check_resync(ctx, frame_worker_data->pbi); } - } while (ctx->next_output_worker_id != 0); + YV12_BUFFER_CONFIG *sd; + aom_film_grain_t *grain_params; + if (av1_get_raw_frame(frame_worker_data->pbi, *index, &sd, + &grain_params) == 0) { + RefCntBuffer *const output_frame_buf = pbi->output_frames[*index]; + ctx->last_show_frame = output_frame_buf; + if (ctx->need_resync) return NULL; + aom_img_remove_metadata(&ctx->img); + yuvconfig2image(&ctx->img, sd, frame_worker_data->user_priv); + move_decoder_metadata_to_img(pbi, &ctx->img); + + if (!pbi->ext_tile_debug && tiles->large_scale) { + *index += 1; // Advance the iterator to point to the next image + aom_img_remove_metadata(&ctx->img); + yuvconfig2image(&ctx->img, &pbi->tile_list_outbuf, NULL); + move_decoder_metadata_to_img(pbi, &ctx->img); + img = &ctx->img; + return img; + } + + const int num_planes = av1_num_planes(cm); + if (pbi->ext_tile_debug && tiles->single_tile_decoding && + pbi->dec_tile_row >= 0) { + int tile_width, tile_height; + av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + const int tile_row = AOMMIN(pbi->dec_tile_row, tiles->rows - 1); + const int mi_row = tile_row * tile_height; + const int ssy = ctx->img.y_chroma_shift; + int plane; + ctx->img.planes[0] += mi_row * MI_SIZE * ctx->img.stride[0]; + if (num_planes > 1) { + for (plane = 1; plane < MAX_MB_PLANE; ++plane) { + ctx->img.planes[plane] += + mi_row * (MI_SIZE >> ssy) * ctx->img.stride[plane]; + } + } + ctx->img.d_h = + AOMMIN(tile_height, cm->mi_params.mi_rows - mi_row) * MI_SIZE; + } + + if (pbi->ext_tile_debug && tiles->single_tile_decoding && + pbi->dec_tile_col >= 0) { + int tile_width, tile_height; + av1_get_uniform_tile_size(cm, &tile_width, &tile_height); + const int tile_col = AOMMIN(pbi->dec_tile_col, tiles->cols - 1); + const int mi_col = tile_col * tile_width; + const int ssx = ctx->img.x_chroma_shift; + const int is_hbd = (ctx->img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 1 : 0; + int plane; + ctx->img.planes[0] += mi_col * MI_SIZE * (1 + is_hbd); + if (num_planes > 1) { + for (plane = 1; plane < MAX_MB_PLANE; ++plane) { + ctx->img.planes[plane] += + mi_col * (MI_SIZE >> ssx) * (1 + is_hbd); + } + } + ctx->img.d_w = + AOMMIN(tile_width, cm->mi_params.mi_cols - mi_col) * MI_SIZE; + } + + ctx->img.fb_priv = output_frame_buf->raw_frame_buffer.priv; + img = &ctx->img; + img->temporal_id = cm->temporal_layer_id; + img->spatial_id = cm->spatial_layer_id; + if (pbi->skip_film_grain) grain_params->apply_grain = 0; + aom_image_t *res = + add_grain_if_needed(ctx, img, &ctx->image_with_grain, grain_params); + if (!res) { + aom_internal_error(&pbi->common.error, AOM_CODEC_CORRUPT_FRAME, + "Grain systhesis failed\n"); + } + *index += 1; // Advance the iterator to point to the next image + return res; + } + } else { + // Decoding failed. Release the worker thread. + frame_worker_data->received_frame = 0; + ctx->need_resync = 1; + if (ctx->flushed != 1) return NULL; + } } return NULL; } @@ -879,7 +841,7 @@ static aom_codec_err_t decoder_set_fb_fn( aom_release_frame_buffer_cb_fn_t cb_release, void *cb_priv) { if (cb_get == NULL || cb_release == NULL) { return AOM_CODEC_INVALID_PARAM; - } else if (ctx->frame_workers == NULL) { + } else if (ctx->frame_worker == NULL) { // If the decoder has already been initialized, do not accept changes to // the frame buffer functions. ctx->get_ext_fb_cb = cb_get; @@ -898,7 +860,7 @@ static aom_codec_err_t ctrl_set_reference(aom_codec_alg_priv_t *ctx, if (data) { av1_ref_frame_t *const frame = data; YV12_BUFFER_CONFIG sd; - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; image2yuvconfig(&frame->img, &sd); return av1_set_reference_dec(&frame_worker_data->pbi->common, frame->idx, @@ -913,7 +875,7 @@ static aom_codec_err_t ctrl_copy_reference(aom_codec_alg_priv_t *ctx, const av1_ref_frame_t *const frame = va_arg(args, av1_ref_frame_t *); if (frame) { YV12_BUFFER_CONFIG sd; - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; image2yuvconfig(&frame->img, &sd); return av1_copy_reference_dec(frame_worker_data->pbi, frame->idx, &sd); @@ -927,7 +889,7 @@ static aom_codec_err_t ctrl_get_reference(aom_codec_alg_priv_t *ctx, av1_ref_frame_t *data = va_arg(args, av1_ref_frame_t *); if (data) { YV12_BUFFER_CONFIG *fb; - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; fb = get_ref_frame(&frame_worker_data->pbi->common, data->idx); if (fb == NULL) return AOM_CODEC_ERROR; @@ -943,7 +905,7 @@ static aom_codec_err_t ctrl_get_new_frame_image(aom_codec_alg_priv_t *ctx, aom_image_t *new_img = va_arg(args, aom_image_t *); if (new_img) { YV12_BUFFER_CONFIG new_frame; - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; if (av1_get_frame_to_show(frame_worker_data->pbi, &new_frame) == 0) { @@ -962,7 +924,7 @@ static aom_codec_err_t ctrl_copy_new_frame_image(aom_codec_alg_priv_t *ctx, aom_image_t *img = va_arg(args, aom_image_t *); if (img) { YV12_BUFFER_CONFIG new_frame; - AVxWorker *const worker = ctx->frame_workers; + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; if (av1_get_frame_to_show(frame_worker_data->pbi, &new_frame) == 0) { @@ -978,27 +940,13 @@ static aom_codec_err_t ctrl_copy_new_frame_image(aom_codec_alg_priv_t *ctx, } } -static aom_codec_err_t ctrl_set_postproc(aom_codec_alg_priv_t *ctx, - va_list args) { - (void)ctx; - (void)args; - return AOM_CODEC_INCAPABLE; -} - -static aom_codec_err_t ctrl_set_dbg_options(aom_codec_alg_priv_t *ctx, - va_list args) { - (void)ctx; - (void)args; - return AOM_CODEC_INCAPABLE; -} - static aom_codec_err_t ctrl_get_last_ref_updates(aom_codec_alg_priv_t *ctx, va_list args) { int *const update_info = va_arg(args, int *); if (update_info) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; *update_info = @@ -1016,8 +964,8 @@ static aom_codec_err_t ctrl_get_last_quantizer(aom_codec_alg_priv_t *ctx, va_list args) { int *const arg = va_arg(args, int *); if (arg == NULL) return AOM_CODEC_INVALID_PARAM; - *arg = - ((FrameWorkerData *)ctx->frame_workers[0].data1)->pbi->common.base_qindex; + *arg = ((FrameWorkerData *)ctx->frame_worker->data1) + ->pbi->common.quant_params.base_qindex; return AOM_CODEC_OK; } @@ -1026,8 +974,8 @@ static aom_codec_err_t ctrl_get_frame_corrupted(aom_codec_alg_priv_t *ctx, int *corrupted = va_arg(args, int *); if (corrupted) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; AV1Decoder *const pbi = frame_worker_data->pbi; @@ -1049,8 +997,8 @@ static aom_codec_err_t ctrl_get_frame_size(aom_codec_alg_priv_t *ctx, int *const frame_size = va_arg(args, int *); if (frame_size) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; const AV1_COMMON *const cm = &frame_worker_data->pbi->common; @@ -1070,8 +1018,8 @@ static aom_codec_err_t ctrl_get_frame_header_info(aom_codec_alg_priv_t *ctx, aom_tile_data *const frame_header_info = va_arg(args, aom_tile_data *); if (frame_header_info) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; const AV1Decoder *pbi = frame_worker_data->pbi; @@ -1091,8 +1039,8 @@ static aom_codec_err_t ctrl_get_tile_data(aom_codec_alg_priv_t *ctx, aom_tile_data *const tile_data = va_arg(args, aom_tile_data *); if (tile_data) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; const AV1Decoder *pbi = frame_worker_data->pbi; @@ -1130,8 +1078,8 @@ static aom_codec_err_t ctrl_get_render_size(aom_codec_alg_priv_t *ctx, int *const render_size = va_arg(args, int *); if (render_size) { - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; const AV1_COMMON *const cm = &frame_worker_data->pbi->common; @@ -1149,7 +1097,7 @@ static aom_codec_err_t ctrl_get_render_size(aom_codec_alg_priv_t *ctx, static aom_codec_err_t ctrl_get_bit_depth(aom_codec_alg_priv_t *ctx, va_list args) { unsigned int *const bit_depth = va_arg(args, unsigned int *); - AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; + AVxWorker *const worker = ctx->frame_worker; if (bit_depth) { if (worker) { @@ -1184,7 +1132,7 @@ static aom_img_fmt_t get_img_format(int subsampling_x, int subsampling_y, static aom_codec_err_t ctrl_get_img_format(aom_codec_alg_priv_t *ctx, va_list args) { aom_img_fmt_t *const img_fmt = va_arg(args, aom_img_fmt_t *); - AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; + AVxWorker *const worker = ctx->frame_worker; if (img_fmt) { if (worker) { @@ -1207,7 +1155,7 @@ static aom_codec_err_t ctrl_get_img_format(aom_codec_alg_priv_t *ctx, static aom_codec_err_t ctrl_get_tile_size(aom_codec_alg_priv_t *ctx, va_list args) { unsigned int *const tile_size = va_arg(args, unsigned int *); - AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; + AVxWorker *const worker = ctx->frame_worker; if (tile_size) { if (worker) { @@ -1230,7 +1178,7 @@ static aom_codec_err_t ctrl_get_tile_count(aom_codec_alg_priv_t *ctx, unsigned int *const tile_count = va_arg(args, unsigned int *); if (tile_count) { - AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id]; + AVxWorker *const worker = ctx->frame_worker; if (worker) { FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; @@ -1263,10 +1211,10 @@ static aom_codec_err_t ctrl_set_byte_alignment(aom_codec_alg_priv_t *ctx, return AOM_CODEC_INVALID_PARAM; ctx->byte_alignment = byte_alignment; - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; - frame_worker_data->pbi->common.byte_alignment = byte_alignment; + frame_worker_data->pbi->common.features.byte_alignment = byte_alignment; } return AOM_CODEC_OK; } @@ -1275,10 +1223,10 @@ static aom_codec_err_t ctrl_set_skip_loop_filter(aom_codec_alg_priv_t *ctx, va_list args) { ctx->skip_loop_filter = va_arg(args, int); - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; - frame_worker_data->pbi->common.skip_loop_filter = ctx->skip_loop_filter; + frame_worker_data->pbi->skip_loop_filter = ctx->skip_loop_filter; } return AOM_CODEC_OK; @@ -1288,10 +1236,10 @@ static aom_codec_err_t ctrl_set_skip_film_grain(aom_codec_alg_priv_t *ctx, va_list args) { ctx->skip_film_grain = va_arg(args, int); - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; - frame_worker_data->pbi->common.skip_film_grain = ctx->skip_film_grain; + frame_worker_data->pbi->skip_film_grain = ctx->skip_film_grain; } return AOM_CODEC_OK; @@ -1304,8 +1252,8 @@ static aom_codec_err_t ctrl_get_accounting(aom_codec_alg_priv_t *ctx, (void)args; return AOM_CODEC_INCAPABLE; #else - if (ctx->frame_workers) { - AVxWorker *const worker = ctx->frame_workers; + if (ctx->frame_worker) { + AVxWorker *const worker = ctx->frame_worker; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; AV1Decoder *pbi = frame_worker_data->pbi; Accounting **acct = va_arg(args, Accounting **); @@ -1382,11 +1330,6 @@ static aom_codec_ctrl_fn_map_t decoder_ctrl_maps[] = { // Setters { AV1_SET_REFERENCE, ctrl_set_reference }, - { AOM_SET_POSTPROC, ctrl_set_postproc }, - { AOM_SET_DBG_COLOR_REF_FRAME, ctrl_set_dbg_options }, - { AOM_SET_DBG_COLOR_MB_MODES, ctrl_set_dbg_options }, - { AOM_SET_DBG_COLOR_B_MODES, ctrl_set_dbg_options }, - { AOM_SET_DBG_DISPLAY_MV, ctrl_set_dbg_options }, { AV1_INVERT_TILE_DECODE_ORDER, ctrl_set_invert_tile_order }, { AV1_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment }, { AV1_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter }, @@ -1444,12 +1387,11 @@ CODEC_INTERFACE(aom_codec_av1_dx) = { { // NOLINT 0, - NULL, // aom_codec_enc_cfg_map_t + NULL, // aom_codec_enc_cfg_t NULL, // aom_codec_encode_fn_t NULL, // aom_codec_get_cx_data_fn_t NULL, // aom_codec_enc_config_set_fn_t NULL, // aom_codec_get_global_headers_fn_t - NULL, // aom_codec_get_preview_frame_fn_t - NULL // aom_codec_enc_mr_get_mem_loc_fn_t + NULL // aom_codec_get_preview_frame_fn_t } }; diff --git a/media/libaom/src/av1/av1_iface_common.h b/media/libaom/src/av1/av1_iface_common.h index f87fd1b3db..9b5ffcba45 100644 --- a/media/libaom/src/av1/av1_iface_common.h +++ b/media/libaom/src/av1/av1_iface_common.h @@ -11,6 +11,8 @@ #ifndef AOM_AV1_AV1_IFACE_COMMON_H_ #define AOM_AV1_AV1_IFACE_COMMON_H_ +#include + #include "aom_ports/mem.h" #include "aom_scale/yv12config.h" @@ -74,7 +76,8 @@ static void yuvconfig2image(aom_image_t *img, const YV12_BUFFER_CONFIG *yv12, img->img_data_owner = 0; img->self_allocd = 0; img->sz = yv12->frame_size; - img->metadata = yv12->metadata; + assert(!yv12->metadata); + img->metadata = NULL; } static aom_codec_err_t image2yuvconfig(const aom_image_t *img, diff --git a/media/libaom/src/av1/common/alloccommon.c b/media/libaom/src/av1/common/alloccommon.c index c183e382c5..badee3df92 100644 --- a/media/libaom/src/av1/common/alloccommon.c +++ b/media/libaom/src/av1/common/alloccommon.c @@ -15,10 +15,10 @@ #include "aom_mem/aom_mem.h" #include "av1/common/alloccommon.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/entropymode.h" #include "av1/common/entropymv.h" -#include "av1/common/onyxc_int.h" int av1_get_MBs(int width, int height) { const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); @@ -73,7 +73,7 @@ void av1_alloc_restoration_buffers(AV1_COMMON *cm) { // able to quickly answer the question "Where is the 'th stripe for tile // row ?" To make that efficient, we generate the rst_last_stripe array. int num_stripes = 0; - for (int i = 0; i < cm->tile_rows; ++i) { + for (int i = 0; i < cm->tiles.rows; ++i) { TileInfo tile_info; av1_tile_set_row(&tile_info, cm, i); const int mi_h = tile_info.mi_row_end - tile_info.mi_row_start; @@ -132,101 +132,131 @@ void av1_free_restoration_buffers(AV1_COMMON *cm) { aom_free_frame_buffer(&cm->rst_frame); } -void av1_free_above_context_buffers(AV1_COMMON *cm, - int num_free_above_contexts) { +void av1_free_above_context_buffers(CommonContexts *above_contexts) { int i; - const int num_planes = cm->num_allocated_above_context_planes; + const int num_planes = above_contexts->num_planes; - for (int tile_row = 0; tile_row < num_free_above_contexts; tile_row++) { + for (int tile_row = 0; tile_row < above_contexts->num_tile_rows; tile_row++) { for (i = 0; i < num_planes; i++) { - aom_free(cm->above_context[i][tile_row]); - cm->above_context[i][tile_row] = NULL; + aom_free(above_contexts->entropy[i][tile_row]); + above_contexts->entropy[i][tile_row] = NULL; } - aom_free(cm->above_seg_context[tile_row]); - cm->above_seg_context[tile_row] = NULL; + aom_free(above_contexts->partition[tile_row]); + above_contexts->partition[tile_row] = NULL; - aom_free(cm->above_txfm_context[tile_row]); - cm->above_txfm_context[tile_row] = NULL; + aom_free(above_contexts->txfm[tile_row]); + above_contexts->txfm[tile_row] = NULL; } for (i = 0; i < num_planes; i++) { - aom_free(cm->above_context[i]); - cm->above_context[i] = NULL; + aom_free(above_contexts->entropy[i]); + above_contexts->entropy[i] = NULL; } - aom_free(cm->above_seg_context); - cm->above_seg_context = NULL; + aom_free(above_contexts->partition); + above_contexts->partition = NULL; - aom_free(cm->above_txfm_context); - cm->above_txfm_context = NULL; + aom_free(above_contexts->txfm); + above_contexts->txfm = NULL; - cm->num_allocated_above_contexts = 0; - cm->num_allocated_above_context_mi_col = 0; - cm->num_allocated_above_context_planes = 0; + above_contexts->num_tile_rows = 0; + above_contexts->num_mi_cols = 0; + above_contexts->num_planes = 0; } void av1_free_context_buffers(AV1_COMMON *cm) { - cm->free_mi(cm); + cm->mi_params.free_mi(&cm->mi_params); - av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts); + av1_free_above_context_buffers(&cm->above_contexts); #if CONFIG_LPF_MASK av1_free_loop_filter_mask(cm); #endif } -int av1_alloc_above_context_buffers(AV1_COMMON *cm, - int num_alloc_above_contexts) { - const int num_planes = av1_num_planes(cm); - int plane_idx; +int av1_alloc_above_context_buffers(CommonContexts *above_contexts, + int num_tile_rows, int num_mi_cols, + int num_planes) { const int aligned_mi_cols = - ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2); + ALIGN_POWER_OF_TWO(num_mi_cols, MAX_MIB_SIZE_LOG2); // Allocate above context buffers - cm->num_allocated_above_contexts = num_alloc_above_contexts; - cm->num_allocated_above_context_mi_col = aligned_mi_cols; - cm->num_allocated_above_context_planes = num_planes; - for (plane_idx = 0; plane_idx < num_planes; plane_idx++) { - cm->above_context[plane_idx] = (ENTROPY_CONTEXT **)aom_calloc( - num_alloc_above_contexts, sizeof(cm->above_context[0])); - if (!cm->above_context[plane_idx]) return 1; + above_contexts->num_tile_rows = num_tile_rows; + above_contexts->num_mi_cols = aligned_mi_cols; + above_contexts->num_planes = num_planes; + for (int plane_idx = 0; plane_idx < num_planes; plane_idx++) { + above_contexts->entropy[plane_idx] = (ENTROPY_CONTEXT **)aom_calloc( + num_tile_rows, sizeof(above_contexts->entropy[0])); + if (!above_contexts->entropy[plane_idx]) return 1; } - cm->above_seg_context = (PARTITION_CONTEXT **)aom_calloc( - num_alloc_above_contexts, sizeof(cm->above_seg_context)); - if (!cm->above_seg_context) return 1; + above_contexts->partition = (PARTITION_CONTEXT **)aom_calloc( + num_tile_rows, sizeof(above_contexts->partition)); + if (!above_contexts->partition) return 1; - cm->above_txfm_context = (TXFM_CONTEXT **)aom_calloc( - num_alloc_above_contexts, sizeof(cm->above_txfm_context)); - if (!cm->above_txfm_context) return 1; + above_contexts->txfm = + (TXFM_CONTEXT **)aom_calloc(num_tile_rows, sizeof(above_contexts->txfm)); + if (!above_contexts->txfm) return 1; - for (int tile_row = 0; tile_row < num_alloc_above_contexts; tile_row++) { - for (plane_idx = 0; plane_idx < num_planes; plane_idx++) { - cm->above_context[plane_idx][tile_row] = (ENTROPY_CONTEXT *)aom_calloc( - aligned_mi_cols, sizeof(*cm->above_context[0][tile_row])); - if (!cm->above_context[plane_idx][tile_row]) return 1; + for (int tile_row = 0; tile_row < num_tile_rows; tile_row++) { + for (int plane_idx = 0; plane_idx < num_planes; plane_idx++) { + above_contexts->entropy[plane_idx][tile_row] = + (ENTROPY_CONTEXT *)aom_calloc( + aligned_mi_cols, sizeof(*above_contexts->entropy[0][tile_row])); + if (!above_contexts->entropy[plane_idx][tile_row]) return 1; } - cm->above_seg_context[tile_row] = (PARTITION_CONTEXT *)aom_calloc( - aligned_mi_cols, sizeof(*cm->above_seg_context[tile_row])); - if (!cm->above_seg_context[tile_row]) return 1; + above_contexts->partition[tile_row] = (PARTITION_CONTEXT *)aom_calloc( + aligned_mi_cols, sizeof(*above_contexts->partition[tile_row])); + if (!above_contexts->partition[tile_row]) return 1; - cm->above_txfm_context[tile_row] = (TXFM_CONTEXT *)aom_calloc( - aligned_mi_cols, sizeof(*cm->above_txfm_context[tile_row])); - if (!cm->above_txfm_context[tile_row]) return 1; + above_contexts->txfm[tile_row] = (TXFM_CONTEXT *)aom_calloc( + aligned_mi_cols, sizeof(*above_contexts->txfm[tile_row])); + if (!above_contexts->txfm[tile_row]) return 1; + } + + return 0; +} + +// Allocate the dynamically allocated arrays in 'mi_params' assuming +// 'mi_params->set_mb_mi()' was already called earlier to initialize the rest of +// the struct members. +static int alloc_mi(CommonModeInfoParams *mi_params) { + const int aligned_mi_rows = calc_mi_size(mi_params->mi_rows); + const int mi_grid_size = mi_params->mi_stride * aligned_mi_rows; + const int alloc_size_1d = mi_size_wide[mi_params->mi_alloc_bsize]; + const int alloc_mi_size = + mi_params->mi_alloc_stride * (aligned_mi_rows / alloc_size_1d); + + if (mi_params->mi_alloc_size < alloc_mi_size || + mi_params->mi_grid_size < mi_grid_size) { + mi_params->free_mi(mi_params); + + mi_params->mi_alloc = + aom_calloc(alloc_mi_size, sizeof(*mi_params->mi_alloc)); + if (!mi_params->mi_alloc) return 1; + mi_params->mi_alloc_size = alloc_mi_size; + + mi_params->mi_grid_base = (MB_MODE_INFO **)aom_calloc( + mi_grid_size, sizeof(*mi_params->mi_grid_base)); + if (!mi_params->mi_grid_base) return 1; + mi_params->mi_grid_size = mi_grid_size; + + mi_params->tx_type_map = + aom_calloc(mi_grid_size, sizeof(*mi_params->tx_type_map)); + if (!mi_params->tx_type_map) return 1; } return 0; } int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height) { - cm->set_mb_mi(cm, width, height); - - if (cm->alloc_mi(cm)) goto fail; - + CommonModeInfoParams *const mi_params = &cm->mi_params; + mi_params->set_mb_mi(mi_params, width, height); + if (alloc_mi(mi_params)) goto fail; return 0; fail: // clear the mi_* values to force a realloc on resync - cm->set_mb_mi(cm, 0, 0); + mi_params->set_mb_mi(mi_params, 0, 0); av1_free_context_buffers(cm); return 1; } @@ -240,7 +270,9 @@ void av1_remove_common(AV1_COMMON *cm) { cm->default_frame_context = NULL; } -void av1_init_context_buffers(AV1_COMMON *cm) { cm->setup_mi(cm); } +void av1_init_mi_buffers(CommonModeInfoParams *mi_params) { + mi_params->setup_mi(mi_params); +} #if CONFIG_LPF_MASK int av1_alloc_loop_filter_mask(AV1_COMMON *cm) { @@ -251,9 +283,11 @@ int av1_alloc_loop_filter_mask(AV1_COMMON *cm) { // 64x64 (128x128 for ext_partitions) region. The stride // and rows are rounded up / truncated to a multiple of 16 // (32 for ext_partition). - cm->lf.lfm_stride = (cm->mi_cols + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2; - cm->lf.lfm_num = ((cm->mi_rows + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2) * - cm->lf.lfm_stride; + cm->lf.lfm_stride = + (cm->mi_params.mi_cols + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2; + cm->lf.lfm_num = + ((cm->mi_params.mi_rows + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2) * + cm->lf.lfm_stride; cm->lf.lfm = (LoopFilterMask *)aom_calloc(cm->lf.lfm_num, sizeof(*cm->lf.lfm)); if (!cm->lf.lfm) return 1; diff --git a/media/libaom/src/av1/common/alloccommon.h b/media/libaom/src/av1/common/alloccommon.h index ab226fb74c..fe8e0c5301 100644 --- a/media/libaom/src/av1/common/alloccommon.h +++ b/media/libaom/src/av1/common/alloccommon.h @@ -22,15 +22,17 @@ extern "C" { struct AV1Common; struct BufferPool; +struct CommonContexts; +struct CommonModeInfoParams; void av1_remove_common(struct AV1Common *cm); -int av1_alloc_above_context_buffers(struct AV1Common *cm, - int num_alloc_above_contexts); -void av1_free_above_context_buffers(struct AV1Common *cm, - int num_free_above_contexts); +int av1_alloc_above_context_buffers(struct CommonContexts *above_contexts, + int num_tile_rows, int num_mi_cols, + int num_planes); +void av1_free_above_context_buffers(struct CommonContexts *above_contexts); int av1_alloc_context_buffers(struct AV1Common *cm, int width, int height); -void av1_init_context_buffers(struct AV1Common *cm); +void av1_init_mi_buffers(struct CommonModeInfoParams *mi_params); void av1_free_context_buffers(struct AV1Common *cm); void av1_free_ref_frame_buffers(struct BufferPool *pool); diff --git a/media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c b/media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c index 29928d9501..2f3567aea3 100644 --- a/media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c +++ b/media/libaom/src/av1/common/arm/av1_inv_txfm_neon.c @@ -48,11 +48,11 @@ static const ITX_TYPE_1D hitx_1d_tab[TX_TYPES] = { // 1D functions static const transform_1d_neon lowbd_txfm_all_1d_arr[TX_SIZES][ITX_TYPES_1D] = { - { av1_idct4_new, av1_iadst4_new, av1_iidentity4_c }, - { av1_idct8_new, av1_iadst8_new, av1_iidentity8_c }, - { av1_idct16_new, av1_iadst16_new, av1_iidentity16_c }, - { av1_idct32_new, NULL, NULL }, - { av1_idct64_new, NULL, NULL }, + { av1_idct4, av1_iadst4, av1_iidentity4_c }, + { av1_idct8, av1_iadst8, av1_iidentity8_c }, + { av1_idct16, av1_iadst16, av1_iidentity16_c }, + { av1_idct32, NULL, NULL }, + { av1_idct64, NULL, NULL }, }; static INLINE void lowbd_add_flip_buffer_8xn_neon(int16x8_t *in, @@ -258,8 +258,8 @@ static INLINE int16x4_t set_s16x4_neon(const int16_t c0, const int16_t c1, return val; } -static INLINE void iadst8_new_neon(int16x8_t *const in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void iadst8_neon(int16x8_t *const in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); @@ -332,8 +332,8 @@ static INLINE void iadst8_new_neon(int16x8_t *const in, int16x8_t *out, out[7] = vqnegq_s16(x[1]); } -static INLINE void iadst8_low1_new_neon(int16x8_t *const in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void iadst8_low1_neon(int16x8_t *const in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); const int16x4_t c2 = set_s16x4_neon((int16_t)cospi[32], (int16_t)cospi[32], @@ -385,8 +385,8 @@ static INLINE void iadst8_low1_new_neon(int16x8_t *const in, int16x8_t *out, out[7] = vqnegq_s16(x[1]); } -static INLINE void idct8_new_neon(int16x8_t *in, int16x8_t *out, int8_t cos_bit, - int bit) { +static INLINE void idct8_neon(int16x8_t *in, int16x8_t *out, int8_t cos_bit, + int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[8], step2[8]; @@ -425,8 +425,8 @@ static INLINE void idct8_new_neon(int16x8_t *in, int16x8_t *out, int8_t cos_bit, out[7] = vqsubq_s16(step1[0], step2[7]); } -static INLINE void idct8_low1_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct8_low1_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1; @@ -518,8 +518,8 @@ static INLINE void round_shift_for_rect(int16x8_t *input, int16x8_t *output, } } -static INLINE void idct16_low1_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct16_low1_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1; @@ -552,8 +552,8 @@ static INLINE void idct16_low1_new_neon(int16x8_t *in, int16x8_t *out, out[15] = step1; } -static INLINE void idct16_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct16_neon(int16x8_t *in, int16x8_t *out, int8_t cos_bit, + int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[16], step2[16]; @@ -675,8 +675,8 @@ static INLINE void idct16_new_neon(int16x8_t *in, int16x8_t *out, out[15] = vqsubq_s16(step2[0], step2[15]); } -static INLINE void idct16_low8_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct16_low8_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[16], step2[16]; @@ -786,8 +786,8 @@ static INLINE void idct16_low8_new_neon(int16x8_t *in, int16x8_t *out, out[15] = vqsubq_s16(step2[0], step2[15]); } -static INLINE void iadst16_new_neon(int16x8_t *const in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void iadst16_neon(int16x8_t *const in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); @@ -944,8 +944,8 @@ static INLINE void iadst16_new_neon(int16x8_t *const in, int16x8_t *out, out[15] = vqnegq_s16(x[1]); } -static INLINE void iadst16_low1_new_neon(int16x8_t *const in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void iadst16_low1_neon(int16x8_t *const in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); const int16x4_t c0 = set_s16x4_neon((int16_t)cospi[8], (int16_t)cospi[56], @@ -1036,8 +1036,8 @@ static INLINE void iadst16_low1_new_neon(int16x8_t *const in, int16x8_t *out, out[15] = vqnegq_s16(x[1]); } -static INLINE void iadst16_low8_new_neon(int16x8_t *const in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void iadst16_low8_neon(int16x8_t *const in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); @@ -1179,8 +1179,8 @@ static INLINE void iadst16_low8_new_neon(int16x8_t *const in, int16x8_t *out, out[15] = vqnegq_s16(x[1]); } -static INLINE void idct32_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct32_neon(int16x8_t *in, int16x8_t *out, int8_t cos_bit, + int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[32], step2[32]; @@ -1464,8 +1464,8 @@ static INLINE void idct32_new_neon(int16x8_t *in, int16x8_t *out, out[31] = vqsubq_s16(step2[0], step2[31]); } -static INLINE void idct32_low1_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct32_low1_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1; @@ -1521,8 +1521,8 @@ static INLINE void idct32_low1_new_neon(int16x8_t *in, int16x8_t *out, out[31] = step1; } -static INLINE void idct32_low8_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct32_low8_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[32], step2[32]; @@ -1768,8 +1768,8 @@ static INLINE void idct32_low8_new_neon(int16x8_t *in, int16x8_t *out, out[31] = vqsubq_s16(step2[0], step2[31]); } -static INLINE void idct32_low16_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct32_low16_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1[32], step2[32]; @@ -2165,8 +2165,8 @@ static INLINE void idct64_stage10_neon(int16x8_t *step1, int16x8_t *step2, step2[63] = step1[63]; } -static INLINE void idct64_low32_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct64_low32_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step2[64], step1[64]; @@ -2646,8 +2646,8 @@ static INLINE void idct64_low32_new_neon(int16x8_t *in, int16x8_t *out, out[63] = vqsubq_s16(step2[0], step2[63]); } -static INLINE void idct64_low1_new_neon(int16x8_t *input, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct64_low1_neon(int16x8_t *input, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step1; @@ -2736,8 +2736,8 @@ static INLINE void idct64_low1_new_neon(int16x8_t *input, int16x8_t *out, out[63] = step1; } -static INLINE void idct64_low8_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct64_low8_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step2[64], step1[64]; @@ -3114,8 +3114,8 @@ static INLINE void idct64_low8_new_neon(int16x8_t *in, int16x8_t *out, out[63] = vqsubq_s16(step2[0], step2[63]); } -static INLINE void idct64_low16_new_neon(int16x8_t *in, int16x8_t *out, - int8_t cos_bit, int bit) { +static INLINE void idct64_low16_neon(int16x8_t *in, int16x8_t *out, + int8_t cos_bit, int bit) { (void)bit; const int32_t *cospi = cospi_arr(cos_bit); int16x8_t step2[64], step1[64]; @@ -3574,21 +3574,19 @@ static const transform_neon { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL }, }, - { { idct8_low1_new_neon, idct8_new_neon, NULL, NULL }, - { iadst8_low1_new_neon, iadst8_new_neon, NULL, NULL }, + { { idct8_low1_neon, idct8_neon, NULL, NULL }, + { iadst8_low1_neon, iadst8_neon, NULL, NULL }, { NULL, NULL, NULL, NULL } }, { - { idct16_low1_new_neon, idct16_low8_new_neon, idct16_new_neon, NULL }, - { iadst16_low1_new_neon, iadst16_low8_new_neon, iadst16_new_neon, - NULL }, + { idct16_low1_neon, idct16_low8_neon, idct16_neon, NULL }, + { iadst16_low1_neon, iadst16_low8_neon, iadst16_neon, NULL }, { NULL, NULL, NULL, NULL }, }, - { { idct32_low1_new_neon, idct32_low8_new_neon, idct32_low16_new_neon, - idct32_new_neon }, + { { idct32_low1_neon, idct32_low8_neon, idct32_low16_neon, idct32_neon }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } }, - { { idct64_low1_new_neon, idct64_low8_new_neon, idct64_low16_new_neon, - idct64_low32_new_neon }, + { { idct64_low1_neon, idct64_low8_neon, idct64_low16_neon, + idct64_low32_neon }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } } }; diff --git a/media/libaom/src/av1/common/arm/convolve_neon.c b/media/libaom/src/av1/common/arm/convolve_neon.c index 934297b99e..51c96961cf 100644 --- a/media/libaom/src/av1/common/arm/convolve_neon.c +++ b/media/libaom/src/av1/common/arm/convolve_neon.c @@ -844,6 +844,98 @@ void av1_convolve_y_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, } } +// Horizontal filtering for convolve_2d_sr for width multiple of 8 +// Processes one row at a time +static INLINE void horiz_filter_w8_single_row( + const uint8_t *src_ptr, int src_stride, int16_t *dst_ptr, + const int dst_stride, int width, int height, const int16_t *x_filter, + const int16x8_t horiz_const, const int16x8_t shift_round_0) { + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7; + do { + uint8x8_t t0 = vld1_u8(src_ptr); + s0 = vreinterpretq_s16_u16(vmovl_u8(t0)); // a0 a1 a2 a3 a4 a5 a6 a7 + + int width_tmp = width; + const uint8_t *s = src_ptr + 8; + int16_t *dst_tmp = dst_ptr; + + __builtin_prefetch(dst_ptr); + + do { + t0 = vld1_u8(s); // a8 a9 a10 a11 a12 a13 a14 a15 + s7 = vreinterpretq_s16_u16(vmovl_u8(t0)); + int16x8_t sum = s0; + s0 = s7; + + s1 = vextq_s16(sum, s7, 1); // a1 a2 a3 a4 a5 a6 a7 a8 + s2 = vextq_s16(sum, s7, 2); // a2 a3 a4 a5 a6 a7 a8 a9 + s3 = vextq_s16(sum, s7, 3); // a3 a4 a5 a6 a7 a8 a9 a10 + s4 = vextq_s16(sum, s7, 4); // a4 a5 a6 a7 a8 a9 a10 a11 + s5 = vextq_s16(sum, s7, 5); // a5 a6 a7 a8 a9 a10 a11 a12 + s6 = vextq_s16(sum, s7, 6); // a6 a7 a8 a9 a10 a11 a12 a13 + s7 = vextq_s16(sum, s7, 7); // a7 a8 a9 a10 a11 a12 a13 a14 + + int16x8_t res0 = convolve8_8x8_s16(sum, s1, s2, s3, s4, s5, s6, s7, + x_filter, horiz_const, shift_round_0); + + vst1q_s16(dst_tmp, res0); + + s += 8; + dst_tmp += 8; + width_tmp -= 8; + } while (width_tmp > 0); + src_ptr += src_stride; + dst_ptr += dst_stride; + height--; + } while (height > 0); +} + +// Horizontal filtering for convolve_2d_sr for width <= 4 +// Processes one row at a time +static INLINE void horiz_filter_w4_single_row( + const uint8_t *src_ptr, int src_stride, int16_t *dst_ptr, + const int dst_stride, int width, int height, const int16_t *x_filter, + const int16x4_t horiz_const, const int16x4_t shift_round_0) { + int16x4_t s0, s1, s2, s3, s4, s5, s6, s7; + do { + const uint8_t *s = src_ptr; + + __builtin_prefetch(s); + + uint8x8_t t0 = vld1_u8(s); // a0 a1 a2 a3 a4 a5 a6 a7 + int16x8_t tt0 = vreinterpretq_s16_u16(vmovl_u8(t0)); + s0 = vget_low_s16(tt0); + s4 = vget_high_s16(tt0); + + __builtin_prefetch(dst_ptr); + s += 8; + + t0 = vld1_u8(s); // a8 a9 a10 a11 a12 a13 a14 a15 + s7 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); + + s1 = vext_s16(s0, s4, 1); // a1 a2 a3 a4 + s2 = vext_s16(s0, s4, 2); // a2 a3 a4 a5 + s3 = vext_s16(s0, s4, 3); // a3 a4 a5 a6 + s5 = vext_s16(s4, s7, 1); // a5 a6 a7 a8 + s6 = vext_s16(s4, s7, 2); // a6 a7 a8 a9 + s7 = vext_s16(s4, s7, 3); // a7 a8 a9 a10 + + int16x4_t d0 = convolve8_4x4_s16(s0, s1, s2, s3, s4, s5, s6, s7, x_filter, + horiz_const, shift_round_0); + + if (width == 4) { + vst1_s16(dst_ptr, d0); + dst_ptr += dst_stride; + } else if (width == 2) { + vst1_lane_u32((uint32_t *)dst_ptr, vreinterpret_u32_s16(d0), 0); + dst_ptr += dst_stride; + } + + src_ptr += src_stride; + height--; + } while (height > 0); +} + void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, @@ -852,9 +944,10 @@ void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, ConvolveParams *conv_params) { int im_dst_stride; int width, height; - uint8x8_t t0; #if defined(__aarch64__) + uint8x8_t t0; uint8x8_t t1, t2, t3, t4, t5, t6, t7; + const uint8_t *s; #endif DECLARE_ALIGNED(16, int16_t, @@ -867,7 +960,7 @@ void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, const int horiz_offset = filter_params_x->taps / 2 - 1; const uint8_t *src_ptr = src - vert_offset * src_stride - horiz_offset; - const uint8_t *s; + int16_t *dst_ptr; dst_ptr = im_block; @@ -893,18 +986,14 @@ void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, assert(conv_params->round_0 > 0); if (w <= 4) { - int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, d0; -#if defined(__aarch64__) - int16x4_t s8, s9, s10, d1, d2, d3; -#endif - const int16x4_t horiz_const = vdup_n_s16((1 << (bd + FILTER_BITS - 2))); const int16x4_t shift_round_0 = vdup_n_s16(-(conv_params->round_0 - 1)); - do { - s = src_ptr; - #if defined(__aarch64__) + int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, d0, d1, d2, d3; + do { + assert(height >= 4); + s = src_ptr; __builtin_prefetch(s + 0 * src_stride); __builtin_prefetch(s + 1 * src_stride); __builtin_prefetch(s + 2 * src_stride); @@ -963,57 +1052,30 @@ void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, src_ptr += 4 * src_stride; dst_ptr += 4 * im_dst_stride; height -= 4; + } while (height >= 4); + + if (height) { + assert(height < 4); + horiz_filter_w4_single_row(src_ptr, src_stride, dst_ptr, im_dst_stride, w, + height, x_filter_tmp, horiz_const, + shift_round_0); + } #else - int16x8_t tt0; - - __builtin_prefetch(s); - - t0 = vld1_u8(s); // a0 a1 a2 a3 a4 a5 a6 a7 - tt0 = vreinterpretq_s16_u16(vmovl_u8(t0)); - s0 = vget_low_s16(tt0); - s4 = vget_high_s16(tt0); - - __builtin_prefetch(dst_ptr); - s += 8; - - t0 = vld1_u8(s); // a8 a9 a10 a11 a12 a13 a14 a15 - s7 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); - - s1 = vext_s16(s0, s4, 1); // a1 a2 a3 a4 - s2 = vext_s16(s0, s4, 2); // a2 a3 a4 a5 - s3 = vext_s16(s0, s4, 3); // a3 a4 a5 a6 - s5 = vext_s16(s4, s7, 1); // a5 a6 a7 a8 - s6 = vext_s16(s4, s7, 2); // a6 a7 a8 a9 - s7 = vext_s16(s4, s7, 3); // a7 a8 a9 a10 - - d0 = convolve8_4x4_s16(s0, s1, s2, s3, s4, s5, s6, s7, x_filter_tmp, - horiz_const, shift_round_0); - - if (w == 4) { - vst1_s16(dst_ptr, d0); - dst_ptr += im_dst_stride; - } else if (w == 2) { - vst1_lane_u32((uint32_t *)dst_ptr, vreinterpret_u32_s16(d0), 0); - dst_ptr += im_dst_stride; - } - - src_ptr += src_stride; - height -= 1; + horiz_filter_w4_single_row(src_ptr, src_stride, dst_ptr, im_dst_stride, w, + height, x_filter_tmp, horiz_const, + shift_round_0); #endif - } while (height > 0); + } else { - int16_t *d_tmp; - int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, res0; -#if defined(__aarch64__) - int16x8_t s8, s9, s10, res1, res2, res3, res4, res5, res6, res7; - int16x8_t s11, s12, s13, s14; -#endif - const int16x8_t horiz_const = vdupq_n_s16((1 << (bd + FILTER_BITS - 2))); const int16x8_t shift_round_0 = vdupq_n_s16(-(conv_params->round_0 - 1)); #if defined(__aarch64__) + int16_t *d_tmp; + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14; + int16x8_t res0, res1, res2, res3, res4, res5, res6, res7; do { + assert(height >= 8); __builtin_prefetch(src_ptr + 0 * src_stride); __builtin_prefetch(src_ptr + 1 * src_stride); __builtin_prefetch(src_ptr + 2 * src_stride); @@ -1099,45 +1161,121 @@ void av1_convolve_2d_sr_neon(const uint8_t *src, int src_stride, uint8_t *dst, src_ptr += 8 * src_stride; dst_ptr += 8 * im_dst_stride; height -= 8; - } while (height > 0); -#else - do { - t0 = vld1_u8(src_ptr); - s0 = vreinterpretq_s16_u16(vmovl_u8(t0)); // a0 a1 a2 a3 a4 a5 a6 a7 + } while (height >= 8); - width = w; - s = src_ptr + 8; + if (height >= 4) { + assert(height < 8); + int16x4_t reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8, reg9, + reg10, reg11, reg12, reg13, reg14; + int16x4_t d0, d1, d2, d3, d4, d5, d6, d7; + int16x8_t out0, out1, out2, out3; + + __builtin_prefetch(src_ptr + 0 * src_stride); + __builtin_prefetch(src_ptr + 1 * src_stride); + __builtin_prefetch(src_ptr + 2 * src_stride); + __builtin_prefetch(src_ptr + 3 * src_stride); + + load_u8_8x4(src_ptr, src_stride, &t0, &t1, &t2, &t3); + transpose_u8_8x4(&t0, &t1, &t2, &t3); + + reg0 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); + reg1 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t1))); + reg2 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t2))); + reg3 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t3))); + reg4 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); + reg5 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t1))); + reg6 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t2))); + + __builtin_prefetch(dst_ptr + 0 * dst_stride); + __builtin_prefetch(dst_ptr + 1 * dst_stride); + __builtin_prefetch(dst_ptr + 2 * dst_stride); + __builtin_prefetch(dst_ptr + 3 * dst_stride); + + s = src_ptr + 7; d_tmp = dst_ptr; - - __builtin_prefetch(dst_ptr); + width = w; do { - t0 = vld1_u8(s); // a8 a9 a10 a11 a12 a13 a14 a15 - s7 = vreinterpretq_s16_u16(vmovl_u8(t0)); - int16x8_t sum = s0; - s0 = s7; + load_u8_8x4(s, src_stride, &t0, &t1, &t2, &t3); + transpose_u8_8x4(&t0, &t1, &t2, &t3); - s1 = vextq_s16(sum, s7, 1); // a1 a2 a3 a4 a5 a6 a7 a8 - s2 = vextq_s16(sum, s7, 2); // a2 a3 a4 a5 a6 a7 a8 a9 - s3 = vextq_s16(sum, s7, 3); // a3 a4 a5 a6 a7 a8 a9 a10 - s4 = vextq_s16(sum, s7, 4); // a4 a5 a6 a7 a8 a9 a10 a11 - s5 = vextq_s16(sum, s7, 5); // a5 a6 a7 a8 a9 a10 a11 a12 - s6 = vextq_s16(sum, s7, 6); // a6 a7 a8 a9 a10 a11 a12 a13 - s7 = vextq_s16(sum, s7, 7); // a7 a8 a9 a10 a11 a12 a13 a14 + reg7 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); + reg8 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t1))); + reg9 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t2))); + reg10 = vget_low_s16(vreinterpretq_s16_u16(vmovl_u8(t3))); + reg11 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t0))); + reg12 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t1))); + reg13 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t2))); + reg14 = vget_high_s16(vreinterpretq_s16_u16(vmovl_u8(t3))); - res0 = convolve8_8x8_s16(sum, s1, s2, s3, s4, s5, s6, s7, x_filter_tmp, - horiz_const, shift_round_0); + d0 = convolve8_4x4(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, + x_filter_tmp); - vst1q_s16(d_tmp, res0); + d1 = convolve8_4x4(reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8, + x_filter_tmp); + d2 = convolve8_4x4(reg2, reg3, reg4, reg5, reg6, reg7, reg8, reg9, + x_filter_tmp); + + d3 = convolve8_4x4(reg3, reg4, reg5, reg6, reg7, reg8, reg9, reg10, + x_filter_tmp); + + d4 = convolve8_4x4(reg4, reg5, reg6, reg7, reg8, reg9, reg10, reg11, + x_filter_tmp); + + d5 = convolve8_4x4(reg5, reg6, reg7, reg8, reg9, reg10, reg11, reg12, + x_filter_tmp); + + d6 = convolve8_4x4(reg6, reg7, reg8, reg9, reg10, reg11, reg12, reg13, + x_filter_tmp); + + d7 = convolve8_4x4(reg7, reg8, reg9, reg10, reg11, reg12, reg13, reg14, + x_filter_tmp); + + transpose_s16_4x8(&d0, &d1, &d2, &d3, &d4, &d5, &d6, &d7, &out0, &out1, + &out2, &out3); + + out0 = vaddq_s16(out0, horiz_const); + out0 = vqrshlq_s16(out0, shift_round_0); + + out1 = vaddq_s16(out1, horiz_const); + out1 = vqrshlq_s16(out1, shift_round_0); + + out2 = vaddq_s16(out2, horiz_const); + out2 = vqrshlq_s16(out2, shift_round_0); + + out3 = vaddq_s16(out3, horiz_const); + out3 = vqrshlq_s16(out3, shift_round_0); + + store_s16_8x4(d_tmp, im_dst_stride, out0, out1, out2, out3); + + reg0 = reg8; + reg1 = reg9; + reg2 = reg10; + reg3 = reg11; + reg4 = reg12; + reg5 = reg13; + reg6 = reg14; s += 8; d_tmp += 8; width -= 8; } while (width > 0); - src_ptr += src_stride; - dst_ptr += im_dst_stride; - height -= 1; - } while (height > 0); + src_ptr += 4 * src_stride; + dst_ptr += 4 * im_dst_stride; + height -= 4; + } + + if (height) { + assert(height < 4); + horiz_filter_w8_single_row(src_ptr, src_stride, dst_ptr, im_stride, w, + height, x_filter_tmp, horiz_const, + shift_round_0); + } +#else + + horiz_filter_w8_single_row(src_ptr, src_stride, dst_ptr, im_stride, w, + height, x_filter_tmp, horiz_const, + shift_round_0); #endif } diff --git a/media/libaom/src/av1/common/arm/selfguided_neon.c b/media/libaom/src/av1/common/arm/selfguided_neon.c index d1e93d7305..fc404a64ab 100644 --- a/media/libaom/src/av1/common/arm/selfguided_neon.c +++ b/media/libaom/src/av1/common/arm/selfguided_neon.c @@ -19,8 +19,8 @@ #include "aom_dsp/txfm_common.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/common.h" -#include "av1/common/onyxc_int.h" #include "av1/common/resize.h" #include "av1/common/restoration.h" #include "av1/common/arm/mem_neon.h" @@ -376,6 +376,21 @@ static INLINE void boxsum2(int16_t *src, const int src_stride, int16_t *dst16, w -= 8; count++; } while (w > 0); + + // memset needed for row pixels as 2nd stage of boxsum filter uses + // first 2 rows of dst16, dst2 buffer which is not filled in first stage. + for (int x = 0; x < 2; x++) { + memset(dst16 + x * dst_stride, 0, (width + 4) * sizeof(*dst16)); + memset(dst2 + x * dst_stride, 0, (width + 4) * sizeof(*dst2)); + } + + // memset needed for extra columns as 2nd stage of boxsum filter uses + // last 2 columns of dst16, dst2 buffer which is not filled in first stage. + for (int x = 2; x < height + 2; x++) { + int dst_offset = x * dst_stride + width + 2; + memset(dst16 + dst_offset, 0, 3 * sizeof(*dst16)); + memset(dst2 + dst_offset, 0, 3 * sizeof(*dst2)); + } } { @@ -792,6 +807,21 @@ static INLINE void boxsum1(int16_t *src, const int src_stride, uint16_t *dst1, w -= 8; count++; } while (w > 0); + + // memset needed for row pixels as 2nd stage of boxsum filter uses + // first 2 rows of dst1, dst2 buffer which is not filled in first stage. + for (int x = 0; x < 2; x++) { + memset(dst1 + x * dst_stride, 0, (width + 4) * sizeof(*dst1)); + memset(dst2 + x * dst_stride, 0, (width + 4) * sizeof(*dst2)); + } + + // memset needed for extra columns as 2nd stage of boxsum filter uses + // last 2 columns of dst1, dst2 buffer which is not filled in first stage. + for (int x = 2; x < height + 2; x++) { + int dst_offset = x * dst_stride + width + 2; + memset(dst1 + dst_offset, 0, 3 * sizeof(*dst1)); + memset(dst2 + dst_offset, 0, 3 * sizeof(*dst2)); + } } { @@ -1319,6 +1349,11 @@ static INLINE void src_convert_u8_to_u16(const uint8_t *src, dst_ptr[y + x * dst_stride] = src_ptr[y + x * src_stride]; } } + + // memset uninitialized rows of src buffer as they are needed for the + // boxsum filter calculation. + for (int x = height; x < height + 5; x++) + memset(dst + x * dst_stride, 0, (width + 2) * sizeof(*dst)); } #if CONFIG_AV1_HIGHBITDEPTH @@ -1360,6 +1395,10 @@ static INLINE void src_convert_hbd_copy(const uint16_t *src, int src_stride, memcpy((dst_ptr + x * dst_stride), (src_ptr + x * src_stride), sizeof(uint16_t) * width); } + // memset uninitialized rows of src buffer as they are needed for the + // boxsum filter calculation. + for (int x = height; x < height + 5; x++) + memset(dst + x * dst_stride, 0, (width + 2) * sizeof(*dst)); } #endif // CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/av1/common/arm/transpose_neon.h b/media/libaom/src/av1/common/arm/transpose_neon.h index 8a3d9f07ff..91d89b43f7 100644 --- a/media/libaom/src/av1/common/arm/transpose_neon.h +++ b/media/libaom/src/av1/common/arm/transpose_neon.h @@ -250,6 +250,71 @@ static INLINE void transpose_u16_4x8(uint16x4_t *a0, uint16x4_t *a1, vreinterpret_u16_u32(c3.val[1])); } +static INLINE void transpose_s16_4x8(int16x4_t *a0, int16x4_t *a1, + int16x4_t *a2, int16x4_t *a3, + int16x4_t *a4, int16x4_t *a5, + int16x4_t *a6, int16x4_t *a7, + int16x8_t *o0, int16x8_t *o1, + int16x8_t *o2, int16x8_t *o3) { + // Swap 16 bit elements. Goes from: + // a0: 00 01 02 03 + // a1: 10 11 12 13 + // a2: 20 21 22 23 + // a3: 30 31 32 33 + // a4: 40 41 42 43 + // a5: 50 51 52 53 + // a6: 60 61 62 63 + // a7: 70 71 72 73 + // to: + // b0.val[0]: 00 10 02 12 + // b0.val[1]: 01 11 03 13 + // b1.val[0]: 20 30 22 32 + // b1.val[1]: 21 31 23 33 + // b2.val[0]: 40 50 42 52 + // b2.val[1]: 41 51 43 53 + // b3.val[0]: 60 70 62 72 + // b3.val[1]: 61 71 63 73 + + int16x4x2_t b0 = vtrn_s16(*a0, *a1); + int16x4x2_t b1 = vtrn_s16(*a2, *a3); + int16x4x2_t b2 = vtrn_s16(*a4, *a5); + int16x4x2_t b3 = vtrn_s16(*a6, *a7); + + // Swap 32 bit elements resulting in: + // c0.val[0]: 00 10 20 30 + // c0.val[1]: 02 12 22 32 + // c1.val[0]: 01 11 21 31 + // c1.val[1]: 03 13 23 33 + // c2.val[0]: 40 50 60 70 + // c2.val[1]: 42 52 62 72 + // c3.val[0]: 41 51 61 71 + // c3.val[1]: 43 53 63 73 + + int32x2x2_t c0 = vtrn_s32(vreinterpret_s32_s16(b0.val[0]), + vreinterpret_s32_s16(b1.val[0])); + int32x2x2_t c1 = vtrn_s32(vreinterpret_s32_s16(b0.val[1]), + vreinterpret_s32_s16(b1.val[1])); + int32x2x2_t c2 = vtrn_s32(vreinterpret_s32_s16(b2.val[0]), + vreinterpret_s32_s16(b3.val[0])); + int32x2x2_t c3 = vtrn_s32(vreinterpret_s32_s16(b2.val[1]), + vreinterpret_s32_s16(b3.val[1])); + + // Swap 64 bit elements resulting in: + // o0: 00 10 20 30 40 50 60 70 + // o1: 01 11 21 31 41 51 61 71 + // o2: 02 12 22 32 42 52 62 72 + // o3: 03 13 23 33 43 53 63 73 + + *o0 = vcombine_s16(vreinterpret_s16_s32(c0.val[0]), + vreinterpret_s16_s32(c2.val[0])); + *o1 = vcombine_s16(vreinterpret_s16_s32(c1.val[0]), + vreinterpret_s16_s32(c3.val[0])); + *o2 = vcombine_s16(vreinterpret_s16_s32(c0.val[1]), + vreinterpret_s16_s32(c2.val[1])); + *o3 = vcombine_s16(vreinterpret_s16_s32(c1.val[1]), + vreinterpret_s16_s32(c3.val[1])); +} + static INLINE void transpose_u16_8x8(uint16x8_t *a0, uint16x8_t *a1, uint16x8_t *a2, uint16x8_t *a3, uint16x8_t *a4, uint16x8_t *a5, @@ -386,7 +451,7 @@ static INLINE void transpose_s16_8x8(int16x8_t *a0, int16x8_t *a1, vget_high_s16(vreinterpretq_s16_s32(c3.val[1]))); } -static INLINE int16x8x2_t vpx_vtrnq_s64_to_s16(int32x4_t a0, int32x4_t a1) { +static INLINE int16x8x2_t aom_vtrnq_s64_to_s16(int32x4_t a0, int32x4_t a1) { int16x8x2_t b0; b0.val[0] = vcombine_s16(vreinterpret_s16_s32(vget_low_s32(a0)), vreinterpret_s16_s32(vget_low_s32(a1))); @@ -448,10 +513,10 @@ static INLINE void transpose_s16_8x8q(int16x8_t *a0, int16x8_t *out) { // d2.val[1]: 06 16 26 36 46 56 66 76 // d3.val[0]: 03 13 23 33 43 53 63 73 // d3.val[1]: 07 17 27 37 47 57 67 77 - const int16x8x2_t d0 = vpx_vtrnq_s64_to_s16(c0.val[0], c2.val[0]); - const int16x8x2_t d1 = vpx_vtrnq_s64_to_s16(c1.val[0], c3.val[0]); - const int16x8x2_t d2 = vpx_vtrnq_s64_to_s16(c0.val[1], c2.val[1]); - const int16x8x2_t d3 = vpx_vtrnq_s64_to_s16(c1.val[1], c3.val[1]); + const int16x8x2_t d0 = aom_vtrnq_s64_to_s16(c0.val[0], c2.val[0]); + const int16x8x2_t d1 = aom_vtrnq_s64_to_s16(c1.val[0], c3.val[0]); + const int16x8x2_t d2 = aom_vtrnq_s64_to_s16(c0.val[1], c2.val[1]); + const int16x8x2_t d3 = aom_vtrnq_s64_to_s16(c1.val[1], c3.val[1]); *out = d0.val[0]; *(out + 1) = d1.val[0]; diff --git a/media/libaom/src/av1/common/onyxc_int.h b/media/libaom/src/av1/common/av1_common_int.h similarity index 67% rename from media/libaom/src/av1/common/onyxc_int.h rename to media/libaom/src/av1/common/av1_common_int.h index fafd656e1c..0403405e9c 100644 --- a/media/libaom/src/av1/common/onyxc_int.h +++ b/media/libaom/src/av1/common/av1_common_int.h @@ -9,8 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ -#ifndef AOM_AV1_COMMON_ONYXC_INT_H_ -#define AOM_AV1_COMMON_ONYXC_INT_H_ +#ifndef AOM_AV1_COMMON_AV1_COMMON_INT_H_ +#define AOM_AV1_COMMON_AV1_COMMON_INT_H_ #include "config/aom_config.h" #include "config/av1_rtcd.h" @@ -71,7 +71,7 @@ extern "C" { // clang-format seems to think this is a pointer dereference and not a // multiplication. #define MAX_NUM_OPERATING_POINTS \ - MAX_NUM_TEMPORAL_LAYERS * MAX_NUM_SPATIAL_LAYERS + (MAX_NUM_TEMPORAL_LAYERS * MAX_NUM_SPATIAL_LAYERS) /* clang-format on */ // TODO(jingning): Turning this on to set up transform coefficient @@ -149,7 +149,6 @@ typedef struct RefCntBuffer { aom_film_grain_t film_grain_params; aom_codec_frame_buffer_t raw_frame_buffer; YV12_BUFFER_CONFIG buf; - hash_table hash_table; FRAME_TYPE frame_type; // This is only used in the encoder but needs to be indexed per ref frame @@ -224,6 +223,8 @@ typedef struct { // Note: All syntax elements of sequence_header_obu that need to be // bit-identical across multiple sequence headers must be part of this struct, // so that consistency is checked by are_seq_headers_consistent() function. +// One exception is the last member 'op_params' that is ignored by +// are_seq_headers_consistent() function. typedef struct SequenceHeader { int num_bits_width; int num_bits_height; @@ -262,15 +263,6 @@ typedef struct SequenceHeader { uint8_t enable_restoration; // To turn on/off loop restoration BITSTREAM_PROFILE profile; - // Operating point info. - int operating_points_cnt_minus_1; - int operating_point_idc[MAX_NUM_OPERATING_POINTS]; - uint8_t display_model_info_present_flag; - uint8_t decoder_model_info_present_flag; - 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. - // Color config. aom_bit_depth_t bit_depth; // AOM_BITS_8 in profile 0 or 1, // AOM_BITS_10 or AOM_BITS_12 in profile 2 or 3. @@ -285,20 +277,23 @@ typedef struct SequenceHeader { aom_chroma_sample_position_t chroma_sample_position; uint8_t separate_uv_delta_q; uint8_t film_grain_params_present; -} SequenceHeader; -typedef struct { - int frame_width; - int frame_height; - int mi_rows; - int mi_cols; - int mb_rows; - int mb_cols; - int num_mbs; - aom_bit_depth_t bit_depth; - int subsampling_x; - int subsampling_y; -} FRAME_INFO; + // Operating point info. + int operating_points_cnt_minus_1; + int operating_point_idc[MAX_NUM_OPERATING_POINTS]; + int timing_info_present; + aom_timing_info_t timing_info; + uint8_t decoder_model_info_present_flag; + aom_dec_model_info_t decoder_model_info; + uint8_t display_model_info_present_flag; + AV1_LEVEL seq_level_idx[MAX_NUM_OPERATING_POINTS]; + uint8_t tier[MAX_NUM_OPERATING_POINTS]; // seq_tier in spec. One bit: 0 or 1. + + // IMPORTANT: the op_params member must be at the end of the struct so that + // are_seq_headers_consistent() can be implemented with a memcmp() call. + // TODO(urvang): We probably don't need the +1 here. + aom_dec_model_op_parameters_t op_params[MAX_NUM_OPERATING_POINTS + 1]; +} SequenceHeader; typedef struct { int skip_mode_allowed; @@ -319,28 +314,259 @@ typedef struct { int frame_refs_short_signaling; } CurrentFrame; +// Struct containing some frame level features. +typedef struct { + bool disable_cdf_update; + bool allow_high_precision_mv; + bool cur_frame_force_integer_mv; // 0 the default in AOM, 1 only integer + bool allow_screen_content_tools; + bool allow_intrabc; + bool allow_warped_motion; + // Whether to use previous frames' motion vectors for prediction. + bool allow_ref_frame_mvs; + bool coded_lossless; // frame is fully lossless at the coded resolution. + bool all_lossless; // frame is fully lossless at the upscaled resolution. + bool reduced_tx_set_used; + bool error_resilient_mode; + bool switchable_motion_mode; + TX_MODE tx_mode; + InterpFilter interp_filter; + int primary_ref_frame; + int byte_alignment; + // Flag signaling how frame contexts should be updated at the end of + // a frame decode + REFRESH_FRAME_CONTEXT_MODE refresh_frame_context; +} FeatureFlags; + +// Struct containing params related to tiles. +typedef struct CommonTileParams { + int cols; // number of tile columns that frame is divided into + int rows; // number of tile rows that frame is divided into + int max_width_sb; // maximum tile width in superblock units. + int max_height_sb; // maximum tile height in superblock units. + // Min width of non-rightmost tile in MI units. Only valid if cols > 1. + int min_inner_width; + + // If true, tiles are uniformly spaced with power-of-two number of rows and + // columns. + // If false, tiles have explicitly configured widths and heights. + int uniform_spacing; + + // Following members are only valid when uniform_spacing == 1 + int log2_cols; // log2 of 'cols'. + int log2_rows; // log2 of 'rows'. + int width; // tile width in MI units + int height; // tile height in MI units + // End of members that are only valid when uniform_spacing == 1 + + // Min num of tile columns possible based on 'max_width_sb' and frame width. + int min_log2_cols; + // Min num of tile rows possible based on 'max_height_sb' and frame height. + int min_log2_rows; + // Min num of tile columns possible based on frame width. + int max_log2_cols; + // Max num of tile columns possible based on frame width. + int max_log2_rows; + // log2 of min number of tiles (same as min_log2_cols + min_log2_rows). + int min_log2; + // col_start_sb[i] is the start position of tile column i in superblock units. + // valid for 0 <= i <= cols + int col_start_sb[MAX_TILE_COLS + 1]; + // row_start_sb[i] is the start position of tile row i in superblock units. + // valid for 0 <= i <= rows + int row_start_sb[MAX_TILE_ROWS + 1]; + // If true, we are using large scale tile mode. + unsigned int large_scale; + // Only relevant when large_scale == 1. + // If true, the independent decoding of a single tile or a section of a frame + // is allowed. + unsigned int single_tile_decoding; +} CommonTileParams; + +// Struct containing params related to MB_MODE_INFO arrays and related info. +typedef struct CommonModeInfoParams CommonModeInfoParams; +struct CommonModeInfoParams { + // Number of rows/cols in the frame in 16 pixel units. + // This is computed from frame width and height aligned to a multiple of 8. + int mb_rows; + int mb_cols; + // Total MBs = mb_rows * mb_cols. + int MBs; + + // Number of rows/cols in the frame in 4 pixel (MB_MODE_INFO) units. + // This is computed from frame width and height aligned to a multiple of 8. + int mi_rows; + int mi_cols; + + // An array of MB_MODE_INFO structs for every 'mi_alloc_bsize' sized block + // in the frame. + // Note: This array should be treated like a scratch memory, and should NOT be + // accessed directly, in most cases. Please use 'mi_grid_base' array instead. + MB_MODE_INFO *mi_alloc; + // Number of allocated elements in 'mi_alloc'. + int mi_alloc_size; + // Stride for 'mi_alloc' array. + int mi_alloc_stride; + // The minimum block size that each element in 'mi_alloc' can correspond to. + // For decoder, this is always BLOCK_4X4. + // For encoder, this is currently set to BLOCK_4X4 for resolution < 4k, + // and BLOCK_8X8 for resolution >= 4k. + BLOCK_SIZE mi_alloc_bsize; + + // Grid of pointers to 4x4 MB_MODE_INFO structs allocated in 'mi_alloc'. + // It's possible that: + // - Multiple pointers in the grid point to the same element in 'mi_alloc' + // (for example, for all 4x4 blocks that belong to the same partition block). + // - Some pointers can be NULL (for example, for blocks outside visible area). + MB_MODE_INFO **mi_grid_base; + // Number of allocated elements in 'mi_grid_base' (and 'tx_type_map' also). + int mi_grid_size; + // Stride for 'mi_grid_base' (and 'tx_type_map' also). + int mi_stride; + + // An array of tx types for each 4x4 block in the frame. + // Number of allocated elements is same as 'mi_grid_size', and stride is + // same as 'mi_grid_size'. So, indexing into 'tx_type_map' is same as that of + // 'mi_grid_base'. + TX_TYPE *tx_type_map; + + // Function pointers to allow separate logic for encoder and decoder. + void (*free_mi)(struct CommonModeInfoParams *mi_params); + void (*setup_mi)(struct CommonModeInfoParams *mi_params); + void (*set_mb_mi)(struct CommonModeInfoParams *mi_params, int width, + int height); +}; + +// Parameters related to quantization at the frame level. +typedef struct CommonQuantParams CommonQuantParams; +struct CommonQuantParams { + // Base qindex of the frame in the range 0 to 255. + int base_qindex; + + // Delta of qindex (from base_qindex) for Y plane DC coefficient. + // Note: y_ac_delta_q is implicitly 0. + int y_dc_delta_q; + + // Delta of qindex (from base_qindex) for U plane DC and AC coefficients. + int u_dc_delta_q; + int v_dc_delta_q; + + // Delta of qindex (from base_qindex) for V plane DC and AC coefficients. + // Same as those for U plane if cm->seq_params.separate_uv_delta_q == 0. + int u_ac_delta_q; + int v_ac_delta_q; + + // Note: The qindex per superblock may have a delta from the qindex obtained + // at frame level from parameters above, based on 'cm->delta_q_info'. + + // The dequantizers below are true dequantizers used only in the + // dequantization process. They have the same coefficient + // shift/scale as TX. + int16_t y_dequant_QTX[MAX_SEGMENTS][2]; + int16_t u_dequant_QTX[MAX_SEGMENTS][2]; + int16_t v_dequant_QTX[MAX_SEGMENTS][2]; + + // Global quant matrix tables + const qm_val_t *giqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL]; + const qm_val_t *gqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL]; + + // Local quant matrix tables for each frame + const qm_val_t *y_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; + const qm_val_t *u_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; + const qm_val_t *v_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; + + // Flag indicating whether quantization matrices are being used: + // - If true, qm_level_y, qm_level_u and qm_level_v indicate the level + // indices to be used to access appropriate global quant matrix tables. + // - If false, we implicitly use level index 'NUM_QM_LEVELS - 1'. + bool using_qmatrix; + int qmatrix_level_y; + int qmatrix_level_u; + int qmatrix_level_v; +}; + +// Context used for transmitting various symbols in the bistream. +typedef struct CommonContexts CommonContexts; +struct CommonContexts { + // Context used by 'FRAME_CONTEXT.partition_cdf' to transmit partition type. + // partition[i][j] is the context for ith tile row, jth mi_col. + PARTITION_CONTEXT **partition; + + // Context used to derive context for multiple symbols: + // - 'TXB_CTX.txb_skip_ctx' used by 'FRAME_CONTEXT.txb_skip_cdf' to transmit + // to transmit skip_txfm flag. + // - 'TXB_CTX.dc_sign_ctx' used by 'FRAME_CONTEXT.dc_sign_cdf' to transmit + // sign. + // entropy[i][j][k] is the context for ith plane, jth tile row, kth mi_col. + ENTROPY_CONTEXT **entropy[MAX_MB_PLANE]; + + // Context used to derive context for 'FRAME_CONTEXT.txfm_partition_cdf' to + // transmit 'is_split' flag to indicate if this transform block should be + // split into smaller sub-blocks. + // txfm[i][j] is the context for ith tile row, jth mi_col. + TXFM_CONTEXT **txfm; + + // Dimensions that were used to allocate the arrays above. + // If these dimensions change, the arrays may have to be re-allocated. + int num_planes; // Corresponds to av1_num_planes(cm) + int num_tile_rows; // Corresponds to cm->tiles.row + int num_mi_cols; // Corresponds to cm->mi_params.mi_cols +}; + typedef struct AV1Common { + // Information about the current frame that is being coded. CurrentFrame current_frame; + // Code and details about current error status. struct aom_internal_error_info error; + + // AV1 allows two types of frame scaling operations: + // (1) Frame super-resolution: that allows coding a frame at lower resolution + // and after decoding the frame, normatively uscales and restores the frame -- + // inside the coding loop. + // (2) Frame resize: that allows coding frame at lower/higher resolution, and + // then non-normatively upscale the frame at the time of rendering -- outside + // the coding loop. + // Hence, the need for 3 types of dimensions. + + // Coded frame dimensions. int width; int height; + + // Rendered frame dimensions, after applying both super-resolution and resize + // to the coded frame. + // Different from coded dimensions if super-resolution and/or resize are + // being used for this frame. int render_width; int render_height; - int timing_info_present; - aom_timing_info_t timing_info; - int buffer_removal_time_present; - aom_dec_model_info_t buffer_model; - aom_dec_model_op_parameters_t op_params[MAX_NUM_OPERATING_POINTS + 1]; - aom_op_timing_info_t op_frame_timing[MAX_NUM_OPERATING_POINTS + 1]; + + // Frame dimensions after applying super-resolution to the coded frame (if + // present), but before applying resize. + // Larger than the coded dimensions if super-resolution is being used for + // this frame. + // Different from rendered dimensions if resize is being used for this frame. + int superres_upscaled_width; + int superres_upscaled_height; + + // The denominator of the superres scale used by this frame. + // Note: The numerator is fixed to be SCALE_NUMERATOR. + uint8_t superres_scale_denominator; + + // If true, buffer removal times are present. + bool buffer_removal_time_present; + // buffer_removal_times[op_num] specifies the frame removal time in units of + // DecCT clock ticks counted from the removal time of the last random access + // point for operating point op_num. + // TODO(urvang): We probably don't need the +1 here. + uint32_t buffer_removal_times[MAX_NUM_OPERATING_POINTS + 1]; + // Presentation time of the frame in clock ticks DispCT counted from the + // removal time of the last random access point for the operating point that + // is being decoded. uint32_t frame_presentation_time; - int context_update_tile_id; - - // Scale of the current frame with respect to itself. - struct scale_factors sf_identity; - + // Buffer where previous frame is stored. RefCntBuffer *prev_frame; + // Buffer into which the current frame will be stored and other related info. // TODO(hkuang): Combine this with cur_buf in macroblockd. RefCntBuffer *cur_frame; @@ -364,6 +590,15 @@ typedef struct AV1Common { // have a remapped index for the same. int remapped_ref_idx[REF_FRAMES]; + // Scale of the current frame with respect to itself. + // This is currently used for intra block copy, which behaves like an inter + // prediction mode, where the reference frame is the current frame itself. + struct scale_factors sf_identity; + + // Scale factors of the reference frame with respect to the current frame. + // This is required for generating inter prediction and will be non-identity + // for a reference frame, if it has different dimensions than the coded + // dimensions of the current frame. struct scale_factors ref_scale_factors[REF_FRAMES]; // For decoder, ref_frame_map[i] maps reference type 'i' to a pointer to @@ -373,203 +608,133 @@ typedef struct AV1Common { // a pointer to the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'. RefCntBuffer *ref_frame_map[REF_FRAMES]; - FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/ - + // If true, this frame is actually shown after decoding. + // If false, this frame is coded in the bitstream, but not shown. It is only + // used as a reference for other frames coded later. int show_frame; - int showable_frame; // frame can be used as show existing frame in future + + // If true, this frame can be used as a show-existing frame for other frames + // coded later. + // When 'show_frame' is true, this is always true for all non-keyframes. + // When 'show_frame' is false, this value is transmitted in the bitstream. + int showable_frame; + + // If true, show an existing frame coded before, instead of actually coding a + // frame. The existing frame comes from one of the existing reference buffers, + // as signaled in the bitstream. int show_existing_frame; - uint8_t disable_cdf_update; - int allow_high_precision_mv; - uint8_t cur_frame_force_integer_mv; // 0 the default in AOM, 1 only integer + // Whether some features are allowed or not. + FeatureFlags features; - uint8_t allow_screen_content_tools; - int allow_intrabc; - int allow_warped_motion; - - // MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in - // MB_MODE_INFO (4-pixel) units. - int MBs; - int mb_rows, mi_rows; - int mb_cols, mi_cols; - int mi_stride; - - /* profile settings */ - TX_MODE tx_mode; + // Params related to MB_MODE_INFO arrays and related info. + CommonModeInfoParams mi_params; #if CONFIG_ENTROPY_STATS int coef_cdf_category; #endif + // Quantization params. + CommonQuantParams quant_params; - int base_qindex; - int y_dc_delta_q; - int u_dc_delta_q; - int v_dc_delta_q; - int u_ac_delta_q; - int v_ac_delta_q; - - // The dequantizers below are true dequantizers used only in the - // dequantization process. They have the same coefficient - // shift/scale as TX. - int16_t y_dequant_QTX[MAX_SEGMENTS][2]; - int16_t u_dequant_QTX[MAX_SEGMENTS][2]; - int16_t v_dequant_QTX[MAX_SEGMENTS][2]; - - // Global quant matrix tables - const qm_val_t *giqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL]; - const qm_val_t *gqmatrix[NUM_QM_LEVELS][3][TX_SIZES_ALL]; - - // Local quant matrix tables for each frame - const qm_val_t *y_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; - const qm_val_t *u_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; - const qm_val_t *v_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; - - // Encoder - int using_qmatrix; - int qm_y; - int qm_u; - int qm_v; - int min_qmlevel; - int max_qmlevel; - int use_quant_b_adapt; - - /* We allocate a MB_MODE_INFO struct for each macroblock, together with - an extra row on top and column on the left to simplify prediction. */ - int mi_alloc_size, mi_grid_size; - MB_MODE_INFO *mi; /* Corresponds to upper left visible macroblock */ - uint8_t *tx_type_map; - - // The minimum size each allocated mi can correspond to. - // For decoder, this is always BLOCK_4X4. - // For encoder, this is currently set to BLOCK_4X4 for resolution below 4k, - // and BLOCK_8X8 for resolution above 4k - BLOCK_SIZE mi_alloc_bsize; - int mi_alloc_rows, mi_alloc_cols, mi_alloc_stride; - - // Separate mi functions between encoder and decoder. - int (*alloc_mi)(struct AV1Common *cm); - void (*free_mi)(struct AV1Common *cm); - void (*setup_mi)(struct AV1Common *cm); - void (*set_mb_mi)(struct AV1Common *cm, int height, int width); - - // Grid of pointers to 4x4 MB_MODE_INFO structs. Any 4x4 not in the visible - // area will be NULL. - MB_MODE_INFO **mi_grid_base; - - // Whether to use previous frames' motion vectors for prediction. - int allow_ref_frame_mvs; + // Segmentation info for current frame. + struct segmentation seg; + // Segmentation map for previous frame. uint8_t *last_frame_seg_map; - InterpFilter interp_filter; - - int switchable_motion_mode; - + // Deblocking filter parameters. loop_filter_info_n lf_info; - // The denominator of the superres scale; the numerator is fixed. - uint8_t superres_scale_denominator; - int superres_upscaled_width; - int superres_upscaled_height; - RestorationInfo rst_info[MAX_MB_PLANE]; - - // Pointer to a scratch buffer used by self-guided restoration - int32_t *rst_tmpbuf; - RestorationLineBuffers *rlbs; - - // Output of loop restoration - YV12_BUFFER_CONFIG rst_frame; - - // Flag signaling how frame contexts should be updated at the end of - // a frame decode - REFRESH_FRAME_CONTEXT_MODE refresh_frame_context; - - int ref_frame_sign_bias[REF_FRAMES]; /* Two state 0, 1 */ - struct loopfilter lf; - struct segmentation seg; - int coded_lossless; // frame is fully lossless at the coded resolution. - int all_lossless; // frame is fully lossless at the upscaled resolution. - int reduced_tx_set_used; + // Loop Restoration filter parameters. + RestorationInfo rst_info[MAX_MB_PLANE]; // Loop Restoration filter info. + int32_t *rst_tmpbuf; // Scratch buffer for self-guided restoration filter. + RestorationLineBuffers *rlbs; // Line buffers required by loop restoration. + YV12_BUFFER_CONFIG rst_frame; // Stores the output of loop restoration. - // Context probabilities for reference frame prediction - MV_REFERENCE_FRAME comp_fwd_ref[FWD_REFS]; - MV_REFERENCE_FRAME comp_bwd_ref[BWD_REFS]; + // CDEF (Constrained Directional Enhancement Filter) parameters. + CdefInfo cdef_info; - FRAME_CONTEXT *fc; /* this frame entropy */ + // Parameters for film grain synthesis. + aom_film_grain_t film_grain_params; + + // Parameters for delta quantization and delta loop filter level. + DeltaQInfo delta_q_info; + + // Global motion parameters for each reference frame. + WarpedMotionParams global_motion[REF_FRAMES]; + + // Elements part of the sequence header, that are applicable for all the + // frames in the video. + SequenceHeader seq_params; + + // Current CDFs of all the symbols for the current frame. + FRAME_CONTEXT *fc; + // Default CDFs used when features.primary_ref_frame = PRIMARY_REF_NONE + // (e.g. for a keyframe). These default CDFs are defined by the bitstream and + // copied from default CDF tables for each symbol. FRAME_CONTEXT *default_frame_context; - int primary_ref_frame; - int error_resilient_mode; - - int tile_cols, tile_rows; - - int max_tile_width_sb; - int min_log2_tile_cols; - int max_log2_tile_cols; - int max_log2_tile_rows; - int min_log2_tile_rows; - int min_log2_tiles; - int max_tile_height_sb; - int uniform_tile_spacing_flag; - int log2_tile_cols; // only valid for uniform tiles - int log2_tile_rows; // only valid for uniform tiles - 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; - - int byte_alignment; - int skip_loop_filter; - int skip_film_grain; + // Parameters related to tiling. + CommonTileParams tiles; // External BufferPool passed from outside. BufferPool *buffer_pool; - PARTITION_CONTEXT **above_seg_context; - ENTROPY_CONTEXT **above_context[MAX_MB_PLANE]; - TXFM_CONTEXT **above_txfm_context; - WarpedMotionParams global_motion[REF_FRAMES]; - aom_film_grain_t film_grain_params; + // Above context buffers and their sizes. + // Note: above contexts are allocated in this struct, as their size is + // dependent on frame width, while left contexts are declared and allocated in + // MACROBLOCKD struct, as they have a fixed size. + CommonContexts above_contexts; - CdefInfo cdef_info; - DeltaQInfo delta_q_info; // Delta Q and Delta LF parameters - - int num_tg; - SequenceHeader seq_params; + // When cm->seq_params.frame_id_numbers_present_flag == 1, current and + // reference frame IDs are signaled in the bitstream. int current_frame_id; int ref_frame_id[REF_FRAMES]; - int valid_for_referencing[REF_FRAMES]; + + // Motion vectors provided by motion field estimation. + // tpl_mvs[row * stride + col] stores MV for block at [mi_row, mi_col] where: + // mi_row = 2 * row, + // mi_col = 2 * col, and + // stride = cm->mi_params.mi_stride / 2 TPL_MV_REF *tpl_mvs; + // Allocated size of 'tpl_mvs' array. Refer to 'ensure_mv_buffer()' function. int tpl_mvs_mem_size; + // ref_frame_sign_bias[k] is 1 if relative distance between reference 'k' and + // current frame is positive; and 0 otherwise. + int ref_frame_sign_bias[REF_FRAMES]; + // ref_frame_side[k] is 1 if relative distance between reference 'k' and + // current frame is positive, -1 if relative distance is 0; and 0 otherwise. // TODO(jingning): This can be combined with sign_bias later. int8_t ref_frame_side[REF_FRAMES]; - int is_annexb; - - int temporal_layer_id; - int spatial_layer_id; + // Number of temporal layers: may be > 1 for SVC (scalable vector coding). unsigned int number_temporal_layers; + // Temporal layer ID of this frame + // (in the range 0 ... (number_temporal_layers - 1)). + int temporal_layer_id; + + // Number of spatial layers: may be > 1 for SVC (scalable vector coding). unsigned int number_spatial_layers; - int num_allocated_above_context_mi_col; - int num_allocated_above_contexts; - int num_allocated_above_context_planes; + // Spatial layer ID of this frame + // (in the range 0 ... (number_spatial_layers - 1)). + int spatial_layer_id; #if TXCOEFF_TIMER int64_t cum_txcoeff_timer; int64_t txcoeff_timer; int txb_count; -#endif +#endif // TXCOEFF_TIMER #if TXCOEFF_COST_TIMER int64_t cum_txcoeff_cost_timer; int64_t txcoeff_cost_timer; int64_t txcoeff_cost_count; -#endif +#endif // TXCOEFF_COST_TIMER + +#if CONFIG_LPF_MASK int is_decoding; +#endif // CONFIG_LPF_MASK } AV1_COMMON; // TODO(hkuang): Don't need to lock the whole pool after implementing atomic @@ -703,14 +868,15 @@ static INLINE struct scale_factors *get_ref_scale_factors( static INLINE RefCntBuffer *get_primary_ref_frame_buf( const AV1_COMMON *const cm) { - if (cm->primary_ref_frame == PRIMARY_REF_NONE) return NULL; - const int map_idx = get_ref_frame_map_idx(cm, cm->primary_ref_frame + 1); + const int primary_ref_frame = cm->features.primary_ref_frame; + if (primary_ref_frame == PRIMARY_REF_NONE) return NULL; + const int map_idx = get_ref_frame_map_idx(cm, primary_ref_frame + 1); return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL; } // Returns 1 if this frame might allow mvs from some reference frame. static INLINE int frame_might_allow_ref_frame_mvs(const AV1_COMMON *cm) { - return !cm->error_resilient_mode && + return !cm->features.error_resilient_mode && cm->seq_params.order_hint_info.enable_ref_frame_mvs && cm->seq_params.order_hint_info.enable_order_hint && !frame_is_intra_only(cm); @@ -718,30 +884,33 @@ static INLINE int frame_might_allow_ref_frame_mvs(const AV1_COMMON *cm) { // Returns 1 if this frame might use warped_motion static INLINE int frame_might_allow_warped_motion(const AV1_COMMON *cm) { - return !cm->error_resilient_mode && !frame_is_intra_only(cm) && + return !cm->features.error_resilient_mode && !frame_is_intra_only(cm) && cm->seq_params.enable_warped_motion; } static INLINE void ensure_mv_buffer(RefCntBuffer *buf, AV1_COMMON *cm) { const int buf_rows = buf->mi_rows; const int buf_cols = buf->mi_cols; + const CommonModeInfoParams *const mi_params = &cm->mi_params; - if (buf->mvs == NULL || buf_rows != cm->mi_rows || buf_cols != cm->mi_cols) { + if (buf->mvs == NULL || buf_rows != mi_params->mi_rows || + buf_cols != mi_params->mi_cols) { aom_free(buf->mvs); - buf->mi_rows = cm->mi_rows; - buf->mi_cols = cm->mi_cols; + buf->mi_rows = mi_params->mi_rows; + buf->mi_cols = mi_params->mi_cols; CHECK_MEM_ERROR(cm, buf->mvs, - (MV_REF *)aom_calloc( - ((cm->mi_rows + 1) >> 1) * ((cm->mi_cols + 1) >> 1), - sizeof(*buf->mvs))); + (MV_REF *)aom_calloc(((mi_params->mi_rows + 1) >> 1) * + ((mi_params->mi_cols + 1) >> 1), + sizeof(*buf->mvs))); aom_free(buf->seg_map); - CHECK_MEM_ERROR(cm, buf->seg_map, - (uint8_t *)aom_calloc(cm->mi_rows * cm->mi_cols, - sizeof(*buf->seg_map))); + CHECK_MEM_ERROR( + cm, buf->seg_map, + (uint8_t *)aom_calloc(mi_params->mi_rows * mi_params->mi_cols, + sizeof(*buf->seg_map))); } const int mem_size = - ((cm->mi_rows + MAX_MIB_SIZE) >> 1) * (cm->mi_stride >> 1); + ((mi_params->mi_rows + MAX_MIB_SIZE) >> 1) * (mi_params->mi_stride >> 1); int realloc = cm->tpl_mvs == NULL; if (cm->tpl_mvs) realloc |= cm->tpl_mvs_mem_size < mem_size; @@ -759,48 +928,51 @@ static INLINE int av1_num_planes(const AV1_COMMON *cm) { return cm->seq_params.monochrome ? 1 : MAX_MB_PLANE; } -static INLINE void av1_init_above_context(AV1_COMMON *cm, MACROBLOCKD *xd, - const int tile_row) { - const int num_planes = av1_num_planes(cm); +static INLINE void av1_init_above_context(CommonContexts *above_contexts, + int num_planes, int tile_row, + MACROBLOCKD *xd) { for (int i = 0; i < num_planes; ++i) { - xd->above_context[i] = cm->above_context[i][tile_row]; + xd->above_entropy_context[i] = above_contexts->entropy[i][tile_row]; } - xd->above_seg_context = cm->above_seg_context[tile_row]; - xd->above_txfm_context = cm->above_txfm_context[tile_row]; + xd->above_partition_context = above_contexts->partition[tile_row]; + xd->above_txfm_context = above_contexts->txfm[tile_row]; } static INLINE void av1_init_macroblockd(AV1_COMMON *cm, MACROBLOCKD *xd, tran_low_t *dqcoeff) { const int num_planes = av1_num_planes(cm); + const CommonQuantParams *const quant_params = &cm->quant_params; + for (int i = 0; i < num_planes; ++i) { xd->plane[i].dqcoeff = dqcoeff; if (xd->plane[i].plane_type == PLANE_TYPE_Y) { - memcpy(xd->plane[i].seg_dequant_QTX, cm->y_dequant_QTX, - sizeof(cm->y_dequant_QTX)); - memcpy(xd->plane[i].seg_iqmatrix, cm->y_iqmatrix, sizeof(cm->y_iqmatrix)); + memcpy(xd->plane[i].seg_dequant_QTX, quant_params->y_dequant_QTX, + sizeof(quant_params->y_dequant_QTX)); + memcpy(xd->plane[i].seg_iqmatrix, quant_params->y_iqmatrix, + sizeof(quant_params->y_iqmatrix)); } else { if (i == AOM_PLANE_U) { - memcpy(xd->plane[i].seg_dequant_QTX, cm->u_dequant_QTX, - sizeof(cm->u_dequant_QTX)); - memcpy(xd->plane[i].seg_iqmatrix, cm->u_iqmatrix, - sizeof(cm->u_iqmatrix)); + memcpy(xd->plane[i].seg_dequant_QTX, quant_params->u_dequant_QTX, + sizeof(quant_params->u_dequant_QTX)); + memcpy(xd->plane[i].seg_iqmatrix, quant_params->u_iqmatrix, + sizeof(quant_params->u_iqmatrix)); } else { - memcpy(xd->plane[i].seg_dequant_QTX, cm->v_dequant_QTX, - sizeof(cm->v_dequant_QTX)); - memcpy(xd->plane[i].seg_iqmatrix, cm->v_iqmatrix, - sizeof(cm->v_iqmatrix)); + memcpy(xd->plane[i].seg_dequant_QTX, quant_params->v_dequant_QTX, + sizeof(quant_params->v_dequant_QTX)); + memcpy(xd->plane[i].seg_iqmatrix, quant_params->v_iqmatrix, + sizeof(quant_params->v_iqmatrix)); } } } - xd->mi_stride = cm->mi_stride; + xd->mi_stride = cm->mi_params.mi_stride; xd->error_info = &cm->error; cfl_init(&xd->cfl, &cm->seq_params); } -static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col, - const int num_planes) { +static INLINE void set_entropy_context(MACROBLOCKD *xd, int mi_row, int mi_col, + const int num_planes) { int i; int row_offset = mi_row; int col_offset = mi_col; @@ -814,8 +986,10 @@ static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col, col_offset = mi_col - 1; int above_idx = col_offset; int left_idx = row_offset & MAX_MIB_MASK; - pd->above_context = &xd->above_context[i][above_idx >> pd->subsampling_x]; - pd->left_context = &xd->left_context[i][left_idx >> pd->subsampling_y]; + pd->above_entropy_context = + &xd->above_entropy_context[i][above_idx >> pd->subsampling_x]; + pd->left_entropy_context = + &xd->left_entropy_context[i][left_idx >> pd->subsampling_y]; } } @@ -839,10 +1013,13 @@ static INLINE void set_plane_n4(MACROBLOCKD *const xd, int bw, int bh, static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile, int mi_row, int bh, int mi_col, int bw, int mi_rows, int mi_cols) { - xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8); - xd->mb_to_bottom_edge = ((mi_rows - bh - mi_row) * MI_SIZE) * 8; - xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8); - xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8; + xd->mb_to_top_edge = -GET_MV_SUBPEL(mi_row * MI_SIZE); + xd->mb_to_bottom_edge = GET_MV_SUBPEL((mi_rows - bh - mi_row) * MI_SIZE); + xd->mb_to_left_edge = -GET_MV_SUBPEL((mi_col * MI_SIZE)); + xd->mb_to_right_edge = GET_MV_SUBPEL((mi_cols - bw - mi_col) * MI_SIZE); + + xd->mi_row = mi_row; + xd->mi_col = mi_col; // Are edges available for intra prediction? xd->up_available = (mi_row > tile->mi_row_start); @@ -871,6 +1048,7 @@ static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile, const int chroma_ref = ((mi_row & 0x01) || !(bh & 0x01) || !ss_y) && ((mi_col & 0x01) || !(bw & 0x01) || !ss_x); + xd->is_chroma_ref = chroma_ref; if (chroma_ref) { // To help calculate the "above" and "left" chroma blocks, note that the // current block may cover multiple luma blocks (eg, if partitioned into @@ -892,18 +1070,18 @@ static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile, xd->chroma_left_mbmi = chroma_left_mi; } - xd->n4_h = bh; - xd->n4_w = bw; + xd->height = bh; + xd->width = bw; xd->is_sec_rect = 0; - if (xd->n4_w < xd->n4_h) { + if (xd->width < xd->height) { // Only mark is_sec_rect as 1 for the last block. // For PARTITION_VERT_4, it would be (0, 0, 0, 1); // For other partitions, it would be (0, 1). - if (!((mi_col + xd->n4_w) & (xd->n4_h - 1))) xd->is_sec_rect = 1; + if (!((mi_col + xd->width) & (xd->height - 1))) xd->is_sec_rect = 1; } - if (xd->n4_w > xd->n4_h) - if (mi_row & (xd->n4_w - 1)) xd->is_sec_rect = 1; + if (xd->width > xd->height) + if (mi_row & (xd->width - 1)) xd->is_sec_rect = 1; } static INLINE aom_cdf_prob *get_y_mode_cdf(FRAME_CONTEXT *tile_ctx, @@ -919,9 +1097,9 @@ static INLINE aom_cdf_prob *get_y_mode_cdf(FRAME_CONTEXT *tile_ctx, static INLINE void update_partition_context(MACROBLOCKD *xd, int mi_row, int mi_col, BLOCK_SIZE subsize, BLOCK_SIZE bsize) { - PARTITION_CONTEXT *const above_ctx = xd->above_seg_context + mi_col; + PARTITION_CONTEXT *const above_ctx = xd->above_partition_context + mi_col; PARTITION_CONTEXT *const left_ctx = - xd->left_seg_context + (mi_row & MAX_MIB_MASK); + xd->left_partition_context + (mi_row & MAX_MIB_MASK); const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; @@ -939,57 +1117,6 @@ static INLINE int is_chroma_reference(int mi_row, int mi_col, BLOCK_SIZE bsize, return ref_pos; } -static INLINE BLOCK_SIZE scale_chroma_bsize(BLOCK_SIZE bsize, int subsampling_x, - int subsampling_y) { - assert(subsampling_x >= 0 && subsampling_x < 2); - assert(subsampling_y >= 0 && subsampling_y < 2); - BLOCK_SIZE bs = bsize; - switch (bsize) { - case BLOCK_4X4: - if (subsampling_x == 1 && subsampling_y == 1) - bs = BLOCK_8X8; - else if (subsampling_x == 1) - bs = BLOCK_8X4; - else if (subsampling_y == 1) - bs = BLOCK_4X8; - break; - case BLOCK_4X8: - if (subsampling_x == 1 && subsampling_y == 1) - bs = BLOCK_8X8; - else if (subsampling_x == 1) - bs = BLOCK_8X8; - else if (subsampling_y == 1) - bs = BLOCK_4X8; - break; - case BLOCK_8X4: - if (subsampling_x == 1 && subsampling_y == 1) - bs = BLOCK_8X8; - else if (subsampling_x == 1) - bs = BLOCK_8X4; - else if (subsampling_y == 1) - bs = BLOCK_8X8; - break; - case BLOCK_4X16: - if (subsampling_x == 1 && subsampling_y == 1) - bs = BLOCK_8X16; - else if (subsampling_x == 1) - bs = BLOCK_8X16; - else if (subsampling_y == 1) - bs = BLOCK_4X16; - break; - case BLOCK_16X4: - if (subsampling_x == 1 && subsampling_y == 1) - bs = BLOCK_16X8; - else if (subsampling_x == 1) - bs = BLOCK_16X4; - else if (subsampling_y == 1) - bs = BLOCK_16X8; - break; - default: break; - } - return bs; -} - static INLINE aom_cdf_prob cdf_element_prob(const aom_cdf_prob *cdf, size_t element) { assert(cdf != NULL); @@ -1067,9 +1194,9 @@ static INLINE void update_ext_partition_context(MACROBLOCKD *xd, int mi_row, static INLINE int partition_plane_context(const MACROBLOCKD *xd, int mi_row, int mi_col, BLOCK_SIZE bsize) { - const PARTITION_CONTEXT *above_ctx = xd->above_seg_context + mi_col; + const PARTITION_CONTEXT *above_ctx = xd->above_partition_context + mi_col; const PARTITION_CONTEXT *left_ctx = - xd->left_seg_context + (mi_row & MAX_MIB_MASK); + xd->left_partition_context + (mi_row & MAX_MIB_MASK); // Minimum partition point is 8x8. Offset the bsl accordingly. const int bsl = mi_size_wide_log2[bsize] - mi_size_wide_log2[BLOCK_8X8]; int above = (*above_ctx >> bsl) & 1, left = (*left_ctx >> bsl) & 1; @@ -1095,41 +1222,27 @@ static INLINE int max_block_wide(const MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane) { assert(bsize < BLOCK_SIZES_ALL); int max_blocks_wide = block_size_wide[bsize]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (xd->mb_to_right_edge < 0) + if (xd->mb_to_right_edge < 0) { + const struct macroblockd_plane *const pd = &xd->plane[plane]; max_blocks_wide += xd->mb_to_right_edge >> (3 + pd->subsampling_x); + } // Scale the width in the transform block unit. - return max_blocks_wide >> tx_size_wide_log2[0]; + return max_blocks_wide >> MI_SIZE_LOG2; } static INLINE int max_block_high(const MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane) { int max_blocks_high = block_size_high[bsize]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (xd->mb_to_bottom_edge < 0) + if (xd->mb_to_bottom_edge < 0) { + const struct macroblockd_plane *const pd = &xd->plane[plane]; max_blocks_high += xd->mb_to_bottom_edge >> (3 + pd->subsampling_y); + } // Scale the height in the transform block unit. - return max_blocks_high >> tx_size_high_log2[0]; -} - -static INLINE int max_intra_block_width(const MACROBLOCKD *xd, - BLOCK_SIZE plane_bsize, int plane, - TX_SIZE tx_size) { - const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane) - << tx_size_wide_log2[0]; - return ALIGN_POWER_OF_TWO(max_blocks_wide, tx_size_wide_log2[tx_size]); -} - -static INLINE int max_intra_block_height(const MACROBLOCKD *xd, - BLOCK_SIZE plane_bsize, int plane, - TX_SIZE tx_size) { - const int max_blocks_high = max_block_high(xd, plane_bsize, plane) - << tx_size_high_log2[0]; - return ALIGN_POWER_OF_TWO(max_blocks_high, tx_size_high_log2[tx_size]); + return max_blocks_high >> MI_SIZE_LOG2; } static INLINE void av1_zero_above_context(AV1_COMMON *const cm, @@ -1141,32 +1254,36 @@ static INLINE void av1_zero_above_context(AV1_COMMON *const cm, const int width = mi_col_end - mi_col_start; const int aligned_width = ALIGN_POWER_OF_TWO(width, seq_params->mib_size_log2); - const int offset_y = mi_col_start; const int width_y = aligned_width; const int offset_uv = offset_y >> seq_params->subsampling_x; const int width_uv = width_y >> seq_params->subsampling_x; + CommonContexts *const above_contexts = &cm->above_contexts; - av1_zero_array(cm->above_context[0][tile_row] + offset_y, width_y); + av1_zero_array(above_contexts->entropy[0][tile_row] + offset_y, width_y); if (num_planes > 1) { - if (cm->above_context[1][tile_row] && cm->above_context[2][tile_row]) { - av1_zero_array(cm->above_context[1][tile_row] + offset_uv, width_uv); - av1_zero_array(cm->above_context[2][tile_row] + offset_uv, width_uv); + if (above_contexts->entropy[1][tile_row] && + above_contexts->entropy[2][tile_row]) { + av1_zero_array(above_contexts->entropy[1][tile_row] + offset_uv, + width_uv); + av1_zero_array(above_contexts->entropy[2][tile_row] + offset_uv, + width_uv); } else { aom_internal_error(xd->error_info, AOM_CODEC_CORRUPT_FRAME, "Invalid value of planes"); } } - av1_zero_array(cm->above_seg_context[tile_row] + mi_col_start, aligned_width); + av1_zero_array(above_contexts->partition[tile_row] + mi_col_start, + aligned_width); - memset(cm->above_txfm_context[tile_row] + mi_col_start, + memset(above_contexts->txfm[tile_row] + mi_col_start, tx_size_wide[TX_SIZES_LARGEST], aligned_width * sizeof(TXFM_CONTEXT)); } static INLINE void av1_zero_left_context(MACROBLOCKD *const xd) { - av1_zero(xd->left_context); - av1_zero(xd->left_seg_context); + av1_zero(xd->left_entropy_context); + av1_zero(xd->left_partition_context); memset(xd->left_txfm_context_buffer, tx_size_high[TX_SIZES_LARGEST], sizeof(xd->left_txfm_context_buffer)); @@ -1203,26 +1320,33 @@ static INLINE void set_txfm_ctxs(TX_SIZE tx_size, int n4_w, int n4_h, int skip, set_txfm_ctx(xd->left_txfm_context, bh, n4_h); } -static INLINE int get_mi_grid_idx(const AV1_COMMON *cm, int mi_row, +static INLINE int get_mi_grid_idx(const CommonModeInfoParams *const mi_params, + int mi_row, int mi_col) { + return mi_row * mi_params->mi_stride + mi_col; +} + +static INLINE int get_alloc_mi_idx(const CommonModeInfoParams *const mi_params, + int mi_row, int mi_col) { + const int mi_alloc_size_1d = mi_size_wide[mi_params->mi_alloc_bsize]; + const int mi_alloc_row = mi_row / mi_alloc_size_1d; + const int mi_alloc_col = mi_col / mi_alloc_size_1d; + + return mi_alloc_row * mi_params->mi_alloc_stride + mi_alloc_col; +} + +// For this partition block, set pointers in mi_params->mi_grid_base and xd->mi. +static INLINE void set_mi_offsets(const CommonModeInfoParams *const mi_params, + MACROBLOCKD *const xd, int mi_row, int mi_col) { - return mi_row * cm->mi_stride + mi_col; -} - -static INLINE int get_alloc_mi_idx(const AV1_COMMON *cm, int mi_row, - int mi_col) { - const int mi_alloc_size_1d = mi_size_wide[cm->mi_alloc_bsize]; - const int mi_alloc_row = mi_row / mi_alloc_size_1d; - const int mi_alloc_col = mi_col / mi_alloc_size_1d; - - return mi_alloc_row * cm->mi_alloc_stride + mi_alloc_col; -} - -static INLINE int get_mi_ext_idx(const AV1_COMMON *cm, int mi_row, int mi_col) { - const int mi_alloc_size_1d = mi_size_wide[cm->mi_alloc_bsize]; - const int mi_alloc_row = mi_row / mi_alloc_size_1d; - const int mi_alloc_col = mi_col / mi_alloc_size_1d; - - return mi_alloc_row * cm->mi_alloc_cols + mi_alloc_col; + // 'mi_grid_base' should point to appropriate memory in 'mi'. + const int mi_grid_idx = get_mi_grid_idx(mi_params, mi_row, mi_col); + const int mi_alloc_idx = get_alloc_mi_idx(mi_params, mi_row, mi_col); + mi_params->mi_grid_base[mi_grid_idx] = &mi_params->mi_alloc[mi_alloc_idx]; + // 'xd->mi' should point to an offset in 'mi_grid_base'; + xd->mi = mi_params->mi_grid_base + mi_grid_idx; + // 'xd->tx_type_map' should point to an offset in 'mi_params->tx_type_map'. + xd->tx_type_map = mi_params->tx_type_map + mi_grid_idx; + xd->tx_type_map_stride = mi_params->mi_stride; } static INLINE void txfm_partition_update(TXFM_CONTEXT *above_ctx, @@ -1317,10 +1441,12 @@ static INLINE int txfm_partition_context(const TXFM_CONTEXT *const above_ctx, static INLINE PARTITION_TYPE get_partition(const AV1_COMMON *const cm, int mi_row, int mi_col, BLOCK_SIZE bsize) { - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return PARTITION_INVALID; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) + return PARTITION_INVALID; - const int offset = mi_row * cm->mi_stride + mi_col; - MB_MODE_INFO **mi = cm->mi_grid_base + offset; + const int offset = mi_row * mi_params->mi_stride + mi_col; + MB_MODE_INFO **mi = mi_params->mi_grid_base + offset; const BLOCK_SIZE subsize = mi[0]->sb_type; if (subsize == bsize) return PARTITION_NONE; @@ -1330,12 +1456,12 @@ static INLINE PARTITION_TYPE get_partition(const AV1_COMMON *const cm, const int sshigh = mi_size_high[subsize]; const int sswide = mi_size_wide[subsize]; - if (bsize > BLOCK_8X8 && mi_row + bwide / 2 < cm->mi_rows && - mi_col + bhigh / 2 < cm->mi_cols) { + if (bsize > BLOCK_8X8 && mi_row + bwide / 2 < mi_params->mi_rows && + mi_col + bhigh / 2 < mi_params->mi_cols) { // In this case, the block might be using an extended partition // type. const MB_MODE_INFO *const mbmi_right = mi[bwide / 2]; - const MB_MODE_INFO *const mbmi_below = mi[bhigh / 2 * cm->mi_stride]; + const MB_MODE_INFO *const mbmi_below = mi[bhigh / 2 * mi_params->mi_stride]; if (sswide == bwide) { // Smaller height but same width. Is PARTITION_HORZ_4, PARTITION_HORZ or @@ -1424,22 +1550,8 @@ static INLINE int is_valid_seq_level_idx(AV1_LEVEL seq_level_idx) { seq_level_idx != SEQ_LEVEL_7_2 && seq_level_idx != SEQ_LEVEL_7_3); } -static INLINE void init_frame_info(FRAME_INFO *frame_info, - AV1_COMMON *const cm) { - frame_info->frame_width = cm->width; - frame_info->frame_height = cm->height; - frame_info->mi_cols = cm->mi_cols; - frame_info->mi_rows = cm->mi_rows; - frame_info->mb_cols = cm->mb_cols; - frame_info->mb_rows = cm->mb_rows; - frame_info->num_mbs = cm->MBs; - frame_info->bit_depth = cm->seq_params.bit_depth; - frame_info->subsampling_x = cm->seq_params.subsampling_x; - frame_info->subsampling_y = cm->seq_params.subsampling_y; -} - #ifdef __cplusplus } // extern "C" #endif -#endif // AOM_AV1_COMMON_ONYXC_INT_H_ +#endif // AOM_AV1_COMMON_AV1_COMMON_INT_H_ diff --git a/media/libaom/src/av1/common/av1_inv_txfm1d.c b/media/libaom/src/av1/common/av1_inv_txfm1d.c index 7ef2d6d7fa..8d69efcd2d 100644 --- a/media/libaom/src/av1/common/av1_inv_txfm1d.c +++ b/media/libaom/src/av1/common/av1_inv_txfm1d.c @@ -13,11 +13,8 @@ #include "av1/common/av1_inv_txfm1d.h" #include "av1/common/av1_txfm.h" -// TODO(angiebird): Make 1-d txfm functions static -// - -void av1_idct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_idct4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 4; const int32_t *cospi = cospi_arr(cos_bit); @@ -57,8 +54,8 @@ void av1_idct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, bf1[3] = clamp_value(bf0[0] - bf0[3], stage_range[stage]); } -void av1_idct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_idct8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 8; const int32_t *cospi = cospi_arr(cos_bit); @@ -138,8 +135,8 @@ void av1_idct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, bf1[7] = clamp_value(bf0[0] - bf0[7], stage_range[stage]); } -void av1_idct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_idct16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 16; const int32_t *cospi = cospi_arr(cos_bit); @@ -303,8 +300,8 @@ void av1_idct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, bf1[15] = clamp_value(bf0[0] - bf0[15], stage_range[stage]); } -void av1_idct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_idct32(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 32; const int32_t *cospi = cospi_arr(cos_bit); @@ -656,8 +653,8 @@ void av1_idct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, bf1[31] = clamp_value(bf0[0] - bf0[31], stage_range[stage]); } -void av1_iadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_iadst4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { int bit = cos_bit; const int32_t *sinpi = sinpi_arr(bit); int32_t s0, s1, s2, s3, s4, s5, s6, s7; @@ -713,8 +710,8 @@ void av1_iadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, output[3] = round_shift(x3, bit); } -void av1_iadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_iadst8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 8; const int32_t *cospi = cospi_arr(cos_bit); @@ -809,7 +806,6 @@ void av1_iadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); // stage 7 - stage++; bf0 = step; bf1 = output; bf1[0] = bf0[0]; @@ -822,8 +818,8 @@ void av1_iadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, bf1[7] = -bf0[1]; } -void av1_iadst16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_iadst16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 16; const int32_t *cospi = cospi_arr(cos_bit); @@ -1010,7 +1006,6 @@ void av1_iadst16_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); // stage 9 - stage++; bf0 = step; bf1 = output; bf1[0] = bf0[0]; @@ -1064,8 +1059,8 @@ void av1_iidentity32_c(const int32_t *input, int32_t *output, int8_t cos_bit, for (int i = 0; i < 32; ++i) output[i] = (int32_t)((int64_t)input[i] * 4); } -void av1_idct64_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_idct64(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { assert(output != input); const int32_t size = 64; const int32_t *cospi = cospi_arr(cos_bit); diff --git a/media/libaom/src/av1/common/av1_inv_txfm1d.h b/media/libaom/src/av1/common/av1_inv_txfm1d.h index c31c019aa9..e1d5d98d10 100644 --- a/media/libaom/src/av1/common/av1_inv_txfm1d.h +++ b/media/libaom/src/av1/common/av1_inv_txfm1d.h @@ -29,22 +29,22 @@ static INLINE void clamp_buf(int32_t *buf, int32_t size, int8_t bit) { for (int i = 0; i < size; ++i) buf[i] = clamp_value(buf[i], bit); } -void av1_idct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_idct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_idct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_idct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_idct64_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_iadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_iadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_iadst16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); +void av1_idct4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_idct8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_idct16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_idct32(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_idct64(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_iadst4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_iadst8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_iadst16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); void av1_iidentity4_c(const int32_t *input, int32_t *output, int8_t cos_bit, const int8_t *stage_range); void av1_iidentity8_c(const int32_t *input, int32_t *output, int8_t cos_bit, diff --git a/media/libaom/src/av1/common/av1_inv_txfm2d.c b/media/libaom/src/av1/common/av1_inv_txfm2d.c index 92486aa482..559d12129e 100644 --- a/media/libaom/src/av1/common/av1_inv_txfm2d.c +++ b/media/libaom/src/av1/common/av1_inv_txfm2d.c @@ -113,14 +113,14 @@ void av1_highbd_iwht4x4_1_add_c(const tran_low_t *in, uint8_t *dest8, static INLINE TxfmFunc inv_txfm_type_to_func(TXFM_TYPE txfm_type) { switch (txfm_type) { - case TXFM_TYPE_DCT4: return av1_idct4_new; - case TXFM_TYPE_DCT8: return av1_idct8_new; - case TXFM_TYPE_DCT16: return av1_idct16_new; - case TXFM_TYPE_DCT32: return av1_idct32_new; - case TXFM_TYPE_DCT64: return av1_idct64_new; - case TXFM_TYPE_ADST4: return av1_iadst4_new; - case TXFM_TYPE_ADST8: return av1_iadst8_new; - case TXFM_TYPE_ADST16: return av1_iadst16_new; + case TXFM_TYPE_DCT4: return av1_idct4; + case TXFM_TYPE_DCT8: return av1_idct8; + case TXFM_TYPE_DCT16: return av1_idct16; + case TXFM_TYPE_DCT32: return av1_idct32; + case TXFM_TYPE_DCT64: return av1_idct64; + case TXFM_TYPE_ADST4: return av1_iadst4; + case TXFM_TYPE_ADST8: return av1_iadst8; + case TXFM_TYPE_ADST16: return av1_iadst16; case TXFM_TYPE_IDENTITY4: return av1_iidentity4_c; case TXFM_TYPE_IDENTITY8: return av1_iidentity8_c; case TXFM_TYPE_IDENTITY16: return av1_iidentity16_c; diff --git a/media/libaom/src/av1/common/av1_loopfilter.c b/media/libaom/src/av1/common/av1_loopfilter.c index 6e38a9e8f0..c756760def 100644 --- a/media/libaom/src/av1/common/av1_loopfilter.c +++ b/media/libaom/src/av1/common/av1_loopfilter.c @@ -17,8 +17,8 @@ #include "aom_dsp/aom_dsp_common.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/av1_loopfilter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" #include "av1/common/seg_common.h" @@ -256,7 +256,8 @@ static TX_SIZE set_lpf_parameters( // and mi_col should be odd number for chroma plane. const int mi_row = scale_vert | ((y << scale_vert) >> MI_SIZE_LOG2); const int mi_col = scale_horz | ((x << scale_horz) >> MI_SIZE_LOG2); - MB_MODE_INFO **mi = cm->mi_grid_base + mi_row * cm->mi_stride + mi_col; + MB_MODE_INFO **mi = + cm->mi_params.mi_grid_base + mi_row * cm->mi_params.mi_stride + mi_col; const MB_MODE_INFO *mbmi = mi[0]; // If current mbmi is not correctly setup, return an invalid value to stop // filtering. One example is that if this tile is not coded, then its mbmi @@ -479,9 +480,9 @@ void av1_filter_block_plane_horz(const AV1_COMMON *const cm, AV1_DEBLOCKING_PARAMETERS params; memset(¶ms, 0, sizeof(params)); - tx_size = - set_lpf_parameters(¶ms, (cm->mi_stride << scale_vert), cm, xd, - HORZ_EDGE, curr_x, curr_y, plane, plane_ptr); + tx_size = set_lpf_parameters( + ¶ms, (cm->mi_params.mi_stride << scale_vert), cm, xd, HORZ_EDGE, + curr_x, curr_y, plane, plane_ptr); if (tx_size == TX_INVALID) { params.filter_length = 0; tx_size = TX_4X4; @@ -581,8 +582,8 @@ void av1_filter_block_plane_vert_test(const AV1_COMMON *const cm, const uint32_t scale_vert = plane_ptr->subsampling_y; uint8_t *const dst_ptr = plane_ptr->dst.buf; const int dst_stride = plane_ptr->dst.stride; - const int y_range = cm->mi_rows >> scale_vert; - const int x_range = cm->mi_cols >> scale_horz; + const int y_range = cm->mi_params.mi_rows >> scale_vert; + const int x_range = cm->mi_params.mi_cols >> scale_horz; for (int y = 0; y < y_range; y++) { uint8_t *p = dst_ptr + y * MI_SIZE * dst_stride; for (int x = 0; x < x_range;) { @@ -623,8 +624,8 @@ void av1_filter_block_plane_horz_test(const AV1_COMMON *const cm, const uint32_t scale_vert = plane_ptr->subsampling_y; uint8_t *const dst_ptr = plane_ptr->dst.buf; const int dst_stride = plane_ptr->dst.stride; - const int y_range = cm->mi_rows >> scale_vert; - const int x_range = cm->mi_cols >> scale_horz; + const int y_range = cm->mi_params.mi_rows >> scale_vert; + const int x_range = cm->mi_params.mi_cols >> scale_horz; for (int x = 0; x < x_range; x++) { uint8_t *p = dst_ptr + x * MI_SIZE; for (int y = 0; y < y_range;) { @@ -639,9 +640,9 @@ void av1_filter_block_plane_horz_test(const AV1_COMMON *const cm, AV1_DEBLOCKING_PARAMETERS params; memset(¶ms, 0, sizeof(params)); - tx_size = - set_lpf_parameters(¶ms, (cm->mi_stride << scale_vert), cm, xd, - HORZ_EDGE, curr_x, curr_y, plane, plane_ptr); + tx_size = set_lpf_parameters( + ¶ms, (cm->mi_params.mi_stride << scale_vert), cm, xd, HORZ_EDGE, + curr_x, curr_y, plane, plane_ptr); if (tx_size == TX_INVALID) { params.filter_length = 0; tx_size = TX_4X4; @@ -663,7 +664,7 @@ static void loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer, AV1_COMMON *cm, int plane_start, int plane_end) { struct macroblockd_plane *pd = xd->plane; const int col_start = 0; - const int col_end = cm->mi_cols; + const int col_end = cm->mi_params.mi_cols; int mi_row, mi_col; int plane; @@ -773,11 +774,11 @@ void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int start_mi_row, end_mi_row, mi_rows_to_filter; start_mi_row = 0; - mi_rows_to_filter = cm->mi_rows; - if (partial_frame && cm->mi_rows > 8) { - start_mi_row = cm->mi_rows >> 1; + mi_rows_to_filter = cm->mi_params.mi_rows; + if (partial_frame && cm->mi_params.mi_rows > 8) { + start_mi_row = cm->mi_params.mi_rows >> 1; start_mi_row &= 0xfffffff8; - mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8); + mi_rows_to_filter = AOMMAX(cm->mi_params.mi_rows / 8, 8); } end_mi_row = start_mi_row + mi_rows_to_filter; av1_loop_filter_frame_init(cm, plane_start, plane_end); diff --git a/media/libaom/src/av1/common/av1_rtcd_defs.pl b/media/libaom/src/av1/common/av1_rtcd_defs.pl index 7a5a0e52d0..296c6c572d 100644 --- a/media/libaom/src/av1/common/av1_rtcd_defs.pl +++ b/media/libaom/src/av1/common/av1_rtcd_defs.pl @@ -214,9 +214,16 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { add_proto qw/int64_t av1_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz"; specialize qw/av1_block_error sse2 avx2 neon/; + add_proto qw/int64_t av1_block_error_lp/, "const int16_t *coeff, const int16_t *dqcoeff, intptr_t block_size"; + specialize qw/av1_block_error_lp avx2 neon/; + add_proto qw/void av1_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"; specialize qw/av1_quantize_fp sse2 avx2 neon/; + add_proto qw/void av1_quantize_lp/, "const int16_t *coeff_ptr, intptr_t n_coeffs, const int16_t *round_ptr, const int16_t *quant_ptr, int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan"; + specialize qw/av1_quantize_lp avx2 neon/; + + add_proto qw/void av1_quantize_fp_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/av1_quantize_fp_32x32 avx2/; @@ -274,15 +281,17 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { # # Motion search # - add_proto qw/int av1_diamond_search_sad/, "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"; - 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"; if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") { - 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_apply_temporal_filter_yuv/, "const struct yv12_buffer_config *ref_frame, const struct macroblockd *mbd, const BLOCK_SIZE block_size, const int mb_row, const int mb_col, const int num_planes, const int strength, const int use_subblock, const int *subblock_filter_weights, const uint8_t *pred, uint32_t *accum, uint16_t *count"; + specialize qw/av1_apply_temporal_filter_yuv sse4_1/; } + if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") { + add_proto qw/void av1_apply_temporal_filter_planewise/, "const struct yv12_buffer_config *ref_frame, const struct macroblockd *mbd, const BLOCK_SIZE block_size, const int mb_row, const int mb_col, const int num_planes, const double *noise_levels, const int use_subblock, const int block_mse, const int *subblock_mses, const int q_factor, const uint8_t *pred, uint32_t *accum, uint16_t *count"; + specialize qw/av1_apply_temporal_filter_planewise sse2 avx2/; + } 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 @@ -291,11 +300,6 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { specialize qw/av1_highbd_block_error sse2 avx2/; } - if (aom_config("CONFIG_REALTIME_ONLY") ne "yes") { - 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/; - } - if (aom_config("CONFIG_AV1_HIGHBITDEPTH") eq "yes") { 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/; @@ -396,16 +400,12 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") { # LOOP_RESTORATION functions add_proto qw/void av1_apply_selfguided_restoration/, "const uint8_t *dat, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf, int bit_depth, int highbd"; -# TODO(b/141858830,b/141859709): neon is currently disabled due to use of -# uninitialized memory. -specialize qw/av1_apply_selfguided_restoration sse4_1 avx2/; +specialize qw/av1_apply_selfguided_restoration sse4_1 avx2 neon/; add_proto qw/int av1_selfguided_restoration/, "const uint8_t *dgd8, int width, int height, int dgd_stride, int32_t *flt0, int32_t *flt1, int flt_stride, int sgr_params_idx, int bit_depth, int highbd"; -# TODO(b/141858830,b/141859709): neon is currently disabled due to use of -# uninitialized memory. -specialize qw/av1_selfguided_restoration sse4_1 avx2/; +specialize qw/av1_selfguided_restoration sse4_1 avx2 neon/; # CONVOLVE_ROUND/COMPOUND_ROUND functions diff --git a/media/libaom/src/av1/common/blockd.c b/media/libaom/src/av1/common/blockd.c index d29ed4c23d..00725ea2d6 100644 --- a/media/libaom/src/av1/common/blockd.c +++ b/media/libaom/src/av1/common/blockd.c @@ -13,8 +13,8 @@ #include "aom_ports/system_state.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" PREDICTION_MODE av1_left_block_mode(const MB_MODE_INFO *left_mi) { if (!left_mi) return DC_PRED; @@ -28,11 +28,12 @@ PREDICTION_MODE av1_above_block_mode(const MB_MODE_INFO *above_mi) { return above_mi->mode; } -void av1_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd, - int plane, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - int has_eob, int aoff, int loff) { - ENTROPY_CONTEXT *const a = pd->above_context + aoff; - ENTROPY_CONTEXT *const l = pd->left_context + loff; +void av1_set_entropy_contexts(const MACROBLOCKD *xd, + struct macroblockd_plane *pd, int plane, + BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + int has_eob, int aoff, int loff) { + ENTROPY_CONTEXT *const a = pd->above_entropy_context + aoff; + ENTROPY_CONTEXT *const l = pd->left_entropy_context + loff; const int txs_wide = tx_size_wide_unit[tx_size]; const int txs_high = tx_size_high_unit[tx_size]; @@ -56,25 +57,18 @@ void av1_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd, memset(l, has_eob, sizeof(*l) * txs_high); } } -void av1_reset_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col, - BLOCK_SIZE bsize, const int num_planes) { - int i; - int nplanes; - int chroma_ref; +void av1_reset_entropy_context(MACROBLOCKD *xd, BLOCK_SIZE bsize, + const int num_planes) { assert(bsize < BLOCK_SIZES_ALL); - - chroma_ref = - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y); - nplanes = 1 + (num_planes - 1) * chroma_ref; - for (i = 0; i < nplanes; i++) { + const int nplanes = 1 + (num_planes - 1) * xd->is_chroma_ref; + for (int i = 0; i < nplanes; i++) { struct macroblockd_plane *const pd = &xd->plane[i]; const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - const int txs_wide = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int txs_high = block_size_high[plane_bsize] >> tx_size_high_log2[0]; - memset(pd->above_context, 0, sizeof(ENTROPY_CONTEXT) * txs_wide); - memset(pd->left_context, 0, sizeof(ENTROPY_CONTEXT) * txs_high); + const int txs_wide = mi_size_wide[plane_bsize]; + const int txs_high = mi_size_high[plane_bsize]; + memset(pd->above_entropy_context, 0, sizeof(ENTROPY_CONTEXT) * txs_wide); + memset(pd->left_entropy_context, 0, sizeof(ENTROPY_CONTEXT) * txs_high); } } diff --git a/media/libaom/src/av1/common/blockd.h b/media/libaom/src/av1/common/blockd.h index 4c57628a3a..47597bc834 100644 --- a/media/libaom/src/av1/common/blockd.h +++ b/media/libaom/src/av1/common/blockd.h @@ -75,24 +75,24 @@ static INLINE int is_inter_compound_mode(PREDICTION_MODE mode) { } static INLINE PREDICTION_MODE compound_ref0_mode(PREDICTION_MODE mode) { - static PREDICTION_MODE lut[] = { - MB_MODE_COUNT, // DC_PRED - MB_MODE_COUNT, // V_PRED - MB_MODE_COUNT, // H_PRED - MB_MODE_COUNT, // D45_PRED - MB_MODE_COUNT, // D135_PRED - MB_MODE_COUNT, // D113_PRED - MB_MODE_COUNT, // D157_PRED - MB_MODE_COUNT, // D203_PRED - MB_MODE_COUNT, // D67_PRED - MB_MODE_COUNT, // SMOOTH_PRED - MB_MODE_COUNT, // SMOOTH_V_PRED - MB_MODE_COUNT, // SMOOTH_H_PRED - MB_MODE_COUNT, // PAETH_PRED - MB_MODE_COUNT, // NEARESTMV - MB_MODE_COUNT, // NEARMV - MB_MODE_COUNT, // GLOBALMV - MB_MODE_COUNT, // NEWMV + static const PREDICTION_MODE lut[] = { + DC_PRED, // DC_PRED + V_PRED, // V_PRED + H_PRED, // H_PRED + D45_PRED, // D45_PRED + D135_PRED, // D135_PRED + D113_PRED, // D113_PRED + D157_PRED, // D157_PRED + D203_PRED, // D203_PRED + D67_PRED, // D67_PRED + SMOOTH_PRED, // SMOOTH_PRED + SMOOTH_V_PRED, // SMOOTH_V_PRED + SMOOTH_H_PRED, // SMOOTH_H_PRED + PAETH_PRED, // PAETH_PRED + NEARESTMV, // NEARESTMV + NEARMV, // NEARMV + GLOBALMV, // GLOBALMV + NEWMV, // NEWMV NEARESTMV, // NEAREST_NEARESTMV NEARMV, // NEAR_NEARMV NEARESTMV, // NEAREST_NEWMV @@ -103,12 +103,12 @@ static INLINE PREDICTION_MODE compound_ref0_mode(PREDICTION_MODE mode) { NEWMV, // NEW_NEWMV }; assert(NELEMENTS(lut) == MB_MODE_COUNT); - assert(is_inter_compound_mode(mode)); + assert(is_inter_compound_mode(mode) || is_inter_singleref_mode(mode)); return lut[mode]; } static INLINE PREDICTION_MODE compound_ref1_mode(PREDICTION_MODE mode) { - static PREDICTION_MODE lut[] = { + static const PREDICTION_MODE lut[] = { MB_MODE_COUNT, // DC_PRED MB_MODE_COUNT, // V_PRED MB_MODE_COUNT, // H_PRED @@ -361,9 +361,9 @@ static INLINE void mi_to_pixel_loc(int *pixel_c, int *pixel_r, int mi_col, int mi_row, int tx_blk_col, int tx_blk_row, int subsampling_x, int subsampling_y) { *pixel_c = ((mi_col >> subsampling_x) << MI_SIZE_LOG2) + - (tx_blk_col << tx_size_wide_log2[0]); + (tx_blk_col << MI_SIZE_LOG2); *pixel_r = ((mi_row >> subsampling_y) << MI_SIZE_LOG2) + - (tx_blk_row << tx_size_high_log2[0]); + (tx_blk_row << MI_SIZE_LOG2); } #endif @@ -398,8 +398,8 @@ typedef struct macroblockd_plane { int subsampling_y; struct buf_2d dst; struct buf_2d pre[2]; - ENTROPY_CONTEXT *above_context; - ENTROPY_CONTEXT *left_context; + ENTROPY_CONTEXT *above_entropy_context; + ENTROPY_CONTEXT *left_entropy_context; // The dequantizers below are true dequantizers used only in the // dequantization process. They have the same coefficient @@ -414,8 +414,7 @@ typedef struct macroblockd_plane { qm_val_t *seg_qmatrix[MAX_SEGMENTS][TX_SIZES_ALL]; } MACROBLOCKD_PLANE; -#define BLOCK_OFFSET(i) \ - ((i) * (1 << (tx_size_wide_log2[0] + tx_size_high_log2[0]))) +#define BLOCK_OFFSET(i) ((i) << 4) typedef struct { DECLARE_ALIGNED(16, InterpKernel, vfilter); @@ -460,16 +459,12 @@ typedef struct cfl_ctx { // Chroma subsampling int subsampling_x, subsampling_y; - int mi_row, mi_col; - // Whether the reconstructed luma pixels need to be stored int store_y; #if CONFIG_DEBUG int rate; #endif // CONFIG_DEBUG - - int is_chroma_reference; } CFL_CTX; typedef struct dist_wtd_comp_params { @@ -483,53 +478,125 @@ struct scale_factors; // Most/all of the pointers are mere pointers to actual arrays are allocated // elsewhere. This is mostly for coding convenience. typedef struct macroblockd { + // Row and column position of current macroblock in mi units. + int mi_row; + int mi_col; + // Same as cm->mi_params.mi_stride, copied here for convenience. + int mi_stride; + + // True if current block transmits chroma information. + // More detail: + // Smallest supported block size for both luma and chroma plane is 4x4. Hence, + // in case of subsampled chroma plane (YUV 4:2:0 or YUV 4:2:2), multiple luma + // blocks smaller than 8x8 maybe combined into one chroma block. + // For example, for YUV 4:2:0, let's say an 8x8 area is split into four 4x4 + // luma blocks. Then, a single chroma block of size 4x4 will cover the area of + // these four luma blocks. This is implemented in bitstream as follows: + // - There are four MB_MODE_INFO structs for the four luma blocks. + // - First 3 MB_MODE_INFO have is_chroma_ref = false, and so do not transmit + // any information for chroma planes. + // - Last block will have is_chroma_ref = true and transmits chroma + // information for the 4x4 chroma block that covers whole 8x8 area covered by + // four luma blocks. + // Similar logic applies for chroma blocks that cover 2 or 3 luma blocks. + bool is_chroma_ref; + struct macroblockd_plane plane[MAX_MB_PLANE]; TileInfo tile; - int mi_stride; - + // Appropriate offset inside cm->mi_params.mi_grid_base based on current + // mi_row and mi_col. MB_MODE_INFO **mi; + + // True if 4x4 block above the current block is available. + bool up_available; + // True if 4x4 block to the left of the current block is available. + bool left_available; + // True if the above chrome reference block is available. + bool chroma_up_available; + // True if the left chrome reference block is available. + bool chroma_left_available; + + // MB_MODE_INFO for 4x4 block to the left of the current block, if + // left_available == true; otherwise NULL. MB_MODE_INFO *left_mbmi; + // MB_MODE_INFO for 4x4 block above the current block, if + // up_available == true; otherwise NULL. MB_MODE_INFO *above_mbmi; + // Above chroma reference block if is_chroma_ref == true for the current block + // and chroma_up_available == true; otherwise NULL. + // See also: the special case logic when current chroma block covers more than + // one luma blocks in set_mi_row_col(). MB_MODE_INFO *chroma_left_mbmi; + // Left chroma reference block if is_chroma_ref == true for the current block + // and chroma_left_available == true; otherwise NULL. + // See also: the special case logic when current chroma block covers more than + // one luma blocks in set_mi_row_col(). MB_MODE_INFO *chroma_above_mbmi; + // Appropriate offset based on current 'mi_row' and 'mi_col', inside + // 'tx_type_map' in one of 'CommonModeInfoParams', 'PICK_MODE_CONTEXT' or + // 'MACROBLOCK' structs. uint8_t *tx_type_map; + // Stride for 'tx_type_map'. Note that this may / may not be same as + // 'mi_stride', depending on which actual array 'tx_type_map' points to. int tx_type_map_stride; - int up_available; - int left_available; - int chroma_up_available; - int chroma_left_available; - - /* Distance of MB away from frame edges in subpixels (1/8th pixel) */ + // Distance of this macroblock from frame edges in 1/8th pixel units. int mb_to_left_edge; int mb_to_right_edge; int mb_to_top_edge; int mb_to_bottom_edge; - /* pointers to reference frame scale factors */ + // Scale factors for reference frames of the current block. + // These are pointers into 'cm->ref_scale_factors'. const struct scale_factors *block_ref_scale_factors[2]; - /* pointer to current frame */ const YV12_BUFFER_CONFIG *cur_buf; - ENTROPY_CONTEXT *above_context[MAX_MB_PLANE]; - ENTROPY_CONTEXT left_context[MAX_MB_PLANE][MAX_MIB_SIZE]; + // Entropy contexts for the above blocks. + // above_entropy_context[i][j] corresponds to above entropy context for ith + // plane and jth mi column of this *frame*, wrt current 'mi_row'. + // These are pointers into 'cm->above_contexts.entropy'. + ENTROPY_CONTEXT *above_entropy_context[MAX_MB_PLANE]; + // Entropy contexts for the left blocks. + // left_entropy_context[i][j] corresponds to left entropy context for ith + // plane and jth mi row of this *superblock*, wrt current 'mi_col'. + // Note: These contain actual data, NOT pointers. + ENTROPY_CONTEXT left_entropy_context[MAX_MB_PLANE][MAX_MIB_SIZE]; - PARTITION_CONTEXT *above_seg_context; - PARTITION_CONTEXT left_seg_context[MAX_MIB_SIZE]; + // Partition contexts for the above blocks. + // above_partition_context[i] corresponds to above partition context for ith + // mi column of this *frame*, wrt current 'mi_row'. + // These are pointers into 'cm->above_contexts.partition'. + PARTITION_CONTEXT *above_partition_context; + // Partition contexts for the left blocks. + // left_partition_context[i] corresponds to left partition context for ith + // mi row of this *superblock*, wrt current 'mi_col'. + // Note: These contain actual data, NOT pointers. + PARTITION_CONTEXT left_partition_context[MAX_MIB_SIZE]; + // Transform contexts for the above blocks. + // TODO(urvang): Indexed two different ways from cm->above_contexts.txfm in + // code currently. Need to make it consistent / document why. TXFM_CONTEXT *above_txfm_context; + // Transform contexts for the left blocks. TXFM_CONTEXT *left_txfm_context; + // TODO(urvang): 'left_txfm_context' points to 'left_txfm_context_buffer'. + // Can we remove this indirection? TXFM_CONTEXT left_txfm_context_buffer[MAX_MIB_SIZE]; + // Default values for the two restoration filters for each plane. + // These values are used as reference values when writing the bitstream. That + // is, we transmit the delta between the actual values in + // cm->rst_info[plane].unit_info[unit_idx] and these reference values. WienerInfo wiener_info[MAX_MB_PLANE]; SgrprojInfo sgrproj_info[MAX_MB_PLANE]; - // block dimension in the unit of mode_info. - uint8_t n4_w, n4_h; + // Block dimensions in MB_MODE_INFO units. + uint8_t width; + uint8_t height; uint8_t ref_mv_count[MODE_CTX_REF_FRAMES]; CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE]; @@ -541,15 +608,18 @@ typedef struct macroblockd { uint8_t neighbors_ref_counts[REF_FRAMES]; FRAME_CONTEXT *tile_ctx; - /* Bit depth: 8, 10, 12 */ + // Bit depth: copied from cm->seq_params.bit_depth for convenience. int bd; int qindex[MAX_SEGMENTS]; int lossless[MAX_SEGMENTS]; + // TODO(urvang): Move to decoder. int corrupted; + // Same as cm->features.cur_frame_force_integer_mv. int cur_frame_force_integer_mv; - // same with that in AV1_COMMON + // Pointer to cm->error. struct aom_internal_error_info *error_info; + // Same as cm->global_motion. const WarpedMotionParams *global_motion; int delta_qindex; int current_qindex; @@ -574,7 +644,20 @@ typedef struct macroblockd { // SEG_LVL_ALT_LF_U = 3; // SEG_LVL_ALT_LF_V = 4; int8_t delta_lf[FRAME_LF_COUNT]; - int cdef_preset[4]; + // cdef_transmitted[i] is true if CDEF strength for ith CDEF unit in the + // current superblock has already been read from (decoder) / written to + // (encoder) the bitstream; and false otherwise. + // More detail: + // (1) CDEF strength is transmitted only once per CDEF unit, in the 1st + // non-skip coding block. So, we need this array to keep track of whether CDEF + // strengths for the given CDEF units have been transmitted yet or not. + // (2) Superblock size can be either 128x128 or 64x64, but CDEF unit size is + // fixed to be 64x64. So, there may be 4 CDEF units within a superblock (if + // superblock size is 128x128). Hence the array size is 4. + // (3) In the current implementation, CDEF strength for this CDEF unit is + // stored in the MB_MODE_INFO of the 1st block in this CDEF unit (inside + // cm->mi_params.mi_grid_base). + bool cdef_transmitted[4]; DECLARE_ALIGNED(16, uint8_t, seg_mask[2 * MAX_SB_SQUARE]); uint8_t *mc_buf[2]; @@ -796,7 +879,7 @@ static INLINE TX_TYPE get_default_tx_type(PLANE_TYPE plane_type, static INLINE BLOCK_SIZE get_plane_block_size(BLOCK_SIZE bsize, int subsampling_x, int subsampling_y) { - if (bsize == BLOCK_INVALID) return BLOCK_INVALID; + assert(bsize < BLOCK_SIZES_ALL); assert(subsampling_x >= 0 && subsampling_x < 2); assert(subsampling_y >= 0 && subsampling_y < 2); return ss_size_lookup[bsize][subsampling_x][subsampling_y]; @@ -952,6 +1035,7 @@ static INLINE int bsize_to_max_depth(BLOCK_SIZE bsize) { * assert(depth < 10); */ static INLINE int bsize_to_tx_size_cat(BLOCK_SIZE bsize) { + assert(bsize < BLOCK_SIZES_ALL); static const uint8_t bsize_to_tx_size_depth_table[BLOCK_SIZES_ALL] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 3, 3, 4, 4, }; @@ -996,8 +1080,8 @@ static INLINE TX_SIZE av1_get_tx_size(int plane, const MACROBLOCKD *xd) { pd->subsampling_y); } -void av1_reset_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col, - BLOCK_SIZE bsize, const int num_planes); +void av1_reset_entropy_context(MACROBLOCKD *xd, BLOCK_SIZE bsize, + const int num_planes); void av1_reset_loop_filter_delta(MACROBLOCKD *xd, int num_planes); @@ -1008,9 +1092,10 @@ typedef void (*foreach_transformed_block_visitor)(int plane, int block, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg); -void av1_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd, - int plane, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - int has_eob, int aoff, int loff); +void av1_set_entropy_contexts(const MACROBLOCKD *xd, + struct macroblockd_plane *pd, int plane, + BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + int has_eob, int aoff, int loff); #define MAX_INTERINTRA_SB_SQUARE 32 * 32 static INLINE int is_interintra_mode(const MB_MODE_INFO *mbmi) { diff --git a/media/libaom/src/av1/common/cdef.c b/media/libaom/src/av1/common/cdef.c index 8c6375f9bc..ef7b866b5d 100644 --- a/media/libaom/src/av1/common/cdef.c +++ b/media/libaom/src/av1/common/cdef.c @@ -16,9 +16,9 @@ #include "config/aom_scale_rtcd.h" #include "aom/aom_integer.h" +#include "av1/common/av1_common_int.h" #include "av1/common/cdef.h" #include "av1/common/cdef_block.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" static int is_8x8_block_skip(MB_MODE_INFO **grid, int mi_row, int mi_col, @@ -33,11 +33,12 @@ static int is_8x8_block_skip(MB_MODE_INFO **grid, int mi_row, int mi_col, return 1; } -int av1_cdef_compute_sb_list(const AV1_COMMON *const cm, int mi_row, int mi_col, - cdef_list *dlist, BLOCK_SIZE bs) { - MB_MODE_INFO **grid = cm->mi_grid_base; - int maxc = cm->mi_cols - mi_col; - int maxr = cm->mi_rows - mi_row; +int av1_cdef_compute_sb_list(const CommonModeInfoParams *const mi_params, + int mi_row, int mi_col, cdef_list *dlist, + BLOCK_SIZE bs) { + MB_MODE_INFO **grid = mi_params->mi_grid_base; + int maxc = mi_params->mi_cols - mi_col; + int maxr = mi_params->mi_rows - mi_row; if (bs == BLOCK_128X128 || bs == BLOCK_128X64) maxc = AOMMIN(maxc, MI_SIZE_128X128); @@ -55,7 +56,8 @@ int av1_cdef_compute_sb_list(const AV1_COMMON *const cm, int mi_row, int mi_col, int count = 0; for (int r = 0; r < maxr; r += r_step) { for (int c = 0; c < maxc; c += c_step) { - if (!is_8x8_block_skip(grid, mi_row + r, mi_col + c, cm->mi_stride)) { + if (!is_8x8_block_skip(grid, mi_row + r, mi_col + c, + mi_params->mi_stride)) { dlist[count].by = r >> r_shift; dlist[count].bx = c >> c_shift; count++; @@ -119,6 +121,7 @@ static INLINE void copy_rect(uint16_t *dst, int dstride, const uint16_t *src, void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, MACROBLOCKD *xd) { const CdefInfo *const cdef_info = &cm->cdef_info; + const CommonModeInfoParams *const mi_params = &cm->mi_params; const int num_planes = av1_num_planes(cm); DECLARE_ALIGNED(16, uint16_t, src[CDEF_INBUF_SIZE]); uint16_t *linebuf[3]; @@ -133,8 +136,8 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int xdec[3]; int ydec[3]; int coeff_shift = AOMMAX(cm->seq_params.bit_depth - 8, 0); - const int nvfb = (cm->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; - const int nhfb = (cm->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + const int nvfb = (mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + const int nhfb = (mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; av1_setup_dst_planes(xd->plane, cm->seq_params.sb_size, frame, 0, 0, 0, num_planes); row_cdef = aom_malloc(sizeof(*row_cdef) * (nhfb + 2) * 2); @@ -147,7 +150,7 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, mi_wide_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_x; mi_high_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_y; } - const int stride = (cm->mi_cols << MI_SIZE_LOG2) + 2 * CDEF_HBORDER; + const int stride = (mi_params->mi_cols << MI_SIZE_LOG2) + 2 * CDEF_HBORDER; for (int pli = 0; pli < num_planes; pli++) { linebuf[pli] = aom_malloc(sizeof(*linebuf) * CDEF_VBORDER * stride); colbuf[pli] = @@ -169,17 +172,18 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int nhb, nvb; int cstart = 0; curr_row_cdef[fbc] = 0; - if (cm->mi_grid_base[MI_SIZE_64X64 * fbr * cm->mi_stride + - MI_SIZE_64X64 * fbc] == NULL || - cm->mi_grid_base[MI_SIZE_64X64 * fbr * cm->mi_stride + - MI_SIZE_64X64 * fbc] + if (mi_params->mi_grid_base[MI_SIZE_64X64 * fbr * mi_params->mi_stride + + MI_SIZE_64X64 * fbc] == NULL || + mi_params + ->mi_grid_base[MI_SIZE_64X64 * fbr * mi_params->mi_stride + + MI_SIZE_64X64 * fbc] ->cdef_strength == -1) { cdef_left = 0; continue; } if (!cdef_left) cstart = -CDEF_HBORDER; - nhb = AOMMIN(MI_SIZE_64X64, cm->mi_cols - MI_SIZE_64X64 * fbc); - nvb = AOMMIN(MI_SIZE_64X64, cm->mi_rows - MI_SIZE_64X64 * fbr); + nhb = AOMMIN(MI_SIZE_64X64, mi_params->mi_cols - MI_SIZE_64X64 * fbc); + nvb = AOMMIN(MI_SIZE_64X64, mi_params->mi_rows - MI_SIZE_64X64 * fbr); int frame_top, frame_left, frame_bottom, frame_right; int mi_row = MI_SIZE_64X64 * fbr; @@ -197,18 +201,19 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, frame_left = (mi_col == 0) ? 1 : 0; if (fbr != nvfb - 1) - frame_bottom = (mi_row + MI_SIZE_64X64 == cm->mi_rows) ? 1 : 0; + frame_bottom = (mi_row + MI_SIZE_64X64 == mi_params->mi_rows) ? 1 : 0; else frame_bottom = 1; if (fbc != nhfb - 1) - frame_right = (mi_col + MI_SIZE_64X64 == cm->mi_cols) ? 1 : 0; + frame_right = (mi_col + MI_SIZE_64X64 == mi_params->mi_cols) ? 1 : 0; else frame_right = 1; const int mbmi_cdef_strength = - cm->mi_grid_base[MI_SIZE_64X64 * fbr * cm->mi_stride + - MI_SIZE_64X64 * fbc] + mi_params + ->mi_grid_base[MI_SIZE_64X64 * fbr * mi_params->mi_stride + + MI_SIZE_64X64 * fbc] ->cdef_strength; level = cdef_info->cdef_strengths[mbmi_cdef_strength] / CDEF_SEC_STRENGTHS; @@ -222,7 +227,7 @@ void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, uv_sec_strength += uv_sec_strength == 3; if ((level == 0 && sec_strength == 0 && uv_level == 0 && uv_sec_strength == 0) || - (cdef_count = av1_cdef_compute_sb_list(cm, fbr * MI_SIZE_64X64, + (cdef_count = av1_cdef_compute_sb_list(mi_params, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64, dlist, BLOCK_64X64)) == 0) { cdef_left = 0; diff --git a/media/libaom/src/av1/common/cdef.h b/media/libaom/src/av1/common/cdef.h index 384858316f..c36fd135a4 100644 --- a/media/libaom/src/av1/common/cdef.h +++ b/media/libaom/src/av1/common/cdef.h @@ -20,8 +20,8 @@ #include "aom/aom_integer.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/cdef_block.h" -#include "av1/common/onyxc_int.h" static INLINE int sign(int i) { return i < 0 ? -1 : 1; } @@ -37,8 +37,9 @@ static INLINE int constrain(int diff, int threshold, int damping) { extern "C" { #endif -int av1_cdef_compute_sb_list(const AV1_COMMON *const cm, int mi_row, int mi_col, - cdef_list *dlist, BLOCK_SIZE bsize); +int av1_cdef_compute_sb_list(const CommonModeInfoParams *const mi_params, + int mi_row, int mi_col, cdef_list *dlist, + BLOCK_SIZE bsize); void av1_cdef_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, MACROBLOCKD *xd); void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, diff --git a/media/libaom/src/av1/common/cfl.c b/media/libaom/src/av1/common/cfl.c index db84ebb0f3..98199cb953 100644 --- a/media/libaom/src/av1/common/cfl.c +++ b/media/libaom/src/av1/common/cfl.c @@ -9,9 +9,9 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include "av1/common/av1_common_int.h" #include "av1/common/cfl.h" #include "av1/common/common_data.h" -#include "av1/common/onyxc_int.h" #include "config/av1_rtcd.h" @@ -327,7 +327,7 @@ static void cfl_store(CFL_CTX *cfl, const uint8_t *input, int input_stride, int row, int col, TX_SIZE tx_size, int use_hbd) { const int width = tx_size_wide[tx_size]; const int height = tx_size_high[tx_size]; - const int tx_off_log2 = tx_size_wide_log2[0]; + const int tx_off_log2 = MI_SIZE_LOG2; const int sub_x = cfl->subsampling_x; const int sub_y = cfl->subsampling_y; const int store_row = row << (tx_off_log2 - sub_y); @@ -372,16 +372,17 @@ static void cfl_store(CFL_CTX *cfl, const uint8_t *input, int input_stride, // Adjust the row and column of blocks smaller than 8X8, as chroma-referenced // and non-chroma-referenced blocks are stored together in the CfL buffer. -static INLINE void sub8x8_adjust_offset(const CFL_CTX *cfl, int *row_out, +static INLINE void sub8x8_adjust_offset(const CFL_CTX *cfl, int mi_row, + int mi_col, int *row_out, int *col_out) { // Increment row index for bottom: 8x4, 16x4 or both bottom 4x4s. - if ((cfl->mi_row & 0x01) && cfl->subsampling_y) { + if ((mi_row & 0x01) && cfl->subsampling_y) { assert(*row_out == 0); (*row_out)++; } // Increment col index for right: 4x8, 4x16 or both right 4x4s. - if ((cfl->mi_col & 0x01) && cfl->subsampling_x) { + if ((mi_col & 0x01) && cfl->subsampling_x) { assert(*col_out == 0); (*col_out)++; } @@ -391,18 +392,33 @@ void cfl_store_tx(MACROBLOCKD *const xd, int row, int col, TX_SIZE tx_size, BLOCK_SIZE bsize) { CFL_CTX *const cfl = &xd->cfl; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; - uint8_t *dst = - &pd->dst.buf[(row * pd->dst.stride + col) << tx_size_wide_log2[0]]; + uint8_t *dst = &pd->dst.buf[(row * pd->dst.stride + col) << MI_SIZE_LOG2]; if (block_size_high[bsize] == 4 || block_size_wide[bsize] == 4) { // Only dimensions of size 4 can have an odd offset. assert(!((col & 1) && tx_size_wide[tx_size] != 4)); assert(!((row & 1) && tx_size_high[tx_size] != 4)); - sub8x8_adjust_offset(cfl, &row, &col); + sub8x8_adjust_offset(cfl, xd->mi_row, xd->mi_col, &row, &col); } cfl_store(cfl, dst, pd->dst.stride, row, col, tx_size, is_cur_buf_hbd(xd)); } +static INLINE int max_intra_block_width(const MACROBLOCKD *xd, + BLOCK_SIZE plane_bsize, int plane, + TX_SIZE tx_size) { + const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane) + << MI_SIZE_LOG2; + return ALIGN_POWER_OF_TWO(max_blocks_wide, tx_size_wide_log2[tx_size]); +} + +static INLINE int max_intra_block_height(const MACROBLOCKD *xd, + BLOCK_SIZE plane_bsize, int plane, + TX_SIZE tx_size) { + const int max_blocks_high = max_block_high(xd, plane_bsize, plane) + << MI_SIZE_LOG2; + return ALIGN_POWER_OF_TWO(max_blocks_high, tx_size_high_log2[tx_size]); +} + void cfl_store_block(MACROBLOCKD *const xd, BLOCK_SIZE bsize, TX_SIZE tx_size) { CFL_CTX *const cfl = &xd->cfl; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; @@ -410,7 +426,7 @@ void cfl_store_block(MACROBLOCKD *const xd, BLOCK_SIZE bsize, TX_SIZE tx_size) { int col = 0; if (block_size_high[bsize] == 4 || block_size_wide[bsize] == 4) { - sub8x8_adjust_offset(cfl, &row, &col); + sub8x8_adjust_offset(cfl, xd->mi_row, xd->mi_col, &row, &col); } const int width = max_intra_block_width(xd, bsize, AOM_PLANE_Y, tx_size); const int height = max_intra_block_height(xd, bsize, AOM_PLANE_Y, tx_size); diff --git a/media/libaom/src/av1/common/cfl.h b/media/libaom/src/av1/common/cfl.h index 2acad26170..a1d6dc2eaa 100644 --- a/media/libaom/src/av1/common/cfl.h +++ b/media/libaom/src/av1/common/cfl.h @@ -12,8 +12,8 @@ #ifndef AOM_AV1_COMMON_CFL_H_ #define AOM_AV1_COMMON_CFL_H_ +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" // Can we use CfL for the current block? static INLINE CFL_ALLOWED_TYPE is_cfl_allowed(const MACROBLOCKD *xd) { @@ -41,7 +41,7 @@ static INLINE CFL_ALLOWED_TYPE store_cfl_required(const AV1_COMMON *cm, if (cm->seq_params.monochrome) return CFL_DISALLOWED; - if (!xd->cfl.is_chroma_reference) { + if (!xd->is_chroma_ref) { // For non-chroma-reference blocks, we should always store the luma pixels, // in case the corresponding chroma-reference block uses CfL. // Note that this can only happen for block sizes which are <8 on diff --git a/media/libaom/src/av1/common/common_data.h b/media/libaom/src/av1/common/common_data.h index 46e455fdb1..402845cafe 100644 --- a/media/libaom/src/av1/common/common_data.h +++ b/media/libaom/src/av1/common/common_data.h @@ -82,16 +82,16 @@ static const BLOCK_SIZE subsize_lookup[EXT_PARTITION_TYPES][SQR_BLOCK_SIZES] = { BLOCK_INVALID, BLOCK_4X4, BLOCK_8X8, BLOCK_16X16, BLOCK_32X32, BLOCK_64X64 }, { // PARTITION_HORZ_A - BLOCK_INVALID, BLOCK_8X4, BLOCK_16X8, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8, BLOCK_32X16, BLOCK_64X32, BLOCK_128X64 }, { // PARTITION_HORZ_B - BLOCK_INVALID, BLOCK_8X4, BLOCK_16X8, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8, BLOCK_32X16, BLOCK_64X32, BLOCK_128X64 }, { // PARTITION_VERT_A - BLOCK_INVALID, BLOCK_4X8, BLOCK_8X16, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16, BLOCK_16X32, BLOCK_32X64, BLOCK_64X128 }, { // PARTITION_VERT_B - BLOCK_INVALID, BLOCK_4X8, BLOCK_8X16, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16, BLOCK_16X32, BLOCK_32X64, BLOCK_64X128 }, { // PARTITION_HORZ_4 BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X4, diff --git a/media/libaom/src/av1/common/convolve.c b/media/libaom/src/av1/common/convolve.c index 150461193b..e177e3cad3 100644 --- a/media/libaom/src/av1/common/convolve.c +++ b/media/libaom/src/av1/common/convolve.c @@ -15,10 +15,10 @@ #include "config/aom_dsp_rtcd.h" #include "config/av1_rtcd.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/convolve.h" #include "av1/common/filter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/resize.h" #include "aom_dsp/aom_dsp_common.h" #include "aom_ports/mem.h" @@ -573,11 +573,21 @@ void av1_convolve_2d_facade(const uint8_t *src, int src_stride, uint8_t *dst, if (filter_params_x->taps == 2 || filter_params_y->taps == 2) { assert(filter_params_x->taps == 2 && filter_params_y->taps == 2); assert(!scaled); - if (subpel_x_qn || subpel_y_qn) { + if (subpel_x_qn && subpel_y_qn) { av1_convolve_2d_sr_c(src, src_stride, dst, dst_stride, w, h, filter_params_x, filter_params_y, subpel_x_qn, subpel_y_qn, conv_params); return; + } else if (subpel_x_qn) { + av1_convolve_x_sr_c(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, subpel_x_qn, + subpel_y_qn, conv_params); + return; + } else if (subpel_y_qn) { + av1_convolve_y_sr_c(src, src_stride, dst, dst_stride, w, h, + filter_params_x, filter_params_y, subpel_x_qn, + subpel_y_qn, conv_params); + return; } } diff --git a/media/libaom/src/av1/common/convolve.h b/media/libaom/src/av1/common/convolve.h index 6056647281..04df86c42f 100644 --- a/media/libaom/src/av1/common/convolve.h +++ b/media/libaom/src/av1/common/convolve.h @@ -26,6 +26,7 @@ typedef struct ConvolveParams { int round_1; int plane; int is_compound; + int compound_index; // 0: the first single in compound mode, 1: the second. int use_dist_wtd_comp_avg; int fwd_offset; int bck_offset; @@ -61,13 +62,14 @@ void av1_convolve_2d_facade(const uint8_t *src, int src_stride, uint8_t *dst, ConvolveParams *conv_params, const struct scale_factors *sf); -static INLINE ConvolveParams get_conv_params_no_round(int do_average, int plane, +static INLINE ConvolveParams get_conv_params_no_round(int cmp_index, int plane, CONV_BUF_TYPE *dst, int dst_stride, int is_compound, int bd) { ConvolveParams conv_params; - conv_params.do_average = do_average; - assert(IMPLIES(do_average, is_compound)); + conv_params.compound_index = cmp_index; + assert(IMPLIES(cmp_index, is_compound)); + conv_params.is_compound = is_compound; conv_params.round_0 = ROUND0_BITS; conv_params.round_1 = is_compound ? COMPOUND_ROUND1_BITS @@ -83,6 +85,10 @@ static INLINE ConvolveParams get_conv_params_no_round(int do_average, int plane, conv_params.dst = dst; conv_params.dst_stride = dst_stride; conv_params.plane = plane; + + // By default, set do average to 1 if this is the second single prediction + // in a compound mode. + conv_params.do_average = cmp_index; return conv_params; } diff --git a/media/libaom/src/av1/common/debugmodes.c b/media/libaom/src/av1/common/debugmodes.c index 50d1e60149..ff02ddde0b 100644 --- a/media/libaom/src/av1/common/debugmodes.c +++ b/media/libaom/src/av1/common/debugmodes.c @@ -11,14 +11,14 @@ #include +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/enums.h" -#include "av1/common/onyxc_int.h" static void log_frame_info(AV1_COMMON *cm, const char *str, FILE *f) { fprintf(f, "%s", str); fprintf(f, "(Frame %d, Show:%d, Q:%d): \n", cm->current_frame.frame_number, - cm->show_frame, cm->base_qindex); + cm->show_frame, cm->quant_params.base_qindex); } /* This function dereferences a pointer to the mbmi structure * and uses the passed in member offset to print out the value of an integer @@ -26,32 +26,31 @@ static void log_frame_info(AV1_COMMON *cm, const char *str, FILE *f) { */ static void print_mi_data(AV1_COMMON *cm, FILE *file, const char *descriptor, size_t member_offset) { - int mi_row, mi_col; - MB_MODE_INFO **mi = cm->mi_grid_base; - int rows = cm->mi_rows; - int cols = cm->mi_cols; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + MB_MODE_INFO **mi = mi_params->mi_grid_base; + int rows = mi_params->mi_rows; + int cols = mi_params->mi_cols; char prefix = descriptor[0]; log_frame_info(cm, descriptor, file); - for (mi_row = 0; mi_row < rows; mi_row++) { + for (int mi_row = 0; mi_row < rows; mi_row++) { fprintf(file, "%c ", prefix); - for (mi_col = 0; mi_col < cols; mi_col++) { + for (int mi_col = 0; mi_col < cols; mi_col++) { fprintf(file, "%2d ", *((char *)((char *)(mi[0]) + member_offset))); mi++; } fprintf(file, "\n"); - mi += cm->mi_stride - cols; + mi += mi_params->mi_stride - cols; } fprintf(file, "\n"); } void av1_print_modes_and_motion_vectors(AV1_COMMON *cm, const char *file) { - int mi_row; - int mi_col; + CommonModeInfoParams *mi_params = &cm->mi_params; FILE *mvs = fopen(file, "a"); - MB_MODE_INFO **mi = cm->mi_grid_base; - int rows = cm->mi_rows; - int cols = cm->mi_cols; + MB_MODE_INFO **mi = mi_params->mi_grid_base; + const int rows = mi_params->mi_rows; + const int cols = mi_params->mi_cols; print_mi_data(cm, mvs, "Partitions:", offsetof(MB_MODE_INFO, sb_type)); print_mi_data(cm, mvs, "Modes:", offsetof(MB_MODE_INFO, mode)); @@ -61,28 +60,28 @@ void av1_print_modes_and_motion_vectors(AV1_COMMON *cm, const char *file) { // output skip infomation. log_frame_info(cm, "Skips:", mvs); - for (mi_row = 0; mi_row < rows; mi_row++) { + for (int mi_row = 0; mi_row < rows; mi_row++) { fprintf(mvs, "S "); - for (mi_col = 0; mi_col < cols; mi_col++) { + for (int mi_col = 0; mi_col < cols; mi_col++) { fprintf(mvs, "%2d ", mi[0]->skip); mi++; } fprintf(mvs, "\n"); - mi += cm->mi_stride - cols; + mi += mi_params->mi_stride - cols; } fprintf(mvs, "\n"); // output motion vectors. log_frame_info(cm, "Vectors ", mvs); - mi = cm->mi_grid_base; - for (mi_row = 0; mi_row < rows; mi_row++) { + mi = mi_params->mi_grid_base; + for (int mi_row = 0; mi_row < rows; mi_row++) { fprintf(mvs, "V "); - for (mi_col = 0; mi_col < cols; mi_col++) { + for (int mi_col = 0; mi_col < cols; mi_col++) { fprintf(mvs, "%4d:%4d ", mi[0]->mv[0].as_mv.row, mi[0]->mv[0].as_mv.col); mi++; } fprintf(mvs, "\n"); - mi += cm->mi_stride - cols; + mi += mi_params->mi_stride - cols; } fprintf(mvs, "\n"); @@ -93,6 +92,13 @@ void av1_print_uncompressed_frame_header(const uint8_t *data, int size, const char *filename) { FILE *hdrFile = fopen(filename, "w"); fwrite(data, size, sizeof(uint8_t), hdrFile); + + // Reset order hints(7bit + a previous bit) to 0, so that all camera frame + // headers are identical in large scale coding. + uint8_t zero = 0; + fseek(hdrFile, 1, SEEK_SET); + // Reset second byte. + fwrite(&zero, 1, sizeof(uint8_t), hdrFile); fclose(hdrFile); } diff --git a/media/libaom/src/av1/common/entropy.c b/media/libaom/src/av1/common/entropy.c index 9eed1087e6..1f7a0efe08 100644 --- a/media/libaom/src/av1/common/entropy.c +++ b/media/libaom/src/av1/common/entropy.c @@ -13,10 +13,10 @@ #include "aom/aom_integer.h" #include "aom_mem/aom_mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/entropy.h" #include "av1/common/entropymode.h" -#include "av1/common/onyxc_int.h" #include "av1/common/scan.h" #include "av1/common/token_cdfs.h" #include "av1/common/txb_common.h" @@ -29,7 +29,7 @@ static int get_q_ctx(int q) { } void av1_default_coef_probs(AV1_COMMON *cm) { - const int index = get_q_ctx(cm->base_qindex); + const int index = get_q_ctx(cm->quant_params.base_qindex); #if CONFIG_ENTROPY_STATS cm->coef_cdf_category = index; #endif diff --git a/media/libaom/src/av1/common/entropymode.c b/media/libaom/src/av1/common/entropymode.c index 96ae8b4b65..5f061be35e 100644 --- a/media/libaom/src/av1/common/entropymode.c +++ b/media/libaom/src/av1/common/entropymode.c @@ -11,9 +11,9 @@ #include "aom_mem/aom_mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/reconinter.h" #include "av1/common/scan.h" -#include "av1/common/onyxc_int.h" #include "av1/common/seg_common.h" #include "av1/common/txb_common.h" @@ -1071,7 +1071,7 @@ void av1_setup_frame_contexts(AV1_COMMON *cm) { *cm->default_frame_context = *cm->fc; // TODO(jack.haughton@argondesign.com): don't think this should be necessary, // but could do with fuller testing - if (cm->large_scale_tile) { + if (cm->tiles.large_scale) { for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { RefCntBuffer *const buf = get_ref_frame_buf(cm, i); if (buf != NULL) buf->frame_context = *cm->fc; @@ -1087,7 +1087,8 @@ void av1_setup_past_independence(AV1_COMMON *cm) { av1_clearall_segfeatures(&cm->seg); if (cm->cur_frame->seg_map) - memset(cm->cur_frame->seg_map, 0, (cm->mi_rows * cm->mi_cols)); + memset(cm->cur_frame->seg_map, 0, + (cm->mi_params.mi_rows * cm->mi_params.mi_cols)); // reset mode ref deltas av1_set_default_ref_deltas(cm->cur_frame->ref_deltas); diff --git a/media/libaom/src/av1/common/entropymv.c b/media/libaom/src/av1/common/entropymv.c index 4913373875..e1e42f2f18 100644 --- a/media/libaom/src/av1/common/entropymv.c +++ b/media/libaom/src/av1/common/entropymv.c @@ -9,7 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/entropymv.h" static const nmv_context default_nmv_context = { diff --git a/media/libaom/src/av1/common/enums.h b/media/libaom/src/av1/common/enums.h index d5a9151d61..0c09a1bc7a 100644 --- a/media/libaom/src/av1/common/enums.h +++ b/media/libaom/src/av1/common/enums.h @@ -260,6 +260,7 @@ enum { V_FLIPADST, // FLIPADST in vertical, identity in horizontal H_FLIPADST, // Identity in vertical, FLIPADST in horizontal TX_TYPES, + DCT_ADST_TX_MASK = 0x000F, // Either DCT or ADST in each direction } UENUM1BYTE(TX_TYPE); enum { @@ -290,8 +291,6 @@ enum { EXT_TX_SET_TYPES } UENUM1BYTE(TxSetType); -#define IS_2D_TRANSFORM(tx_type) (tx_type < IDTX) - #define EXT_TX_SIZES 4 // number of sizes that use extended transforms #define EXT_TX_SETS_INTER 4 // Sets of transform selections for INTER #define EXT_TX_SETS_INTRA 3 // Sets of transform selections for INTRA @@ -411,6 +410,8 @@ enum { MB_MODE_COUNT, INTRA_MODE_START = DC_PRED, INTRA_MODE_END = NEARESTMV, + DIR_MODE_START = V_PRED, + DIR_MODE_END = D67_PRED + 1, INTRA_MODE_NUM = INTRA_MODE_END - INTRA_MODE_START, SINGLE_INTER_MODE_START = NEARESTMV, SINGLE_INTER_MODE_END = NEAREST_NEARESTMV, diff --git a/media/libaom/src/av1/common/filter.h b/media/libaom/src/av1/common/filter.h index 3fa18d3b3f..91791d3dcb 100644 --- a/media/libaom/src/av1/common/filter.h +++ b/media/libaom/src/av1/common/filter.h @@ -94,7 +94,6 @@ static INLINE InterpFilter av1_unswitchable_filter(InterpFilter filter) { /* (1 << LOG_SWITCHABLE_FILTERS) > SWITCHABLE_FILTERS */ #define LOG_SWITCHABLE_FILTERS 2 -#define MAX_SUBPEL_TAPS 12 #define SWITCHABLE_FILTER_CONTEXTS ((SWITCHABLE_FILTERS + 1) * 4) #define INTER_FILTER_COMP_OFFSET (SWITCHABLE_FILTERS + 1) #define INTER_FILTER_DIR_OFFSET ((SWITCHABLE_FILTERS + 1) * 2) @@ -231,11 +230,6 @@ av1_get_interp_filter_params_with_block_size(const InterpFilter interp_filter, return &av1_interp_filter_params_list[interp_filter]; } -static INLINE const InterpFilterParams *get_4tap_interp_filter_params( - const InterpFilter interp_filter) { - return &av1_interp_4tap[interp_filter]; -} - static INLINE const int16_t *av1_get_interp_filter_kernel( const InterpFilter interp_filter, int subpel_search) { assert(subpel_search >= USE_2_TAPS); @@ -255,8 +249,8 @@ static INLINE const InterpFilterParams *av1_get_filter(int subpel_search) { assert(subpel_search >= USE_2_TAPS); switch (subpel_search) { - case USE_2_TAPS: return get_4tap_interp_filter_params(BILINEAR); - case USE_4_TAPS: return get_4tap_interp_filter_params(EIGHTTAP_REGULAR); + case USE_2_TAPS: return &av1_interp_4tap[BILINEAR]; + case USE_4_TAPS: return &av1_interp_4tap[EIGHTTAP_REGULAR]; case USE_8_TAPS: return &av1_interp_filter_params_list[EIGHTTAP_REGULAR]; default: assert(0); return NULL; } diff --git a/media/libaom/src/av1/common/loopfiltermask.c b/media/libaom/src/av1/common/loopfiltermask.c index ce31285544..157310f2df 100644 --- a/media/libaom/src/av1/common/loopfiltermask.c +++ b/media/libaom/src/av1/common/loopfiltermask.c @@ -17,8 +17,8 @@ #include "aom_dsp/aom_dsp_common.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/av1_loopfilter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" #include "av1/common/seg_common.h" @@ -964,7 +964,7 @@ void av1_filter_block_plane_bitmask_vert( const int shift = get_index_shift(col, row, &index); int index_next = 0; const int shift_next = get_index_shift(col, row_next, &index_next); - const int has_next_row = row_next < cm->mi_rows; + const int has_next_row = row_next < cm->mi_params.mi_rows; switch (pl) { case 0: mask_16x16 = lfm->left_y[TX_16X16].bits[index]; diff --git a/media/libaom/src/av1/common/mv.h b/media/libaom/src/av1/common/mv.h index fe821eeed6..be539e8201 100644 --- a/media/libaom/src/av1/common/mv.h +++ b/media/libaom/src/av1/common/mv.h @@ -21,17 +21,34 @@ extern "C" { #endif #define INVALID_MV 0x80008000 +#define GET_MV_RAWPEL(x) (((x) + 3 + ((x) >= 0)) >> 3) +#define GET_MV_SUBPEL(x) ((x)*8) +#define MARK_MV_INVALID(mv) \ + do { \ + ((int_mv *)(mv))->as_int = INVALID_MV; \ + } while (0); +#define CHECK_MV_EQUAL(x, y) (((x).row == (y).row) && ((x).col == (y).col)) + +// The motion vector in units of full pixel +typedef struct fullpel_mv { + int16_t row; + int16_t col; +} FULLPEL_MV; + +// The motion vector in units of 1/8-pel typedef struct mv { int16_t row; int16_t col; } MV; static const MV kZeroMv = { 0, 0 }; +static const FULLPEL_MV kZeroFullMv = { 0, 0 }; typedef union int_mv { uint32_t as_int; MV as_mv; + FULLPEL_MV as_fullmv; } int_mv; /* facilitates faster equality tests and copies */ typedef struct mv32 { @@ -39,6 +56,38 @@ typedef struct mv32 { int32_t col; } MV32; +// The mv limit for fullpel mvs +typedef struct { + int col_min; + int col_max; + int row_min; + int row_max; +} FullMvLimits; + +// The mv limit for subpel mvs +typedef struct { + int col_min; + int col_max; + int row_min; + int row_max; +} SubpelMvLimits; + +static AOM_INLINE FULLPEL_MV get_fullmv_from_mv(const MV *subpel_mv) { + const FULLPEL_MV full_mv = { (int16_t)GET_MV_RAWPEL(subpel_mv->row), + (int16_t)GET_MV_RAWPEL(subpel_mv->col) }; + return full_mv; +} + +static AOM_INLINE MV get_mv_from_fullmv(const FULLPEL_MV *full_mv) { + const MV subpel_mv = { (int16_t)GET_MV_SUBPEL(full_mv->row), + (int16_t)GET_MV_SUBPEL(full_mv->col) }; + return subpel_mv; +} + +static AOM_INLINE void convert_fullmv_to_mv(int_mv *mv) { + mv->as_mv = get_mv_from_fullmv(&mv->as_fullmv); +} + // Bits of precision used for the model #define WARPEDMODEL_PREC_BITS 16 #define WARPEDMODEL_ROW3HOMO_PREC_BITS 16 @@ -225,7 +274,8 @@ static INLINE int_mv gm_get_motion_vector(const WarpedMotionParams *gm, // All global motion vectors are stored with WARPEDMODEL_PREC_BITS (16) // bits of fractional precision. The offset for a translation is stored in // entries 0 and 1. For translations, all but the top three (two if - // cm->allow_high_precision_mv is false) fractional bits are always zero. + // cm->features.allow_high_precision_mv is false) fractional bits are always + // zero. // // After the right shifts, there are 3 fractional bits of precision. If // allow_hp is false, the bottom bit is always zero (so we don't need a @@ -287,10 +337,14 @@ static INLINE int is_equal_mv(const MV *a, const MV *b) { return *((const uint32_t *)a) == *((const uint32_t *)b); } -static INLINE void clamp_mv(MV *mv, int min_col, int max_col, int min_row, - int max_row) { - mv->col = clamp(mv->col, min_col, max_col); - mv->row = clamp(mv->row, min_row, max_row); +static INLINE void clamp_mv(MV *mv, const SubpelMvLimits *mv_limits) { + mv->col = clamp(mv->col, mv_limits->col_min, mv_limits->col_max); + mv->row = clamp(mv->row, mv_limits->row_min, mv_limits->row_max); +} + +static INLINE void clamp_fullmv(FULLPEL_MV *mv, const FullMvLimits *mv_limits) { + mv->col = clamp(mv->col, mv_limits->col_min, mv_limits->col_max); + mv->row = clamp(mv->row, mv_limits->row_min, mv_limits->row_max); } #ifdef __cplusplus diff --git a/media/libaom/src/av1/common/mvref_common.c b/media/libaom/src/av1/common/mvref_common.c index 8055d10d65..db3098cc0e 100644 --- a/media/libaom/src/av1/common/mvref_common.c +++ b/media/libaom/src/av1/common/mvref_common.c @@ -40,7 +40,7 @@ static AOM_INLINE void get_mv_projection(MV *output, MV ref, int num, int den) { 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) { - const int frame_mvs_stride = ROUND_POWER_OF_TWO(cm->mi_cols, 1); + const int frame_mvs_stride = ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, 1); MV_REF *frame_mvs = cm->cur_frame->mvs + (mi_row >> 1) * frame_mvs_stride + (mi_col >> 1); x_mis = ROUND_POWER_OF_TWO(x_mis, 1); @@ -75,7 +75,7 @@ static AOM_INLINE void add_ref_mv_candidate( const MB_MODE_INFO *const candidate, const MV_REFERENCE_FRAME rf[2], uint8_t *refmv_count, uint8_t *ref_match_count, uint8_t *newmv_count, CANDIDATE_MV *ref_mv_stack, uint16_t *ref_mv_weight, - int_mv *gm_mv_candidates, const WarpedMotionParams *gm_params, int col, + int_mv *gm_mv_candidates, const WarpedMotionParams *gm_params, uint16_t weight) { if (!is_inter_block(candidate)) return; assert(weight % 2 == 0); @@ -87,9 +87,8 @@ static AOM_INLINE void add_ref_mv_candidate( if (candidate->ref_frame[ref] == rf[0]) { const int is_gm_block = is_global_mv_block(candidate, gm_params[rf[0]].wmtype); - const int_mv this_refmv = is_gm_block - ? gm_mv_candidates[0] - : get_sub_block_mv(candidate, ref, col); + const int_mv this_refmv = + is_gm_block ? gm_mv_candidates[0] : get_block_mv(candidate, ref); for (index = 0; index < *refmv_count; ++index) { if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int) { ref_mv_weight[index] += weight; @@ -116,7 +115,7 @@ static AOM_INLINE void add_ref_mv_candidate( if (is_global_mv_block(candidate, gm_params[rf[ref]].wmtype)) this_refmv[ref] = gm_mv_candidates[ref]; else - this_refmv[ref] = get_sub_block_mv(candidate, ref, col); + this_refmv[ref] = get_block_mv(candidate, ref); } for (index = 0; index < *refmv_count; ++index) { @@ -141,38 +140,36 @@ static AOM_INLINE void add_ref_mv_candidate( } static AOM_INLINE void scan_row_mbmi( - const AV1_COMMON *cm, const MACROBLOCKD *xd, int mi_row, int mi_col, + const AV1_COMMON *cm, const MACROBLOCKD *xd, int mi_col, const MV_REFERENCE_FRAME rf[2], int row_offset, CANDIDATE_MV *ref_mv_stack, uint16_t *ref_mv_weight, uint8_t *refmv_count, uint8_t *ref_match_count, uint8_t *newmv_count, int_mv *gm_mv_candidates, int max_row_offset, int *processed_rows) { - int end_mi = AOMMIN(xd->n4_w, cm->mi_cols - mi_col); + int end_mi = AOMMIN(xd->width, cm->mi_params.mi_cols - mi_col); end_mi = AOMMIN(end_mi, mi_size_wide[BLOCK_64X64]); - const int n8_w_8 = mi_size_wide[BLOCK_8X8]; - const int n8_w_16 = mi_size_wide[BLOCK_16X16]; - int i; + const int width_8x8 = mi_size_wide[BLOCK_8X8]; + const int width_16x16 = mi_size_wide[BLOCK_16X16]; int col_offset = 0; // TODO(jingning): Revisit this part after cb4x4 is stable. if (abs(row_offset) > 1) { col_offset = 1; - if ((mi_col & 0x01) && xd->n4_w < n8_w_8) --col_offset; + if ((mi_col & 0x01) && xd->width < width_8x8) --col_offset; } - const int use_step_16 = (xd->n4_w >= 16); + const int use_step_16 = (xd->width >= 16); MB_MODE_INFO **const candidate_mi0 = xd->mi + row_offset * xd->mi_stride; - (void)mi_row; - for (i = 0; i < end_mi;) { + for (int i = 0; i < end_mi;) { const MB_MODE_INFO *const candidate = candidate_mi0[col_offset + i]; const int candidate_bsize = candidate->sb_type; const int n4_w = mi_size_wide[candidate_bsize]; - int len = AOMMIN(xd->n4_w, n4_w); + int len = AOMMIN(xd->width, n4_w); if (use_step_16) - len = AOMMAX(n8_w_16, len); + len = AOMMAX(width_16x16, len); else if (abs(row_offset) > 1) - len = AOMMAX(len, n8_w_8); + len = AOMMAX(len, width_8x8); uint16_t weight = 2; - if (xd->n4_w >= n8_w_8 && xd->n4_w <= n4_w) { + if (xd->width >= width_8x8 && xd->width <= n4_w) { uint16_t inc = AOMMIN(-max_row_offset + row_offset + 1, mi_size_high[candidate_bsize]); // Obtain range used in weight calculation. @@ -183,20 +180,19 @@ static AOM_INLINE void scan_row_mbmi( add_ref_mv_candidate(candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, ref_mv_weight, - gm_mv_candidates, cm->global_motion, col_offset + i, - len * weight); + gm_mv_candidates, cm->global_motion, len * weight); i += len; } } static AOM_INLINE void scan_col_mbmi( - const AV1_COMMON *cm, const MACROBLOCKD *xd, int mi_row, int mi_col, + const AV1_COMMON *cm, const MACROBLOCKD *xd, int mi_row, const MV_REFERENCE_FRAME rf[2], int col_offset, CANDIDATE_MV *ref_mv_stack, uint16_t *ref_mv_weight, uint8_t *refmv_count, uint8_t *ref_match_count, uint8_t *newmv_count, int_mv *gm_mv_candidates, int max_col_offset, int *processed_cols) { - int end_mi = AOMMIN(xd->n4_h, cm->mi_rows - mi_row); + int end_mi = AOMMIN(xd->height, cm->mi_params.mi_rows - mi_row); end_mi = AOMMIN(end_mi, mi_size_high[BLOCK_64X64]); const int n8_h_8 = mi_size_high[BLOCK_8X8]; const int n8_h_16 = mi_size_high[BLOCK_16X16]; @@ -204,24 +200,23 @@ static AOM_INLINE void scan_col_mbmi( int row_offset = 0; if (abs(col_offset) > 1) { row_offset = 1; - if ((mi_row & 0x01) && xd->n4_h < n8_h_8) --row_offset; + if ((mi_row & 0x01) && xd->height < n8_h_8) --row_offset; } - const int use_step_16 = (xd->n4_h >= 16); - (void)mi_col; + const int use_step_16 = (xd->height >= 16); for (i = 0; i < end_mi;) { const MB_MODE_INFO *const candidate = xd->mi[(row_offset + i) * xd->mi_stride + col_offset]; const int candidate_bsize = candidate->sb_type; const int n4_h = mi_size_high[candidate_bsize]; - int len = AOMMIN(xd->n4_h, n4_h); + int len = AOMMIN(xd->height, n4_h); if (use_step_16) len = AOMMAX(n8_h_16, len); else if (abs(col_offset) > 1) len = AOMMAX(len, n8_h_8); int weight = 2; - if (xd->n4_h >= n8_h_8 && xd->n4_h <= n4_h) { + if (xd->height >= n8_h_8 && xd->height <= n4_h) { int inc = AOMMIN(-max_col_offset + col_offset + 1, mi_size_wide[candidate_bsize]); // Obtain range used in weight calculation. @@ -232,8 +227,7 @@ static AOM_INLINE void scan_col_mbmi( add_ref_mv_candidate(candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, ref_mv_weight, - gm_mv_candidates, cm->global_motion, col_offset, - len * weight); + gm_mv_candidates, cm->global_motion, len * weight); i += len; } @@ -258,8 +252,7 @@ static AOM_INLINE void scan_blk_mbmi( add_ref_mv_candidate(candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, ref_mv_weight, - gm_mv_candidates, cm->global_motion, mi_pos.col, - 2 * len); + gm_mv_candidates, cm->global_motion, 2 * len); } // Analyze a single 8x8 block motion information. } @@ -294,19 +287,19 @@ static int has_top_right(const AV1_COMMON *cm, const MACROBLOCKD *xd, // The left hand of two vertical rectangles always has a top right (as the // block above will have been decoded) - if (xd->n4_w < xd->n4_h) + if (xd->width < xd->height) if (!xd->is_sec_rect) has_tr = 1; // The bottom of two horizontal rectangles never has a top right (as the block // to the right won't have been decoded) - if (xd->n4_w > xd->n4_h) + if (xd->width > xd->height) if (xd->is_sec_rect) has_tr = 0; // The bottom left square of a Vertical A (in the old format) does // not have a top right as it is decoded before the right hand // rectangle of the partition if (xd->mi[0]->partition == PARTITION_VERT_A) { - if (xd->n4_w == xd->n4_h) + if (xd->width == xd->height) if (mask_row & bs) has_tr = 0; } @@ -340,7 +333,8 @@ static int add_tpl_ref_mv(const AV1_COMMON *cm, const MACROBLOCKD *xd, if (!is_inside(&xd->tile, mi_col, mi_row, &mi_pos)) return 0; const TPL_MV_REF *prev_frame_mvs = - cm->tpl_mvs + ((mi_row + mi_pos.row) >> 1) * (cm->mi_stride >> 1) + + cm->tpl_mvs + + ((mi_row + mi_pos.row) >> 1) * (cm->mi_params.mi_stride >> 1) + ((mi_col + mi_pos.col) >> 1); if (prev_frame_mvs->mfmv0.as_int == INVALID_MV) return 0; @@ -354,12 +348,14 @@ static int add_tpl_ref_mv(const AV1_COMMON *cm, const MACROBLOCKD *xd, const int cur_offset_0 = get_relative_dist(&cm->seq_params.order_hint_info, cur_frame_index, frame0_index); int idx; + const int allow_high_precision_mv = cm->features.allow_high_precision_mv; + const int force_integer_mv = cm->features.cur_frame_force_integer_mv; int_mv this_refmv; get_mv_projection(&this_refmv.as_mv, prev_frame_mvs->mfmv0.as_mv, cur_offset_0, prev_frame_mvs->ref_frame_offset); - lower_mv_precision(&this_refmv.as_mv, cm->allow_high_precision_mv, - cm->cur_frame_force_integer_mv); + lower_mv_precision(&this_refmv.as_mv, allow_high_precision_mv, + force_integer_mv); if (rf[1] == NONE_FRAME) { if (blk_row == 0 && blk_col == 0) { @@ -387,8 +383,8 @@ static int add_tpl_ref_mv(const AV1_COMMON *cm, const MACROBLOCKD *xd, int_mv comp_refmv; get_mv_projection(&comp_refmv.as_mv, prev_frame_mvs->mfmv0.as_mv, cur_offset_1, prev_frame_mvs->ref_frame_offset); - lower_mv_precision(&comp_refmv.as_mv, cm->allow_high_precision_mv, - cm->cur_frame_force_integer_mv); + lower_mv_precision(&comp_refmv.as_mv, allow_high_precision_mv, + force_integer_mv); if (blk_row == 0 && blk_col == 0) { if (abs(this_refmv.as_mv.row - gm_mv_candidates[0].as_mv.row) >= 16 || @@ -480,14 +476,14 @@ static AOM_INLINE void setup_ref_mv_list( uint16_t ref_mv_weight[MAX_REF_MV_STACK_SIZE], int_mv mv_ref_list[MAX_MV_REF_CANDIDATES], int_mv *gm_mv_candidates, int mi_row, int mi_col, int16_t *mode_context) { - const int bs = AOMMAX(xd->n4_w, xd->n4_h); + const int bs = AOMMAX(xd->width, xd->height); const int has_tr = has_top_right(cm, xd, mi_row, mi_col, bs); MV_REFERENCE_FRAME rf[2]; const TileInfo *const tile = &xd->tile; int max_row_offset = 0, max_col_offset = 0; - const int row_adj = (xd->n4_h < mi_size_high[BLOCK_8X8]) && (mi_row & 0x01); - const int col_adj = (xd->n4_w < mi_size_wide[BLOCK_8X8]) && (mi_col & 0x01); + const int row_adj = (xd->height < mi_size_high[BLOCK_8X8]) && (mi_row & 0x01); + const int col_adj = (xd->width < mi_size_wide[BLOCK_8X8]) && (mi_col & 0x01); int processed_rows = 0; int processed_cols = 0; @@ -499,7 +495,7 @@ static AOM_INLINE void setup_ref_mv_list( if (xd->up_available) { max_row_offset = -(MVREF_ROW_COLS << 1) + row_adj; - if (xd->n4_h < mi_size_high[BLOCK_8X8]) + if (xd->height < mi_size_high[BLOCK_8X8]) max_row_offset = -(2 << 1) + row_adj; max_row_offset = find_valid_row_offset(tile, mi_row, max_row_offset); @@ -508,7 +504,7 @@ static AOM_INLINE void setup_ref_mv_list( if (xd->left_available) { max_col_offset = -(MVREF_ROW_COLS << 1) + col_adj; - if (xd->n4_w < mi_size_wide[BLOCK_8X8]) + if (xd->width < mi_size_wide[BLOCK_8X8]) max_col_offset = -(2 << 1) + col_adj; max_col_offset = find_valid_col_offset(tile, mi_col, max_col_offset); @@ -520,17 +516,17 @@ static AOM_INLINE void setup_ref_mv_list( // Scan the first above row mode info. row_offset = -1; if (abs(max_row_offset) >= 1) - scan_row_mbmi(cm, xd, mi_row, mi_col, rf, -1, ref_mv_stack, ref_mv_weight, + scan_row_mbmi(cm, xd, mi_col, rf, -1, ref_mv_stack, ref_mv_weight, refmv_count, &row_match_count, &newmv_count, gm_mv_candidates, max_row_offset, &processed_rows); // Scan the first left column mode info. col_offset = -1; if (abs(max_col_offset) >= 1) - scan_col_mbmi(cm, xd, mi_row, mi_col, rf, -1, ref_mv_stack, ref_mv_weight, + scan_col_mbmi(cm, xd, mi_row, rf, -1, ref_mv_stack, ref_mv_weight, refmv_count, &col_match_count, &newmv_count, gm_mv_candidates, max_col_offset, &processed_cols); // Check top-right boundary if (has_tr) - scan_blk_mbmi(cm, xd, mi_row, mi_col, rf, -1, xd->n4_w, ref_mv_stack, + scan_blk_mbmi(cm, xd, mi_row, mi_col, rf, -1, xd->width, ref_mv_stack, ref_mv_weight, &row_match_count, &newmv_count, gm_mv_candidates, refmv_count); @@ -541,27 +537,27 @@ static AOM_INLINE void setup_ref_mv_list( for (int idx = 0; idx < nearest_refmv_count; ++idx) ref_mv_weight[idx] += REF_CAT_LEVEL; - if (cm->allow_ref_frame_mvs) { + if (cm->features.allow_ref_frame_mvs) { int is_available = 0; - const int voffset = AOMMAX(mi_size_high[BLOCK_8X8], xd->n4_h); - const int hoffset = AOMMAX(mi_size_wide[BLOCK_8X8], xd->n4_w); - const int blk_row_end = AOMMIN(xd->n4_h, mi_size_high[BLOCK_64X64]); - const int blk_col_end = AOMMIN(xd->n4_w, mi_size_wide[BLOCK_64X64]); + const int voffset = AOMMAX(mi_size_high[BLOCK_8X8], xd->height); + const int hoffset = AOMMAX(mi_size_wide[BLOCK_8X8], xd->width); + const int blk_row_end = AOMMIN(xd->height, mi_size_high[BLOCK_64X64]); + const int blk_col_end = AOMMIN(xd->width, mi_size_wide[BLOCK_64X64]); const int tpl_sample_pos[3][2] = { { voffset, -2 }, { voffset, hoffset }, { voffset - 2, hoffset }, }; - const int allow_extension = (xd->n4_h >= mi_size_high[BLOCK_8X8]) && - (xd->n4_h < mi_size_high[BLOCK_64X64]) && - (xd->n4_w >= mi_size_wide[BLOCK_8X8]) && - (xd->n4_w < mi_size_wide[BLOCK_64X64]); + const int allow_extension = (xd->height >= mi_size_high[BLOCK_8X8]) && + (xd->height < mi_size_high[BLOCK_64X64]) && + (xd->width >= mi_size_wide[BLOCK_8X8]) && + (xd->width < mi_size_wide[BLOCK_64X64]); - const int step_h = (xd->n4_h >= mi_size_high[BLOCK_64X64]) + const int step_h = (xd->height >= mi_size_high[BLOCK_64X64]) ? mi_size_high[BLOCK_16X16] : mi_size_high[BLOCK_8X8]; - const int step_w = (xd->n4_w >= mi_size_wide[BLOCK_64X64]) + const int step_w = (xd->width >= mi_size_wide[BLOCK_64X64]) ? mi_size_wide[BLOCK_16X16] : mi_size_wide[BLOCK_8X8]; @@ -600,17 +596,15 @@ static AOM_INLINE void setup_ref_mv_list( if (abs(row_offset) <= abs(max_row_offset) && abs(row_offset) > processed_rows) - scan_row_mbmi(cm, xd, mi_row, mi_col, rf, row_offset, ref_mv_stack, - ref_mv_weight, refmv_count, &row_match_count, - &dummy_newmv_count, gm_mv_candidates, max_row_offset, - &processed_rows); + scan_row_mbmi(cm, xd, mi_col, rf, row_offset, ref_mv_stack, ref_mv_weight, + refmv_count, &row_match_count, &dummy_newmv_count, + gm_mv_candidates, max_row_offset, &processed_rows); if (abs(col_offset) <= abs(max_col_offset) && abs(col_offset) > processed_cols) - scan_col_mbmi(cm, xd, mi_row, mi_col, rf, col_offset, ref_mv_stack, - ref_mv_weight, refmv_count, &col_match_count, - &dummy_newmv_count, gm_mv_candidates, max_col_offset, - &processed_cols); + scan_col_mbmi(cm, xd, mi_row, rf, col_offset, ref_mv_stack, ref_mv_weight, + refmv_count, &col_match_count, &dummy_newmv_count, + gm_mv_candidates, max_col_offset, &processed_cols); } const uint8_t ref_match_count = (row_match_count > 0) + (col_match_count > 0); @@ -676,10 +670,10 @@ static AOM_INLINE void setup_ref_mv_list( len = nr_len; } - int mi_width = AOMMIN(mi_size_wide[BLOCK_64X64], xd->n4_w); - mi_width = AOMMIN(mi_width, cm->mi_cols - mi_col); - int mi_height = AOMMIN(mi_size_high[BLOCK_64X64], xd->n4_h); - mi_height = AOMMIN(mi_height, cm->mi_rows - mi_row); + int mi_width = AOMMIN(mi_size_wide[BLOCK_64X64], xd->width); + mi_width = AOMMIN(mi_width, cm->mi_params.mi_cols - mi_col); + int mi_height = AOMMIN(mi_size_high[BLOCK_64X64], xd->height); + mi_height = AOMMIN(mi_height, cm->mi_params.mi_rows - mi_row); const int mi_size = AOMMIN(mi_width, mi_height); if (rf[1] > NONE_FRAME) { // TODO(jingning, yunqing): Refactor and consolidate the compound and @@ -744,10 +738,10 @@ static AOM_INLINE void setup_ref_mv_list( assert(*refmv_count >= 2); for (int idx = 0; idx < *refmv_count; ++idx) { - clamp_mv_ref(&ref_mv_stack[idx].this_mv.as_mv, xd->n4_w << MI_SIZE_LOG2, - xd->n4_h << MI_SIZE_LOG2, xd); - clamp_mv_ref(&ref_mv_stack[idx].comp_mv.as_mv, xd->n4_w << MI_SIZE_LOG2, - xd->n4_h << MI_SIZE_LOG2, xd); + clamp_mv_ref(&ref_mv_stack[idx].this_mv.as_mv, xd->width << MI_SIZE_LOG2, + xd->height << MI_SIZE_LOG2, xd); + clamp_mv_ref(&ref_mv_stack[idx].comp_mv.as_mv, xd->width << MI_SIZE_LOG2, + xd->height << MI_SIZE_LOG2, xd); } } else { // Handle single reference frame extension @@ -768,8 +762,8 @@ static AOM_INLINE void setup_ref_mv_list( } for (int idx = 0; idx < *refmv_count; ++idx) { - clamp_mv_ref(&ref_mv_stack[idx].this_mv.as_mv, xd->n4_w << MI_SIZE_LOG2, - xd->n4_h << MI_SIZE_LOG2, xd); + clamp_mv_ref(&ref_mv_stack[idx].this_mv.as_mv, xd->width << MI_SIZE_LOG2, + xd->height << MI_SIZE_LOG2, xd); } if (mv_ref_list != NULL) { @@ -790,8 +784,9 @@ void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd, CANDIDATE_MV ref_mv_stack[][MAX_REF_MV_STACK_SIZE], uint16_t ref_mv_weight[][MAX_REF_MV_STACK_SIZE], int_mv mv_ref_list[][MAX_MV_REF_CANDIDATES], - int_mv *global_mvs, int mi_row, int mi_col, - int16_t *mode_context) { + int_mv *global_mvs, int16_t *mode_context) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; int_mv gm_mv[2]; if (ref_frame == INTRA_FRAME) { @@ -801,21 +796,23 @@ void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd, } } else { const BLOCK_SIZE bsize = mi->sb_type; + const int allow_high_precision_mv = cm->features.allow_high_precision_mv; + const int force_integer_mv = cm->features.cur_frame_force_integer_mv; if (ref_frame < REF_FRAMES) { - gm_mv[0] = gm_get_motion_vector( - &cm->global_motion[ref_frame], cm->allow_high_precision_mv, bsize, - mi_col, mi_row, cm->cur_frame_force_integer_mv); + gm_mv[0] = gm_get_motion_vector(&cm->global_motion[ref_frame], + allow_high_precision_mv, bsize, mi_col, + mi_row, force_integer_mv); gm_mv[1].as_int = 0; if (global_mvs != NULL) global_mvs[ref_frame] = gm_mv[0]; } else { MV_REFERENCE_FRAME rf[2]; av1_set_ref_frame(rf, ref_frame); - gm_mv[0] = gm_get_motion_vector( - &cm->global_motion[rf[0]], cm->allow_high_precision_mv, bsize, mi_col, - mi_row, cm->cur_frame_force_integer_mv); - gm_mv[1] = gm_get_motion_vector( - &cm->global_motion[rf[1]], cm->allow_high_precision_mv, bsize, mi_col, - mi_row, cm->cur_frame_force_integer_mv); + gm_mv[0] = gm_get_motion_vector(&cm->global_motion[rf[0]], + allow_high_precision_mv, bsize, mi_col, + mi_row, force_integer_mv); + gm_mv[1] = gm_get_motion_vector(&cm->global_motion[rf[1]], + allow_high_precision_mv, bsize, mi_col, + mi_row, force_integer_mv); } } @@ -887,8 +884,8 @@ static int get_block_position(AV1_COMMON *cm, int *mi_r, int *mi_c, int blk_row, const int col = (sign_bias == 1) ? blk_col - col_offset : blk_col + col_offset; - if (row < 0 || row >= (cm->mi_rows >> 1) || col < 0 || - col >= (cm->mi_cols >> 1)) + if (row < 0 || row >= (cm->mi_params.mi_rows >> 1) || col < 0 || + col >= (cm->mi_params.mi_cols >> 1)) return 0; if (row < base_blk_row - (MAX_OFFSET_HEIGHT >> 3) || @@ -922,8 +919,8 @@ static int motion_field_projection(AV1_COMMON *cm, start_frame_buf->frame_type == INTRA_ONLY_FRAME) return 0; - if (start_frame_buf->mi_rows != cm->mi_rows || - start_frame_buf->mi_cols != cm->mi_cols) + if (start_frame_buf->mi_rows != cm->mi_params.mi_rows || + start_frame_buf->mi_cols != cm->mi_params.mi_cols) return 0; const int start_frame_order_hint = start_frame_buf->order_hint; @@ -942,8 +939,8 @@ static int motion_field_projection(AV1_COMMON *cm, if (dir == 2) start_to_current_frame_offset = -start_to_current_frame_offset; MV_REF *mv_ref_base = start_frame_buf->mvs; - const int mvs_rows = (cm->mi_rows + 1) >> 1; - const int mvs_cols = (cm->mi_cols + 1) >> 1; + const int mvs_rows = (cm->mi_params.mi_rows + 1) >> 1; + const int mvs_cols = (cm->mi_params.mi_cols + 1) >> 1; for (int blk_row = 0; blk_row < mvs_rows; ++blk_row) { for (int blk_col = 0; blk_col < mvs_cols; ++blk_col) { @@ -968,7 +965,7 @@ static int motion_field_projection(AV1_COMMON *cm, } if (pos_valid) { - const int mi_offset = mi_r * (cm->mi_stride >> 1) + mi_c; + const int mi_offset = mi_r * (cm->mi_params.mi_stride >> 1) + mi_c; tpl_mvs_base[mi_offset].mfmv0.as_mv.row = fwd_mv.row; tpl_mvs_base[mi_offset].mfmv0.as_mv.col = fwd_mv.col; @@ -988,7 +985,8 @@ void av1_setup_motion_field(AV1_COMMON *cm) { if (!order_hint_info->enable_order_hint) return; TPL_MV_REF *tpl_mvs_base = cm->tpl_mvs; - int size = ((cm->mi_rows + MAX_MIB_SIZE) >> 1) * (cm->mi_stride >> 1); + int size = ((cm->mi_params.mi_rows + MAX_MIB_SIZE) >> 1) * + (cm->mi_params.mi_stride >> 1); for (int idx = 0; idx < size; ++idx) { tpl_mvs_base[idx].mfmv0.as_int = INVALID_MV; tpl_mvs_base[idx].ref_frame_offset = 0; @@ -1057,10 +1055,10 @@ static INLINE void record_samples(const MB_MODE_INFO *mbmi, int *pts, int x = col_offset * MI_SIZE + sign_c * AOMMAX(bw, MI_SIZE) / 2 - 1; int y = row_offset * MI_SIZE + sign_r * AOMMAX(bh, MI_SIZE) / 2 - 1; - pts[0] = (x * 8); - pts[1] = (y * 8); - pts_inref[0] = (x * 8) + mbmi->mv[0].as_mv.col; - pts_inref[1] = (y * 8) + mbmi->mv[0].as_mv.row; + pts[0] = GET_MV_SUBPEL(x); + pts[1] = GET_MV_SUBPEL(y); + pts_inref[0] = GET_MV_SUBPEL(x) + mbmi->mv[0].as_mv.col; + pts_inref[1] = GET_MV_SUBPEL(y) + mbmi->mv[0].as_mv.row; } // Select samples according to the motion vector difference. @@ -1112,8 +1110,8 @@ uint8_t av1_selectSamples(MV *mv, int *pts, int *pts_inref, int len, // Note: Samples returned are at 1/8-pel precision // Sample are the neighbor block center point's coordinates relative to the // left-top pixel of current block. -uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, - int mi_col, int *pts, int *pts_inref) { +uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int *pts, + int *pts_inref) { const MB_MODE_INFO *const mbmi0 = xd->mi[0]; const int ref_frame = mbmi0->ref_frame[0]; const int up_available = xd->up_available; @@ -1123,19 +1121,21 @@ uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int do_tl = 1; int do_tr = 1; const int mi_stride = xd->mi_stride; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; // scan the nearest above rows if (up_available) { const int mi_row_offset = -1; const MB_MODE_INFO *mbmi = xd->mi[mi_row_offset * mi_stride]; - uint8_t n4_w = mi_size_wide[mbmi->sb_type]; + uint8_t superblock_width = mi_size_wide[mbmi->sb_type]; - if (xd->n4_w <= n4_w) { + if (xd->width <= superblock_width) { // Handle "current block width <= above block width" case. - const int col_offset = -mi_col % n4_w; + const int col_offset = -mi_col % superblock_width; if (col_offset < 0) do_tl = 0; - if (col_offset + n4_w > xd->n4_w) do_tr = 0; + if (col_offset + superblock_width > xd->width) do_tr = 0; if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, 0, -1, col_offset, 1); @@ -1146,10 +1146,11 @@ uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, } } else { // Handle "current block width > above block width" case. - for (i = 0; i < AOMMIN(xd->n4_w, cm->mi_cols - mi_col); i += mi_step) { + for (i = 0; i < AOMMIN(xd->width, cm->mi_params.mi_cols - mi_col); + i += mi_step) { mbmi = xd->mi[i + mi_row_offset * mi_stride]; - n4_w = mi_size_wide[mbmi->sb_type]; - mi_step = AOMMIN(xd->n4_w, n4_w); + superblock_width = mi_size_wide[mbmi->sb_type]; + mi_step = AOMMIN(xd->width, superblock_width); if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE_FRAME) { @@ -1168,11 +1169,11 @@ uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, if (left_available) { const int mi_col_offset = -1; const MB_MODE_INFO *mbmi = xd->mi[mi_col_offset]; - uint8_t n4_h = mi_size_high[mbmi->sb_type]; + uint8_t superblock_height = mi_size_high[mbmi->sb_type]; - if (xd->n4_h <= n4_h) { + if (xd->height <= superblock_height) { // Handle "current block height <= above block height" case. - const int row_offset = -mi_row % n4_h; + const int row_offset = -mi_row % superblock_height; if (row_offset < 0) do_tl = 0; @@ -1185,10 +1186,11 @@ uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, } } else { // Handle "current block height > above block height" case. - for (i = 0; i < AOMMIN(xd->n4_h, cm->mi_rows - mi_row); i += mi_step) { + for (i = 0; i < AOMMIN(xd->height, cm->mi_params.mi_rows - mi_row); + i += mi_step) { mbmi = xd->mi[mi_col_offset + i * mi_stride]; - n4_h = mi_size_high[mbmi->sb_type]; - mi_step = AOMMIN(xd->n4_h, n4_h); + superblock_height = mi_size_high[mbmi->sb_type]; + mi_step = AOMMIN(xd->height, superblock_height); if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE_FRAME) { @@ -1221,17 +1223,17 @@ uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, // Top-right block if (do_tr && - has_top_right(cm, xd, mi_row, mi_col, AOMMAX(xd->n4_w, xd->n4_h))) { - const POSITION trb_pos = { -1, xd->n4_w }; + has_top_right(cm, xd, mi_row, mi_col, AOMMAX(xd->width, xd->height))) { + const POSITION trb_pos = { -1, xd->width }; const TileInfo *const tile = &xd->tile; if (is_inside(tile, mi_col, mi_row, &trb_pos)) { const int mi_row_offset = -1; - const int mi_col_offset = xd->n4_w; + const int mi_col_offset = xd->width; const MB_MODE_INFO *mbmi = xd->mi[mi_col_offset + mi_row_offset * mi_stride]; if (mbmi->ref_frame[0] == ref_frame && mbmi->ref_frame[1] == NONE_FRAME) { - record_samples(mbmi, pts, pts_inref, 0, -1, xd->n4_w, 1); + record_samples(mbmi, pts, pts_inref, 0, -1, xd->width, 1); np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } diff --git a/media/libaom/src/av1/common/mvref_common.h b/media/libaom/src/av1/common/mvref_common.h index 482d5fdafd..05a0dbc041 100644 --- a/media/libaom/src/av1/common/mvref_common.h +++ b/media/libaom/src/av1/common/mvref_common.h @@ -11,7 +11,7 @@ #ifndef AOM_AV1_COMMON_MVREF_COMMON_H_ #define AOM_AV1_COMMON_MVREF_COMMON_H_ -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #ifdef __cplusplus @@ -50,23 +50,16 @@ static INLINE int get_relative_dist(const OrderHintInfo *oh, int a, int b) { } static INLINE void clamp_mv_ref(MV *mv, int bw, int bh, const MACROBLOCKD *xd) { - clamp_mv(mv, xd->mb_to_left_edge - bw * 8 - MV_BORDER, - xd->mb_to_right_edge + bw * 8 + MV_BORDER, - xd->mb_to_top_edge - bh * 8 - MV_BORDER, - xd->mb_to_bottom_edge + bh * 8 + MV_BORDER); + const SubpelMvLimits mv_limits = { + xd->mb_to_left_edge - GET_MV_SUBPEL(bw) - MV_BORDER, + xd->mb_to_right_edge + GET_MV_SUBPEL(bw) + MV_BORDER, + xd->mb_to_top_edge - GET_MV_SUBPEL(bh) - MV_BORDER, + xd->mb_to_bottom_edge + GET_MV_SUBPEL(bh) + MV_BORDER + }; + clamp_mv(mv, &mv_limits); } -// This function returns either the appropriate sub block or block's mv -// on whether the block_size < 8x8 and we have check_sub_blocks set. -static INLINE int_mv get_sub_block_mv(const MB_MODE_INFO *candidate, - int which_mv, int search_col) { - (void)search_col; - return candidate->mv[which_mv]; -} - -static INLINE int_mv get_sub_block_pred_mv(const MB_MODE_INFO *candidate, - int which_mv, int search_col) { - (void)search_col; +static INLINE int_mv get_block_mv(const MB_MODE_INFO *candidate, int which_mv) { return candidate->mv[which_mv]; } @@ -252,8 +245,7 @@ void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd, CANDIDATE_MV ref_mv_stack[][MAX_REF_MV_STACK_SIZE], uint16_t ref_mv_weight[][MAX_REF_MV_STACK_SIZE], int_mv mv_ref_list[][MAX_MV_REF_CANDIDATES], - int_mv *global_mvs, int mi_row, int mi_col, - int16_t *mode_context); + int_mv *global_mvs, int16_t *mode_context); // check a list of motion vectors by sad score using a number rows of pixels // above and a number cols of pixels in the left to select the one with best @@ -263,24 +255,22 @@ void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv, uint8_t av1_selectSamples(MV *mv, int *pts, int *pts_inref, int len, BLOCK_SIZE bsize); -uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, - int mi_col, int *pts, int *pts_inref); +uint8_t av1_findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int *pts, + int *pts_inref); #define INTRABC_DELAY_PIXELS 256 // Delay of 256 pixels #define INTRABC_DELAY_SB64 (INTRABC_DELAY_PIXELS / 64) static INLINE void av1_find_ref_dv(int_mv *ref_dv, const TileInfo *const tile, - int mib_size, int mi_row, int mi_col) { - (void)mi_col; + int mib_size, int mi_row) { if (mi_row - mib_size < tile->mi_row_start) { - ref_dv->as_mv.row = 0; - ref_dv->as_mv.col = -MI_SIZE * mib_size - INTRABC_DELAY_PIXELS; + ref_dv->as_fullmv.row = 0; + ref_dv->as_fullmv.col = -MI_SIZE * mib_size - INTRABC_DELAY_PIXELS; } else { - ref_dv->as_mv.row = -MI_SIZE * mib_size; - ref_dv->as_mv.col = 0; + ref_dv->as_fullmv.row = -MI_SIZE * mib_size; + ref_dv->as_fullmv.col = 0; } - ref_dv->as_mv.row *= 8; - ref_dv->as_mv.col *= 8; + convert_fullmv_to_mv(ref_dv); } static INLINE int av1_is_dv_valid(const MV dv, const AV1_COMMON *cm, @@ -312,15 +302,12 @@ static INLINE int av1_is_dv_valid(const MV dv, const AV1_COMMON *cm, // Special case for sub 8x8 chroma cases, to prevent referring to chroma // pixels outside current tile. - for (int plane = 1; plane < av1_num_planes(cm); ++plane) { - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) { - if (bw < 8 && pd->subsampling_x) - if (src_left_edge < tile_left_edge + 4 * SCALE_PX_TO_MV) return 0; - if (bh < 8 && pd->subsampling_y) - if (src_top_edge < tile_top_edge + 4 * SCALE_PX_TO_MV) return 0; - } + if (xd->is_chroma_ref && av1_num_planes(cm) > 1) { + const struct macroblockd_plane *const pd = &xd->plane[1]; + if (bw < 8 && pd->subsampling_x) + if (src_left_edge < tile_left_edge + 4 * SCALE_PX_TO_MV) return 0; + if (bh < 8 && pd->subsampling_y) + if (src_top_edge < tile_top_edge + 4 * SCALE_PX_TO_MV) return 0; } // Is the bottom right within an already coded SB? Also consider additional diff --git a/media/libaom/src/av1/common/obmc.h b/media/libaom/src/av1/common/obmc.h index 1c90cd93fc..cc97b6bb12 100644 --- a/media/libaom/src/av1/common/obmc.h +++ b/media/libaom/src/av1/common/obmc.h @@ -12,25 +12,24 @@ #ifndef AOM_AV1_COMMON_OBMC_H_ #define AOM_AV1_COMMON_OBMC_H_ -typedef void (*overlappable_nb_visitor_t)(MACROBLOCKD *xd, int rel_mi_pos, - uint8_t nb_mi_size, - MB_MODE_INFO *nb_mi, void *fun_ctxt, - const int num_planes); +typedef void (*overlappable_nb_visitor_t)(MACROBLOCKD *xd, int rel_mi_row, + int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *nb_mi, + void *fun_ctxt, const int num_planes); static INLINE void foreach_overlappable_nb_above(const AV1_COMMON *cm, - MACROBLOCKD *xd, int mi_col, - int nb_max, + MACROBLOCKD *xd, int nb_max, overlappable_nb_visitor_t fun, void *fun_ctxt) { - const int num_planes = av1_num_planes(cm); if (!xd->up_available) return; + const int num_planes = av1_num_planes(cm); int nb_count = 0; - + const int mi_col = xd->mi_col; // prev_row_mi points into the mi array, starting at the beginning of the // previous row. MB_MODE_INFO **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride; - const int end_col = AOMMIN(mi_col + xd->n4_w, cm->mi_cols); + const int end_col = AOMMIN(mi_col + xd->width, cm->mi_params.mi_cols); uint8_t mi_step; for (int above_mi_col = mi_col; above_mi_col < end_col && nb_count < nb_max; above_mi_col += mi_step) { @@ -49,26 +48,25 @@ static INLINE void foreach_overlappable_nb_above(const AV1_COMMON *cm, } if (is_neighbor_overlappable(*above_mi)) { ++nb_count; - fun(xd, above_mi_col - mi_col, AOMMIN(xd->n4_w, mi_step), *above_mi, - fun_ctxt, num_planes); + fun(xd, 0, above_mi_col - mi_col, AOMMIN(xd->width, mi_step), 0, + *above_mi, fun_ctxt, num_planes); } } } static INLINE void foreach_overlappable_nb_left(const AV1_COMMON *cm, - MACROBLOCKD *xd, int mi_row, - int nb_max, + MACROBLOCKD *xd, int nb_max, overlappable_nb_visitor_t fun, void *fun_ctxt) { - const int num_planes = av1_num_planes(cm); if (!xd->left_available) return; + const int num_planes = av1_num_planes(cm); int nb_count = 0; - // prev_col_mi points into the mi array, starting at the top of the // previous column + const int mi_row = xd->mi_row; MB_MODE_INFO **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride; - const int end_row = AOMMIN(mi_row + xd->n4_h, cm->mi_rows); + const int end_row = AOMMIN(mi_row + xd->height, cm->mi_params.mi_rows); uint8_t mi_step; for (int left_mi_row = mi_row; left_mi_row < end_row && nb_count < nb_max; left_mi_row += mi_step) { @@ -82,7 +80,7 @@ static INLINE void foreach_overlappable_nb_left(const AV1_COMMON *cm, } if (is_neighbor_overlappable(*left_mi)) { ++nb_count; - fun(xd, left_mi_row - mi_row, AOMMIN(xd->n4_h, mi_step), *left_mi, + fun(xd, left_mi_row - mi_row, 0, AOMMIN(xd->height, mi_step), 1, *left_mi, fun_ctxt, num_planes); } } diff --git a/media/libaom/src/av1/common/pred_common.h b/media/libaom/src/av1/common/pred_common.h index a681e4e0d6..d1dab97e72 100644 --- a/media/libaom/src/av1/common/pred_common.h +++ b/media/libaom/src/av1/common/pred_common.h @@ -12,29 +12,31 @@ #ifndef AOM_AV1_COMMON_PRED_COMMON_H_ #define AOM_AV1_COMMON_PRED_COMMON_H_ +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/mvref_common.h" -#include "av1/common/onyxc_int.h" #include "aom_dsp/aom_dsp_common.h" #ifdef __cplusplus extern "C" { #endif -static INLINE int get_segment_id(const AV1_COMMON *const cm, +static INLINE int get_segment_id(const CommonModeInfoParams *const mi_params, const uint8_t *segment_ids, BLOCK_SIZE bsize, int mi_row, int mi_col) { - const int mi_offset = mi_row * cm->mi_cols + mi_col; + const int mi_offset = mi_row * mi_params->mi_cols + mi_col; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; - const int xmis = AOMMIN(cm->mi_cols - mi_col, bw); - const int ymis = AOMMIN(cm->mi_rows - mi_row, bh); - int x, y, segment_id = MAX_SEGMENTS; + const int xmis = AOMMIN(mi_params->mi_cols - mi_col, bw); + const int ymis = AOMMIN(mi_params->mi_rows - mi_row, bh); + int segment_id = MAX_SEGMENTS; - for (y = 0; y < ymis; ++y) - for (x = 0; x < xmis; ++x) - segment_id = - AOMMIN(segment_id, segment_ids[mi_offset + y * cm->mi_cols + x]); + for (int y = 0; y < ymis; ++y) { + for (int x = 0; x < xmis; ++x) { + segment_id = AOMMIN(segment_id, + segment_ids[mi_offset + y * mi_params->mi_cols + x]); + } + } assert(segment_id >= 0 && segment_id < MAX_SEGMENTS); return segment_id; @@ -42,22 +44,25 @@ static INLINE int get_segment_id(const AV1_COMMON *const cm, static INLINE int av1_get_spatial_seg_pred(const AV1_COMMON *const cm, const MACROBLOCKD *const xd, - int mi_row, int mi_col, int *cdf_index) { int prev_ul = -1; // top left segment_id int prev_l = -1; // left segment_id int prev_u = -1; // top segment_id + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const uint8_t *seg_map = cm->cur_frame->seg_map; if ((xd->up_available) && (xd->left_available)) { - prev_ul = get_segment_id(cm, cm->cur_frame->seg_map, BLOCK_4X4, mi_row - 1, - mi_col - 1); + prev_ul = + get_segment_id(mi_params, seg_map, BLOCK_4X4, mi_row - 1, mi_col - 1); } if (xd->up_available) { - prev_u = get_segment_id(cm, cm->cur_frame->seg_map, BLOCK_4X4, mi_row - 1, - mi_col - 0); + prev_u = + get_segment_id(mi_params, seg_map, BLOCK_4X4, mi_row - 1, mi_col - 0); } if (xd->left_available) { - prev_l = get_segment_id(cm, cm->cur_frame->seg_map, BLOCK_4X4, mi_row - 0, - mi_col - 1); + prev_l = + get_segment_id(mi_params, 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 @@ -203,6 +208,10 @@ static INLINE aom_cdf_prob *av1_get_reference_mode_cdf(const MACROBLOCKD *xd) { return xd->tile_ctx->comp_inter_cdf[av1_get_reference_mode_context(xd)]; } +static INLINE aom_cdf_prob *av1_get_skip_cdf(const MACROBLOCKD *xd) { + return xd->tile_ctx->skip_cdfs[av1_get_skip_context(xd)]; +} + int av1_get_comp_reference_type_context(const MACROBLOCKD *xd); // == Uni-directional contexts == diff --git a/media/libaom/src/av1/common/quant_common.c b/media/libaom/src/av1/common/quant_common.c index 75379493df..e96d71a3b1 100644 --- a/media/libaom/src/av1/common/quant_common.c +++ b/media/libaom/src/av1/common/quant_common.c @@ -9,12 +9,12 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include "av1/common/av1_common_int.h" +#include "av1/common/blockd.h" #include "av1/common/common.h" -#include "av1/common/onyxc_int.h" #include "av1/common/entropy.h" #include "av1/common/quant_common.h" #include "av1/common/seg_common.h" -#include "av1/common/blockd.h" static const int16_t dc_qlookup_QTX[QINDEX_RANGE] = { 4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, @@ -225,13 +225,53 @@ int av1_get_qindex(const struct segmentation *seg, int segment_id, } } -const qm_val_t *av1_iqmatrix(AV1_COMMON *cm, int qmlevel, int plane, - TX_SIZE tx_size) { - return &cm->giqmatrix[qmlevel][plane][tx_size][0]; +bool av1_use_qmatrix(const CommonQuantParams *quant_params, + const struct macroblockd *xd, int segment_id) { + // True if explicit Q matrix levels and this is not a lossless segment. + return quant_params->using_qmatrix && !xd->lossless[segment_id]; } -const qm_val_t *av1_qmatrix(AV1_COMMON *cm, int qmlevel, int plane, - TX_SIZE tx_size) { - return &cm->gqmatrix[qmlevel][plane][tx_size][0]; + +const qm_val_t *av1_iqmatrix(const CommonQuantParams *quant_params, int qmlevel, + int plane, TX_SIZE tx_size) { + assert(quant_params->giqmatrix[qmlevel][plane][tx_size] != NULL || + qmlevel == NUM_QM_LEVELS - 1); + return quant_params->giqmatrix[qmlevel][plane][tx_size]; +} +const qm_val_t *av1_qmatrix(const CommonQuantParams *quant_params, int qmlevel, + int plane, TX_SIZE tx_size) { + assert(quant_params->gqmatrix[qmlevel][plane][tx_size] != NULL || + qmlevel == NUM_QM_LEVELS - 1); + return quant_params->gqmatrix[qmlevel][plane][tx_size]; +} + +// Returns true if the tx_type corresponds to non-identity transform in both +// horizontal and vertical directions. +static INLINE bool is_2d_transform(TX_TYPE tx_type) { return (tx_type < IDTX); } + +const qm_val_t *av1_get_iqmatrix(const CommonQuantParams *quant_params, + const MACROBLOCKD *xd, int plane, + TX_SIZE tx_size, TX_TYPE tx_type) { + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const MB_MODE_INFO *const mbmi = xd->mi[0]; + const int seg_id = mbmi->segment_id; + const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); + // Use a flat matrix (i.e. no weighting) for 1D and Identity transforms + return is_2d_transform(tx_type) + ? pd->seg_iqmatrix[seg_id][qm_tx_size] + : quant_params->giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; +} + +const qm_val_t *av1_get_qmatrix(const CommonQuantParams *quant_params, + const MACROBLOCKD *xd, int plane, + TX_SIZE tx_size, TX_TYPE tx_type) { + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const MB_MODE_INFO *const mbmi = xd->mi[0]; + const int seg_id = mbmi->segment_id; + const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); + // Use a flat matrix (i.e. no weighting) for 1D and Identity transforms + return is_2d_transform(tx_type) + ? pd->seg_qmatrix[seg_id][qm_tx_size] + : quant_params->gqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; } #define QM_TOTAL_SIZE 3344 @@ -240,26 +280,27 @@ const qm_val_t *av1_qmatrix(AV1_COMMON *cm, int qmlevel, int plane, static const qm_val_t wt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE]; static const qm_val_t iwt_matrix_ref[NUM_QM_LEVELS - 1][2][QM_TOTAL_SIZE]; -void av1_qm_init(AV1_COMMON *cm) { - const int num_planes = av1_num_planes(cm); - int q, c, t; - int current; - for (q = 0; q < NUM_QM_LEVELS; ++q) { - for (c = 0; c < num_planes; ++c) { - current = 0; - for (t = 0; t < TX_SIZES_ALL; ++t) { +void av1_qm_init(CommonQuantParams *quant_params, int num_planes) { + for (int q = 0; q < NUM_QM_LEVELS; ++q) { + for (int c = 0; c < num_planes; ++c) { + int current = 0; + for (int t = 0; t < TX_SIZES_ALL; ++t) { const int size = tx_size_2d[t]; const int qm_tx_size = av1_get_adjusted_tx_size(t); if (q == NUM_QM_LEVELS - 1) { - cm->gqmatrix[q][c][t] = NULL; - cm->giqmatrix[q][c][t] = NULL; + quant_params->gqmatrix[q][c][t] = NULL; + quant_params->giqmatrix[q][c][t] = NULL; } else if (t != qm_tx_size) { // Reuse matrices for 'qm_tx_size' - cm->gqmatrix[q][c][t] = cm->gqmatrix[q][c][qm_tx_size]; - cm->giqmatrix[q][c][t] = cm->giqmatrix[q][c][qm_tx_size]; + assert(t > qm_tx_size); + quant_params->gqmatrix[q][c][t] = + quant_params->gqmatrix[q][c][qm_tx_size]; + quant_params->giqmatrix[q][c][t] = + quant_params->giqmatrix[q][c][qm_tx_size]; } else { assert(current + size <= QM_TOTAL_SIZE); - cm->gqmatrix[q][c][t] = &wt_matrix_ref[q][c >= 1][current]; - cm->giqmatrix[q][c][t] = &iwt_matrix_ref[q][c >= 1][current]; + quant_params->gqmatrix[q][c][t] = &wt_matrix_ref[q][c >= 1][current]; + quant_params->giqmatrix[q][c][t] = + &iwt_matrix_ref[q][c >= 1][current]; current += size; } } diff --git a/media/libaom/src/av1/common/quant_common.h b/media/libaom/src/av1/common/quant_common.h index 050dd269a3..9c30204ff0 100644 --- a/media/libaom/src/av1/common/quant_common.h +++ b/media/libaom/src/av1/common/quant_common.h @@ -12,6 +12,7 @@ #ifndef AOM_AV1_COMMON_QUANT_COMMON_H_ #define AOM_AV1_COMMON_QUANT_COMMON_H_ +#include #include "aom/aom_codec.h" #include "av1/common/seg_common.h" #include "av1/common/enums.h" @@ -37,22 +38,43 @@ extern "C" { #define DEFAULT_QM_LAST 9 struct AV1Common; +struct CommonQuantParams; +struct macroblockd; int16_t av1_dc_quant_QTX(int qindex, int delta, aom_bit_depth_t bit_depth); int16_t av1_ac_quant_QTX(int qindex, int delta, aom_bit_depth_t bit_depth); int av1_get_qindex(const struct segmentation *seg, int segment_id, int base_qindex); + +// Returns true if we are using quantization matrix. +bool av1_use_qmatrix(const struct CommonQuantParams *quant_params, + const struct macroblockd *xd, int segment_id); + // Reduce the large number of quantizers to a smaller number of levels for which // different matrices may be defined static INLINE int aom_get_qmlevel(int qindex, int first, int last) { return first + (qindex * (last + 1 - first)) / QINDEX_RANGE; } -void av1_qm_init(struct AV1Common *cm); -const qm_val_t *av1_iqmatrix(struct AV1Common *cm, int qmlevel, int plane, - TX_SIZE tx_size); -const qm_val_t *av1_qmatrix(struct AV1Common *cm, int qmlevel, int plane, - TX_SIZE tx_size); + +// Initialize all global quant/dequant matrices. +void av1_qm_init(struct CommonQuantParams *quant_params, int num_planes); + +// Get global dequant matrix. +const qm_val_t *av1_iqmatrix(const struct CommonQuantParams *quant_params, + int qmlevel, int plane, TX_SIZE tx_size); +// Get global quant matrix. +const qm_val_t *av1_qmatrix(const struct CommonQuantParams *quant_params, + int qmlevel, int plane, TX_SIZE tx_size); + +// Get either local / global dequant matrix as appropriate. +const qm_val_t *av1_get_iqmatrix(const struct CommonQuantParams *quant_params, + const struct macroblockd *xd, int plane, + TX_SIZE tx_size, TX_TYPE tx_type); +// Get either local / global quant matrix as appropriate. +const qm_val_t *av1_get_qmatrix(const struct CommonQuantParams *quant_params, + const struct macroblockd *xd, int plane, + TX_SIZE tx_size, TX_TYPE tx_type); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/common/reconinter.c b/media/libaom/src/av1/common/reconinter.c index 90a87ecdf4..287adddcc0 100644 --- a/media/libaom/src/av1/common/reconinter.c +++ b/media/libaom/src/av1/common/reconinter.c @@ -20,12 +20,12 @@ #include "aom/aom_integer.h" #include "aom_dsp/blend.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/mvref_common.h" +#include "av1/common/obmc.h" #include "av1/common/reconinter.h" #include "av1/common/reconintra.h" -#include "av1/common/onyxc_int.h" -#include "av1/common/obmc.h" // This function will determine whether or not to create a warped // prediction. @@ -61,6 +61,7 @@ void av1_init_inter_params(InterPredParams *inter_pred_params, int block_width, int subsampling_x, int subsampling_y, int bit_depth, int use_hbd_buf, int is_intrabc, const struct scale_factors *sf, + const struct buf_2d *ref_buf, int_interpfilters interp_filters) { inter_pred_params->block_width = block_width; inter_pred_params->block_height = block_height; @@ -72,7 +73,9 @@ void av1_init_inter_params(InterPredParams *inter_pred_params, int block_width, inter_pred_params->use_hbd_buf = use_hbd_buf; inter_pred_params->is_intrabc = is_intrabc; inter_pred_params->scale_factors = sf; - inter_pred_params->mode = UNIFORM_PRED; + inter_pred_params->ref_frame_buf = *ref_buf; + inter_pred_params->mode = TRANSLATION_PRED; + inter_pred_params->comp_mode = UNIFORM_SINGLE; if (is_intrabc) { inter_pred_params->interp_filter_params[0] = &av1_intrabc_filter_params; @@ -87,8 +90,11 @@ void av1_init_inter_params(InterPredParams *inter_pred_params, int block_width, } } +void av1_init_comp_mode(InterPredParams *inter_pred_params) { + inter_pred_params->comp_mode = UNIFORM_COMP; +} + void av1_init_warp_params(InterPredParams *inter_pred_params, - const struct buf_2d *ref_buf, const WarpTypesAllowed *warp_types, int ref, const MACROBLOCKD *xd, const MB_MODE_INFO *mi) { if (inter_pred_params->block_height < 8 || inter_pred_params->block_width < 8) @@ -100,8 +106,17 @@ void av1_init_warp_params(InterPredParams *inter_pred_params, inter_pred_params->scale_factors, &inter_pred_params->warp_params)) inter_pred_params->mode = WARP_PRED; +} - inter_pred_params->ref_frame_buf = *ref_buf; +void av1_init_mask_comp(InterPredParams *inter_pred_params, BLOCK_SIZE bsize, + const INTERINTER_COMPOUND_DATA *mask_comp) { + inter_pred_params->sb_type = bsize; + inter_pred_params->mask_comp = *mask_comp; + + if (inter_pred_params->conv_params.compound_index == 1) { + inter_pred_params->conv_params.do_average = 0; + inter_pred_params->comp_mode = MASK_COMP; + } } void av1_make_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, @@ -123,7 +138,7 @@ void av1_make_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, inter_pred_params->block_width, inter_pred_params->block_height, dst_stride, inter_pred_params->subsampling_x, inter_pred_params->subsampling_y, &inter_pred_params->conv_params); - } else if (inter_pred_params->mode == UNIFORM_PRED) { + } else if (inter_pred_params->mode == TRANSLATION_PRED) { #if CONFIG_AV1_HIGHBITDEPTH if (inter_pred_params->use_hbd_buf) { highbd_inter_predictor( @@ -218,6 +233,10 @@ DECLARE_ALIGNED( DECLARE_ALIGNED(16, static uint8_t, wedge_mask_buf[2 * MAX_WEDGE_TYPES * 4 * MAX_WEDGE_SQUARE]); +DECLARE_ALIGNED(16, static uint8_t, + smooth_interintra_mask_buf[INTERINTRA_MODES][BLOCK_SIZES_ALL] + [MAX_WEDGE_SQUARE]); + static wedge_masks_type wedge_masks[BLOCK_SIZES_ALL][2]; static const wedge_code_type wedge_codebook_16_hgtw[16] = { @@ -257,19 +276,19 @@ const wedge_params_type av1_wedge_params_lookup[BLOCK_SIZES_ALL] = { { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, - { 4, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_8X8], + { MAX_WEDGE_TYPES, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_8X8], wedge_masks[BLOCK_8X8] }, - { 4, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_8X16], + { MAX_WEDGE_TYPES, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_8X16], wedge_masks[BLOCK_8X16] }, - { 4, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_16X8], + { MAX_WEDGE_TYPES, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_16X8], wedge_masks[BLOCK_16X8] }, - { 4, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_16X16], + { MAX_WEDGE_TYPES, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_16X16], wedge_masks[BLOCK_16X16] }, - { 4, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_16X32], + { MAX_WEDGE_TYPES, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_16X32], wedge_masks[BLOCK_16X32] }, - { 4, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_32X16], + { MAX_WEDGE_TYPES, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_32X16], wedge_masks[BLOCK_32X16] }, - { 4, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_32X32], + { MAX_WEDGE_TYPES, wedge_codebook_16_heqw, wedge_signflip_lookup[BLOCK_32X32], wedge_masks[BLOCK_32X32] }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, @@ -279,9 +298,9 @@ const wedge_params_type av1_wedge_params_lookup[BLOCK_SIZES_ALL] = { { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, - { 4, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_8X32], + { MAX_WEDGE_TYPES, wedge_codebook_16_hgtw, wedge_signflip_lookup[BLOCK_8X32], wedge_masks[BLOCK_8X32] }, - { 4, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_32X8], + { MAX_WEDGE_TYPES, wedge_codebook_16_hltw, wedge_signflip_lookup[BLOCK_32X8], wedge_masks[BLOCK_32X8] }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL }, @@ -298,8 +317,7 @@ static const uint8_t *get_wedge_mask_inplace(int wedge_index, int neg, const uint8_t wsignflip = av1_wedge_params_lookup[sb_type].signflip[wedge_index]; - assert(wedge_index >= 0 && - wedge_index < (1 << get_wedge_bits_lookup(sb_type))); + assert(wedge_index >= 0 && wedge_index < get_wedge_types_lookup(sb_type)); woff = (a->x_offset * bw) >> 3; hoff = (a->y_offset * bh) >> 3; master = wedge_mask_obl[neg ^ wsignflip][a->direction] + @@ -516,14 +534,13 @@ static AOM_INLINE void init_wedge_masks() { BLOCK_SIZE bsize; memset(wedge_masks, 0, sizeof(wedge_masks)); for (bsize = BLOCK_4X4; bsize < BLOCK_SIZES_ALL; ++bsize) { + const wedge_params_type *wedge_params = &av1_wedge_params_lookup[bsize]; + const int wtypes = wedge_params->wedge_types; + if (wtypes == 0) continue; const uint8_t *mask; const int bw = block_size_wide[bsize]; const int bh = block_size_high[bsize]; - const wedge_params_type *wedge_params = &av1_wedge_params_lookup[bsize]; - const int wbits = wedge_params->bits; - const int wtypes = 1 << wbits; int w; - if (wbits == 0) continue; for (w = 0; w < wtypes; ++w) { mask = get_wedge_mask_inplace(w, 0, bsize); aom_convolve_copy(mask, MASK_MASTER_STRIDE, dst, bw, NULL, 0, NULL, 0, bw, @@ -541,54 +558,123 @@ static AOM_INLINE void init_wedge_masks() { } } +/* clang-format off */ +static const uint8_t ii_weights1d[MAX_SB_SIZE] = { + 60, 58, 56, 54, 52, 50, 48, 47, 45, 44, 42, 41, 39, 38, 37, 35, 34, 33, 32, + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 22, 21, 20, 19, 19, 18, 18, 17, 16, + 16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8, + 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, + 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; +static uint8_t ii_size_scales[BLOCK_SIZES_ALL] = { + 32, 16, 16, 16, 8, 8, 8, 4, + 4, 4, 2, 2, 2, 1, 1, 1, + 8, 8, 4, 4, 2, 2 +}; +/* clang-format on */ + +static AOM_INLINE void build_smooth_interintra_mask(uint8_t *mask, int stride, + BLOCK_SIZE plane_bsize, + INTERINTRA_MODE mode) { + int i, j; + const int bw = block_size_wide[plane_bsize]; + const int bh = block_size_high[plane_bsize]; + const int size_scale = ii_size_scales[plane_bsize]; + + switch (mode) { + case II_V_PRED: + for (i = 0; i < bh; ++i) { + memset(mask, ii_weights1d[i * size_scale], bw * sizeof(mask[0])); + mask += stride; + } + break; + + case II_H_PRED: + for (i = 0; i < bh; ++i) { + for (j = 0; j < bw; ++j) mask[j] = ii_weights1d[j * size_scale]; + mask += stride; + } + break; + + case II_SMOOTH_PRED: + for (i = 0; i < bh; ++i) { + for (j = 0; j < bw; ++j) + mask[j] = ii_weights1d[(i < j ? i : j) * size_scale]; + mask += stride; + } + break; + + case II_DC_PRED: + default: + for (i = 0; i < bh; ++i) { + memset(mask, 32, bw * sizeof(mask[0])); + mask += stride; + } + break; + } +} + +static AOM_INLINE void init_smooth_interintra_masks() { + for (int m = 0; m < INTERINTRA_MODES; ++m) { + for (int bs = 0; bs < BLOCK_SIZES_ALL; ++bs) { + const int bw = block_size_wide[bs]; + const int bh = block_size_high[bs]; + if (bw > MAX_WEDGE_SIZE || bh > MAX_WEDGE_SIZE) continue; + build_smooth_interintra_mask(smooth_interintra_mask_buf[m][bs], bw, bs, + m); + } + } +} + // Equation of line: f(x, y) = a[0]*(x - a[2]*w/8) + a[1]*(y - a[3]*h/8) = 0 void av1_init_wedge_masks() { init_wedge_master_masks(); init_wedge_masks(); + init_smooth_interintra_masks(); } static AOM_INLINE void build_masked_compound_no_round( uint8_t *dst, int dst_stride, const CONV_BUF_TYPE *src0, int src0_stride, const CONV_BUF_TYPE *src1, int src1_stride, const INTERINTER_COMPOUND_DATA *const comp_data, BLOCK_SIZE sb_type, int h, - int w, ConvolveParams *conv_params, MACROBLOCKD *xd) { - // Derive subsampling from h and w passed in. May be refactored to - // pass in subsampling factors directly. - const int subh = (2 << mi_size_high_log2[sb_type]) == h; - const int subw = (2 << mi_size_wide_log2[sb_type]) == w; + int w, InterPredParams *inter_pred_params) { + const int ssy = inter_pred_params->subsampling_y; + const int ssx = inter_pred_params->subsampling_x; const uint8_t *mask = av1_get_compound_type_mask(comp_data, sb_type); + const int mask_stride = block_size_wide[sb_type]; #if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { + if (inter_pred_params->use_hbd_buf) { aom_highbd_blend_a64_d16_mask(dst, dst_stride, src0, src0_stride, src1, - src1_stride, mask, block_size_wide[sb_type], - w, h, subw, subh, conv_params, xd->bd); + src1_stride, mask, mask_stride, w, h, ssx, + ssy, &inter_pred_params->conv_params, + inter_pred_params->bit_depth); } else { aom_lowbd_blend_a64_d16_mask(dst, dst_stride, src0, src0_stride, src1, - src1_stride, mask, block_size_wide[sb_type], w, - h, subw, subh, conv_params); + src1_stride, mask, mask_stride, w, h, ssx, ssy, + &inter_pred_params->conv_params); } #else - (void)xd; aom_lowbd_blend_a64_d16_mask(dst, dst_stride, src0, src0_stride, src1, - src1_stride, mask, block_size_wide[sb_type], w, - h, subw, subh, conv_params); + src1_stride, mask, mask_stride, w, h, ssx, ssy, + &inter_pred_params->conv_params); #endif } void av1_make_masked_inter_predictor(const uint8_t *pre, int pre_stride, uint8_t *dst, int dst_stride, InterPredParams *inter_pred_params, - const SubpelParams *subpel_params, int w, - int h, int plane, MACROBLOCKD *xd) { - MB_MODE_INFO *mi = xd->mi[0]; - mi->interinter_comp.seg_mask = xd->seg_mask; - const INTERINTER_COMPOUND_DATA *comp_data = &mi->interinter_comp; + const SubpelParams *subpel_params) { + const INTERINTER_COMPOUND_DATA *comp_data = &inter_pred_params->mask_comp; + BLOCK_SIZE sb_type = inter_pred_params->sb_type; // We're going to call av1_make_inter_predictor to generate a prediction into // a temporary buffer, then will blend that temporary buffer with that from // the other reference. DECLARE_ALIGNED(32, uint8_t, tmp_buf[2 * MAX_SB_SQUARE]); - uint8_t *tmp_dst = get_buf_by_bd(xd, tmp_buf); + uint8_t *tmp_dst = + inter_pred_params->use_hbd_buf ? CONVERT_TO_BYTEPTR(tmp_buf) : tmp_buf; const int tmp_buf_stride = MAX_SB_SIZE; CONV_BUF_TYPE *org_dst = inter_pred_params->conv_params.dst; @@ -602,15 +688,226 @@ void av1_make_masked_inter_predictor(const uint8_t *pre, int pre_stride, av1_make_inter_predictor(pre, pre_stride, tmp_dst, MAX_SB_SIZE, inter_pred_params, subpel_params); - if (!plane && comp_data->type == COMPOUND_DIFFWTD) { + if (!inter_pred_params->conv_params.plane && + comp_data->type == COMPOUND_DIFFWTD) { av1_build_compound_diffwtd_mask_d16( comp_data->seg_mask, comp_data->mask_type, org_dst, org_dst_stride, - tmp_buf16, tmp_buf_stride, h, w, &inter_pred_params->conv_params, - xd->bd); + tmp_buf16, tmp_buf_stride, inter_pred_params->block_height, + inter_pred_params->block_width, &inter_pred_params->conv_params, + inter_pred_params->bit_depth); } build_masked_compound_no_round( dst, dst_stride, org_dst, org_dst_stride, tmp_buf16, tmp_buf_stride, - comp_data, mi->sb_type, h, w, &inter_pred_params->conv_params, xd); + comp_data, sb_type, inter_pred_params->block_height, + inter_pred_params->block_width, inter_pred_params); +} + +void av1_build_one_inter_predictor( + uint8_t *dst, int dst_stride, const MV *const src_mv, + InterPredParams *inter_pred_params, MACROBLOCKD *xd, int mi_x, int mi_y, + int ref, CalcSubpelParamsFunc calc_subpel_params_func) { + SubpelParams subpel_params; + uint8_t *src; + int src_stride; + calc_subpel_params_func(src_mv, inter_pred_params, xd, mi_x, mi_y, ref, &src, + &subpel_params, &src_stride); + + if (inter_pred_params->comp_mode == UNIFORM_SINGLE || + inter_pred_params->comp_mode == UNIFORM_COMP) { + av1_make_inter_predictor(src, src_stride, dst, dst_stride, + inter_pred_params, &subpel_params); + } else { + av1_make_masked_inter_predictor(src, src_stride, dst, dst_stride, + inter_pred_params, &subpel_params); + } +} + +// True if the following hold: +// 1. Not intrabc and not build_for_obmc +// 2. A U or V plane +// 3. If the block size differs from the base block size +// 4. If sub-sampled, none of the previous blocks around the sub-sample +// are intrabc or inter-blocks +static bool is_sub8x8_inter(const MACROBLOCKD *xd, int plane, BLOCK_SIZE bsize, + int is_intrabc, int build_for_obmc) { + if (is_intrabc || build_for_obmc) { + return false; + } + + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + if ((block_size_wide[bsize] >= 8 || !ss_x) && + (block_size_high[bsize] >= 8 || !ss_y)) { + return false; + } + + // For sub8x8 chroma blocks, we may be covering more than one luma block's + // worth of pixels. Thus (mi_x, mi_y) may not be the correct coordinates for + // the top-left corner of the prediction source - the correct top-left corner + // is at (pre_x, pre_y). + const int row_start = (block_size_high[bsize] == 4) && ss_y ? -1 : 0; + const int col_start = (block_size_wide[bsize] == 4) && ss_x ? -1 : 0; + + for (int row = row_start; row <= 0; ++row) { + for (int col = col_start; col <= 0; ++col) { + const MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; + if (!is_inter_block(this_mbmi)) return false; + if (is_intrabc_block(this_mbmi)) return false; + } + } + return true; +} + +static void build_inter_predictors_sub8x8( + const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, const MB_MODE_INFO *mi, + int bw, int bh, int mi_x, int mi_y, + CalcSubpelParamsFunc calc_subpel_params_func) { + const BLOCK_SIZE bsize = mi->sb_type; + struct macroblockd_plane *const pd = &xd->plane[plane]; + const bool ss_x = pd->subsampling_x; + const bool ss_y = pd->subsampling_y; + const int b4_w = block_size_wide[bsize] >> ss_x; + const int b4_h = block_size_high[bsize] >> ss_y; + const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, ss_x, ss_y); + const int b8_w = block_size_wide[plane_bsize]; + const int b8_h = block_size_high[plane_bsize]; + const int is_compound = has_second_ref(mi); + assert(!is_compound); + assert(!is_intrabc_block(mi)); + + // For sub8x8 chroma blocks, we may be covering more than one luma block's + // worth of pixels. Thus (mi_x, mi_y) may not be the correct coordinates for + // the top-left corner of the prediction source - the correct top-left corner + // is at (pre_x, pre_y). + const int row_start = (block_size_high[bsize] == 4) && ss_y ? -1 : 0; + const int col_start = (block_size_wide[bsize] == 4) && ss_x ? -1 : 0; + const int pre_x = (mi_x + MI_SIZE * col_start) >> ss_x; + const int pre_y = (mi_y + MI_SIZE * row_start) >> ss_y; + + int row = row_start; + for (int y = 0; y < b8_h; y += b4_h) { + int col = col_start; + for (int x = 0; x < b8_w; x += b4_w) { + MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; + int tmp_dst_stride = 8; + assert(bw < 8 || bh < 8); + (void)bw; + (void)bh; + struct buf_2d *const dst_buf = &pd->dst; + uint8_t *dst = dst_buf->buf + dst_buf->stride * y + x; + int ref = 0; + const RefCntBuffer *ref_buf = + get_ref_frame_buf(cm, this_mbmi->ref_frame[ref]); + const struct scale_factors *ref_scale_factors = + get_ref_scale_factors_const(cm, this_mbmi->ref_frame[ref]); + const struct scale_factors *const sf = ref_scale_factors; + const struct buf_2d pre_buf = { + NULL, + (plane == 1) ? ref_buf->buf.u_buffer : ref_buf->buf.v_buffer, + ref_buf->buf.uv_crop_width, + ref_buf->buf.uv_crop_height, + ref_buf->buf.uv_stride, + }; + + const MV mv = this_mbmi->mv[ref].as_mv; + + InterPredParams inter_pred_params; + av1_init_inter_params(&inter_pred_params, b4_w, b4_h, pre_y + y, + pre_x + x, pd->subsampling_x, pd->subsampling_y, + xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, + &pre_buf, this_mbmi->interp_filters); + inter_pred_params.conv_params = get_conv_params_no_round( + ref, plane, xd->tmp_conv_dst, tmp_dst_stride, is_compound, xd->bd); + inter_pred_params.conv_params.use_dist_wtd_comp_avg = 0; + + av1_build_one_inter_predictor(dst, dst_buf->stride, &mv, + &inter_pred_params, xd, mi_x + x, mi_y + y, + ref, calc_subpel_params_func); + + ++col; + } + ++row; + } +} + +static void build_inter_predictors_8x8_and_bigger( + const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, const MB_MODE_INFO *mi, + int build_for_obmc, int bw, int bh, int mi_x, int mi_y, + CalcSubpelParamsFunc calc_subpel_params_func) { + const int is_compound = has_second_ref(mi); + const int is_intrabc = is_intrabc_block(mi); + assert(IMPLIES(is_intrabc, !is_compound)); + struct macroblockd_plane *const pd = &xd->plane[plane]; + struct buf_2d *const dst_buf = &pd->dst; + uint8_t *const dst = dst_buf->buf; + + int is_global[2] = { 0, 0 }; + for (int ref = 0; ref < 1 + is_compound; ++ref) { + const WarpedMotionParams *const wm = &xd->global_motion[mi->ref_frame[ref]]; + is_global[ref] = is_global_mv_block(mi, wm->wmtype); + } + + const BLOCK_SIZE bsize = mi->sb_type; + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const int row_start = + (block_size_high[bsize] == 4) && ss_y && !build_for_obmc ? -1 : 0; + const int col_start = + (block_size_wide[bsize] == 4) && ss_x && !build_for_obmc ? -1 : 0; + const int pre_x = (mi_x + MI_SIZE * col_start) >> ss_x; + const int pre_y = (mi_y + MI_SIZE * row_start) >> ss_y; + + for (int ref = 0; ref < 1 + is_compound; ++ref) { + const struct scale_factors *const sf = + is_intrabc ? &cm->sf_identity : xd->block_ref_scale_factors[ref]; + struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; + const MV mv = mi->mv[ref].as_mv; + const WarpTypesAllowed warp_types = { is_global[ref], + mi->motion_mode == WARPED_CAUSAL }; + + InterPredParams inter_pred_params; + av1_init_inter_params(&inter_pred_params, bw, bh, pre_y, pre_x, + pd->subsampling_x, pd->subsampling_y, xd->bd, + is_cur_buf_hbd(xd), mi->use_intrabc, sf, pre_buf, + mi->interp_filters); + if (is_compound) av1_init_comp_mode(&inter_pred_params); + inter_pred_params.conv_params = get_conv_params_no_round( + ref, plane, xd->tmp_conv_dst, MAX_SB_SIZE, is_compound, xd->bd); + + av1_dist_wtd_comp_weight_assign( + cm, mi, 0, &inter_pred_params.conv_params.fwd_offset, + &inter_pred_params.conv_params.bck_offset, + &inter_pred_params.conv_params.use_dist_wtd_comp_avg, is_compound); + + if (!build_for_obmc) + av1_init_warp_params(&inter_pred_params, &warp_types, ref, xd, mi); + + if (is_masked_compound_type(mi->interinter_comp.type)) { + av1_init_mask_comp(&inter_pred_params, mi->sb_type, &mi->interinter_comp); + // Assign physical buffer. + inter_pred_params.mask_comp.seg_mask = xd->seg_mask; + } + + av1_build_one_inter_predictor(dst, dst_buf->stride, &mv, &inter_pred_params, + xd, mi_x, mi_y, ref, calc_subpel_params_func); + } +} + +void av1_build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, + int plane, const MB_MODE_INFO *mi, + int build_for_obmc, int bw, int bh, int mi_x, + int mi_y, + CalcSubpelParamsFunc calc_subpel_params_func) { + if (is_sub8x8_inter(xd, plane, mi->sb_type, is_intrabc_block(mi), + build_for_obmc)) { + build_inter_predictors_sub8x8(cm, xd, plane, mi, bw, bh, mi_x, mi_y, + calc_subpel_params_func); + } else { + build_inter_predictors_8x8_and_bigger(cm, xd, plane, mi, build_for_obmc, bw, + bh, mi_x, mi_y, + calc_subpel_params_func); + } } void av1_dist_wtd_comp_weight_assign(const AV1_COMMON *cm, @@ -729,19 +1026,21 @@ const uint8_t *av1_get_obmc_mask(int length) { } } -static INLINE void increment_int_ptr(MACROBLOCKD *xd, int rel_mi_rc, - uint8_t mi_hw, MB_MODE_INFO *mi, - void *fun_ctxt, const int num_planes) { +static INLINE void increment_int_ptr(MACROBLOCKD *xd, int rel_mi_row, + int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *mi, void *fun_ctxt, + const int num_planes) { (void)xd; - (void)rel_mi_rc; - (void)mi_hw; + (void)rel_mi_row; + (void)rel_mi_col; + (void)op_mi_size; + (void)dir; (void)mi; ++*(int *)fun_ctxt; (void)num_planes; } -void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col) { +void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd) { MB_MODE_INFO *mbmi = xd->mi[0]; mbmi->overlappable_neighbors[0] = 0; @@ -749,9 +1048,9 @@ void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd, if (!is_motion_variation_allowed_bsize(mbmi->sb_type)) return; - foreach_overlappable_nb_above(cm, xd, mi_col, INT_MAX, increment_int_ptr, + foreach_overlappable_nb_above(cm, xd, INT_MAX, increment_int_ptr, &mbmi->overlappable_neighbors[0]); - foreach_overlappable_nb_left(cm, xd, mi_row, INT_MAX, increment_int_ptr, + foreach_overlappable_nb_left(cm, xd, INT_MAX, increment_int_ptr, &mbmi->overlappable_neighbors[1]); } @@ -792,12 +1091,12 @@ struct obmc_inter_pred_ctxt { int *adjacent_stride; }; -static INLINE void build_obmc_inter_pred_above(MACROBLOCKD *xd, int rel_mi_col, - uint8_t above_mi_width, - MB_MODE_INFO *above_mi, - void *fun_ctxt, - const int num_planes) { +static INLINE void build_obmc_inter_pred_above( + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *above_mi, void *fun_ctxt, const int num_planes) { (void)above_mi; + (void)rel_mi_row; + (void)dir; struct obmc_inter_pred_ctxt *ctxt = (struct obmc_inter_pred_ctxt *)fun_ctxt; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; const int overlap = @@ -805,7 +1104,7 @@ static INLINE void build_obmc_inter_pred_above(MACROBLOCKD *xd, int rel_mi_col, for (int plane = 0; plane < num_planes; ++plane) { const struct macroblockd_plane *pd = &xd->plane[plane]; - const int bw = (above_mi_width * MI_SIZE) >> pd->subsampling_x; + const int bw = (op_mi_size * MI_SIZE) >> pd->subsampling_x; const int bh = overlap >> pd->subsampling_y; const int plane_col = (rel_mi_col * MI_SIZE) >> pd->subsampling_x; @@ -831,12 +1130,12 @@ static INLINE void build_obmc_inter_pred_above(MACROBLOCKD *xd, int rel_mi_col, } } -static INLINE void build_obmc_inter_pred_left(MACROBLOCKD *xd, int rel_mi_row, - uint8_t left_mi_height, - MB_MODE_INFO *left_mi, - void *fun_ctxt, - const int num_planes) { +static INLINE void build_obmc_inter_pred_left( + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *left_mi, void *fun_ctxt, const int num_planes) { (void)left_mi; + (void)rel_mi_col; + (void)dir; struct obmc_inter_pred_ctxt *ctxt = (struct obmc_inter_pred_ctxt *)fun_ctxt; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; const int overlap = @@ -845,7 +1144,7 @@ static INLINE void build_obmc_inter_pred_left(MACROBLOCKD *xd, int rel_mi_row, for (int plane = 0; plane < num_planes; ++plane) { const struct macroblockd_plane *pd = &xd->plane[plane]; const int bw = overlap >> pd->subsampling_x; - const int bh = (left_mi_height * MI_SIZE) >> pd->subsampling_y; + const int bh = (op_mi_size * MI_SIZE) >> pd->subsampling_y; const int plane_row = (rel_mi_row * MI_SIZE) >> pd->subsampling_y; if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue; @@ -876,7 +1175,6 @@ static INLINE void build_obmc_inter_pred_left(MACROBLOCKD *xd, int rel_mi_row, // prediction. We assume the original prediction (bmc) is stored in // xd->plane[].dst.buf void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *above[MAX_MB_PLANE], int above_stride[MAX_MB_PLANE], uint8_t *left[MAX_MB_PLANE], @@ -885,23 +1183,54 @@ void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd, // handle above row struct obmc_inter_pred_ctxt ctxt_above = { above, above_stride }; - foreach_overlappable_nb_above(cm, xd, mi_col, + foreach_overlappable_nb_above(cm, xd, max_neighbor_obmc[mi_size_wide_log2[bsize]], build_obmc_inter_pred_above, &ctxt_above); // handle left column struct obmc_inter_pred_ctxt ctxt_left = { left, left_stride }; - foreach_overlappable_nb_left(cm, xd, mi_row, + foreach_overlappable_nb_left(cm, xd, max_neighbor_obmc[mi_size_high_log2[bsize]], build_obmc_inter_pred_left, &ctxt_left); } +void av1_setup_address_for_obmc(MACROBLOCKD *xd, int mi_row_offset, + int mi_col_offset, MB_MODE_INFO *ref_mbmi, + struct build_prediction_ctxt *ctxt, + const int num_planes) { + const BLOCK_SIZE ref_bsize = AOMMAX(BLOCK_8X8, ref_mbmi->sb_type); + const int ref_mi_row = xd->mi_row + mi_row_offset; + const int ref_mi_col = xd->mi_col + mi_col_offset; + + for (int plane = 0; plane < num_planes; ++plane) { + struct macroblockd_plane *const pd = &xd->plane[plane]; + setup_pred_plane(&pd->dst, ref_bsize, ctxt->tmp_buf[plane], + ctxt->tmp_width[plane], ctxt->tmp_height[plane], + ctxt->tmp_stride[plane], mi_row_offset, mi_col_offset, + NULL, pd->subsampling_x, pd->subsampling_y); + } + + const MV_REFERENCE_FRAME frame = ref_mbmi->ref_frame[0]; + + const RefCntBuffer *const ref_buf = get_ref_frame_buf(ctxt->cm, frame); + const struct scale_factors *const sf = + get_ref_scale_factors_const(ctxt->cm, frame); + + xd->block_ref_scale_factors[0] = sf; + if ((!av1_is_valid_scale(sf))) + aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, + "Reference frame has invalid dimensions"); + + av1_setup_pre_planes(xd, 0, &ref_buf->buf, ref_mi_row, ref_mi_col, sf, + num_planes); +} + void av1_setup_build_prediction_by_above_pred( MACROBLOCKD *xd, int rel_mi_col, uint8_t above_mi_width, MB_MODE_INFO *above_mbmi, struct build_prediction_ctxt *ctxt, const int num_planes) { const BLOCK_SIZE a_bsize = AOMMAX(BLOCK_8X8, above_mbmi->sb_type); - const int above_mi_col = ctxt->mi_col + rel_mi_col; + const int above_mi_col = xd->mi_col + rel_mi_col; av1_modify_neighbor_predictor_for_obmc(above_mbmi); @@ -924,13 +1253,14 @@ void av1_setup_build_prediction_by_above_pred( if ((!av1_is_valid_scale(sf))) aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, "Reference frame has invalid dimensions"); - av1_setup_pre_planes(xd, ref, &ref_buf->buf, ctxt->mi_row, above_mi_col, sf, + av1_setup_pre_planes(xd, ref, &ref_buf->buf, xd->mi_row, above_mi_col, sf, num_planes); } xd->mb_to_left_edge = 8 * MI_SIZE * (-above_mi_col); - xd->mb_to_right_edge = ctxt->mb_to_far_edge + - (xd->n4_w - rel_mi_col - above_mi_width) * MI_SIZE * 8; + xd->mb_to_right_edge = + ctxt->mb_to_far_edge + + (xd->width - rel_mi_col - above_mi_width) * MI_SIZE * 8; } void av1_setup_build_prediction_by_left_pred(MACROBLOCKD *xd, int rel_mi_row, @@ -939,7 +1269,7 @@ void av1_setup_build_prediction_by_left_pred(MACROBLOCKD *xd, int rel_mi_row, struct build_prediction_ctxt *ctxt, const int num_planes) { const BLOCK_SIZE l_bsize = AOMMAX(BLOCK_8X8, left_mbmi->sb_type); - const int left_mi_row = ctxt->mi_row + rel_mi_row; + const int left_mi_row = xd->mi_row + rel_mi_row; av1_modify_neighbor_predictor_for_obmc(left_mbmi); @@ -963,72 +1293,14 @@ void av1_setup_build_prediction_by_left_pred(MACROBLOCKD *xd, int rel_mi_row, if ((!av1_is_valid_scale(ref_scale_factors))) aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM, "Reference frame has invalid dimensions"); - av1_setup_pre_planes(xd, ref, &ref_buf->buf, left_mi_row, ctxt->mi_col, + av1_setup_pre_planes(xd, ref, &ref_buf->buf, left_mi_row, xd->mi_col, ref_scale_factors, num_planes); } - xd->mb_to_top_edge = 8 * MI_SIZE * (-left_mi_row); + xd->mb_to_top_edge = GET_MV_SUBPEL(MI_SIZE * (-left_mi_row)); xd->mb_to_bottom_edge = ctxt->mb_to_far_edge + - (xd->n4_h - rel_mi_row - left_mi_height) * MI_SIZE * 8; -} - -/* clang-format off */ -static const uint8_t ii_weights1d[MAX_SB_SIZE] = { - 60, 58, 56, 54, 52, 50, 48, 47, 45, 44, 42, 41, 39, 38, 37, 35, 34, 33, 32, - 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 22, 21, 20, 19, 19, 18, 18, 17, 16, - 16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8, - 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, - 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 -}; -static uint8_t ii_size_scales[BLOCK_SIZES_ALL] = { - 32, 16, 16, 16, 8, 8, 8, 4, - 4, 4, 2, 2, 2, 1, 1, 1, - 8, 8, 4, 4, 2, 2 -}; -/* clang-format on */ - -static AOM_INLINE void build_smooth_interintra_mask(uint8_t *mask, int stride, - BLOCK_SIZE plane_bsize, - INTERINTRA_MODE mode) { - int i, j; - const int bw = block_size_wide[plane_bsize]; - const int bh = block_size_high[plane_bsize]; - const int size_scale = ii_size_scales[plane_bsize]; - - switch (mode) { - case II_V_PRED: - for (i = 0; i < bh; ++i) { - memset(mask, ii_weights1d[i * size_scale], bw * sizeof(mask[0])); - mask += stride; - } - break; - - case II_H_PRED: - for (i = 0; i < bh; ++i) { - for (j = 0; j < bw; ++j) mask[j] = ii_weights1d[j * size_scale]; - mask += stride; - } - break; - - case II_SMOOTH_PRED: - for (i = 0; i < bh; ++i) { - for (j = 0; j < bw; ++j) - mask[j] = ii_weights1d[(i < j ? i : j) * size_scale]; - mask += stride; - } - break; - - case II_DC_PRED: - default: - for (i = 0; i < bh; ++i) { - memset(mask, 32, bw * sizeof(mask[0])); - mask += stride; - } - break; - } + GET_MV_SUBPEL((xd->height - rel_mi_row - left_mi_height) * MI_SIZE); } static AOM_INLINE void combine_interintra( @@ -1040,7 +1312,7 @@ static AOM_INLINE void combine_interintra( const int bh = block_size_high[plane_bsize]; if (use_wedge_interintra) { - if (is_interintra_wedge_used(bsize)) { + if (av1_is_wedge_used(bsize)) { const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); const int subw = 2 * mi_size_wide[bsize] == bw; @@ -1052,8 +1324,7 @@ static AOM_INLINE void combine_interintra( return; } - uint8_t mask[MAX_SB_SQUARE]; - build_smooth_interintra_mask(mask, bw, plane_bsize, mode); + const uint8_t *mask = smooth_interintra_mask_buf[mode][plane_bsize]; aom_blend_a64_mask(comppred, compstride, intrapred, intrastride, interpred, interstride, mask, bw, bw, bh, 0, 0); } @@ -1068,7 +1339,7 @@ static AOM_INLINE void combine_interintra_highbd( const int bh = block_size_high[plane_bsize]; if (use_wedge_interintra) { - if (is_interintra_wedge_used(bsize)) { + if (av1_is_wedge_used(bsize)) { const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); const int subh = 2 * mi_size_high[bsize] == bh; @@ -1133,10 +1404,10 @@ void av1_combine_interintra(MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane, } // build interintra_predictors for one plane -void av1_build_interintra_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd, - uint8_t *pred, int stride, - const BUFFER_SET *ctx, int plane, - BLOCK_SIZE bsize) { +void av1_build_interintra_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd, + uint8_t *pred, int stride, + const BUFFER_SET *ctx, int plane, + BLOCK_SIZE bsize) { assert(bsize < BLOCK_SIZES_ALL); if (is_cur_buf_hbd(xd)) { DECLARE_ALIGNED(16, uint16_t, intrapredictor[MAX_SB_SQUARE]); @@ -1153,12 +1424,3 @@ void av1_build_interintra_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd, MAX_SB_SIZE); } } - -void av1_build_interintra_predictors_sbuv(const AV1_COMMON *cm, MACROBLOCKD *xd, - uint8_t *upred, uint8_t *vpred, - int ustride, int vstride, - const BUFFER_SET *ctx, - BLOCK_SIZE bsize) { - av1_build_interintra_predictors_sbp(cm, xd, upred, ustride, ctx, 1, bsize); - av1_build_interintra_predictors_sbp(cm, xd, vpred, vstride, ctx, 2, bsize); -} diff --git a/media/libaom/src/av1/common/reconinter.h b/media/libaom/src/av1/common/reconinter.h index 2332c817e5..fe3c6a6217 100644 --- a/media/libaom/src/av1/common/reconinter.h +++ b/media/libaom/src/av1/common/reconinter.h @@ -12,9 +12,9 @@ #ifndef AOM_AV1_COMMON_RECONINTER_H_ #define AOM_AV1_COMMON_RECONINTER_H_ -#include "av1/common/filter.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/convolve.h" +#include "av1/common/filter.h" #include "av1/common/warped_motion.h" #include "aom/aom_integer.h" @@ -35,8 +35,7 @@ extern "C" { #endif -// Set to (1 << 5) if the 32-ary codebooks are used for any bock size -#define MAX_WEDGE_TYPES (1 << 4) +#define MAX_WEDGE_TYPES 16 #define MAX_WEDGE_SIZE_LOG2 5 // 32x32 #define MAX_WEDGE_SIZE (1 << MAX_WEDGE_SIZE_LOG2) @@ -67,7 +66,7 @@ typedef struct { typedef uint8_t *wedge_masks_type[MAX_WEDGE_TYPES]; typedef struct { - int bits; + int wedge_types; const wedge_code_type *codebook; uint8_t *signflip; wedge_masks_type *masks; @@ -84,8 +83,6 @@ typedef struct SubpelParams { struct build_prediction_ctxt { const AV1_COMMON *cm; - int mi_row; - int mi_col; uint8_t **tmp_buf; int *tmp_width; int *tmp_height; @@ -94,13 +91,19 @@ struct build_prediction_ctxt { }; typedef enum InterPredMode { - UNIFORM_PRED, + TRANSLATION_PRED, WARP_PRED, - MASK_PRED, } InterPredMode; +typedef enum InterCompMode { + UNIFORM_SINGLE, + UNIFORM_COMP, + MASK_COMP, +} InterCompMode; + typedef struct InterPredParams { InterPredMode mode; + InterCompMode comp_mode; WarpedMotionParams warp_params; ConvolveParams conv_params; const InterpFilterParams *interp_filter_params[2]; @@ -114,6 +117,8 @@ typedef struct InterPredParams { const struct scale_factors *scale_factors; int bit_depth; int use_hbd_buf; + INTERINTER_COMPOUND_DATA mask_comp; + BLOCK_SIZE sb_type; int is_intrabc; } InterPredParams; @@ -122,13 +127,18 @@ void av1_init_inter_params(InterPredParams *inter_pred_params, int block_width, int subsampling_x, int subsampling_y, int bit_depth, int use_hbd_buf, int is_intrabc, const struct scale_factors *sf, + const struct buf_2d *ref_buf, int_interpfilters interp_filters); +void av1_init_comp_mode(InterPredParams *inter_pred_params); + void av1_init_warp_params(InterPredParams *inter_pred_params, - const struct buf_2d *ref_buf, const WarpTypesAllowed *warp_types, int ref, const MACROBLOCKD *xd, const MB_MODE_INFO *mi); +void av1_init_mask_comp(InterPredParams *inter_pred_params, BLOCK_SIZE bsize, + const INTERINTER_COMPOUND_DATA *mask_comp); + static INLINE int has_scale(int xs, int ys) { return xs != SCALE_SUBPEL_SHIFTS || ys != SCALE_SUBPEL_SHIFTS; } @@ -200,7 +210,7 @@ static INLINE int is_interinter_compound_used(COMPOUND_TYPE type, case COMPOUND_DISTWTD: case COMPOUND_DIFFWTD: return comp_allowed; case COMPOUND_WEDGE: - return comp_allowed && av1_wedge_params_lookup[sb_type].bits > 0; + return comp_allowed && av1_wedge_params_lookup[sb_type].wedge_types > 0; default: assert(0); return 0; } } @@ -218,21 +228,12 @@ static INLINE int is_any_masked_compound_used(BLOCK_SIZE sb_type) { return 0; } -static INLINE int get_wedge_bits_lookup(BLOCK_SIZE sb_type) { - return av1_wedge_params_lookup[sb_type].bits; +static INLINE int get_wedge_types_lookup(BLOCK_SIZE sb_type) { + return av1_wedge_params_lookup[sb_type].wedge_types; } -static INLINE int get_interinter_wedge_bits(BLOCK_SIZE sb_type) { - const int wbits = av1_wedge_params_lookup[sb_type].bits; - return (wbits > 0) ? wbits + 1 : 0; -} - -static INLINE int is_interintra_wedge_used(BLOCK_SIZE sb_type) { - return av1_wedge_params_lookup[sb_type].bits > 0; -} - -static INLINE int get_interintra_wedge_bits(BLOCK_SIZE sb_type) { - return av1_wedge_params_lookup[sb_type].bits; +static INLINE int av1_is_wedge_used(BLOCK_SIZE sb_type) { + return av1_wedge_params_lookup[sb_type].wedge_types > 0; } void av1_make_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, @@ -243,8 +244,25 @@ void av1_make_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, void av1_make_masked_inter_predictor(const uint8_t *pre, int pre_stride, uint8_t *dst, int dst_stride, InterPredParams *inter_pred_params, - const SubpelParams *subpel_params, int w, - int h, int plane, MACROBLOCKD *xd); + const SubpelParams *subpel_params); + +typedef void (*CalcSubpelParamsFunc)(const MV *const src_mv, + InterPredParams *const inter_pred_params, + MACROBLOCKD *xd, int mi_x, int mi_y, + int ref, uint8_t **pre, + SubpelParams *subpel_params, + int *src_stride); + +void av1_build_one_inter_predictor( + uint8_t *dst, int dst_stride, const MV *const src_mv, + InterPredParams *inter_pred_params, MACROBLOCKD *xd, int mi_x, int mi_y, + int ref, CalcSubpelParamsFunc calc_subpel_params_func); + +void av1_build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, + int plane, const MB_MODE_INFO *mi, + int build_for_obmc, int bw, int bh, int mi_x, + int mi_y, + CalcSubpelParamsFunc calc_subpel_params_func); // TODO(jkoleszar): yet another mv clamping function :-( static INLINE MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, @@ -261,11 +279,14 @@ static INLINE MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd, (int16_t)(src_mv->col * (1 << (1 - ss_x))) }; assert(ss_x <= 1); assert(ss_y <= 1); + const SubpelMvLimits mv_limits = { + xd->mb_to_left_edge * (1 << (1 - ss_x)) - spel_left, + xd->mb_to_right_edge * (1 << (1 - ss_x)) + spel_right, + xd->mb_to_top_edge * (1 << (1 - ss_y)) - spel_top, + xd->mb_to_bottom_edge * (1 << (1 - ss_y)) + spel_bottom + }; - clamp_mv(&clamped_mv, xd->mb_to_left_edge * (1 << (1 - ss_x)) - spel_left, - xd->mb_to_right_edge * (1 << (1 - ss_x)) + spel_right, - xd->mb_to_top_edge * (1 << (1 - ss_y)) - spel_top, - xd->mb_to_bottom_edge * (1 << (1 - ss_y)) + spel_bottom); + clamp_mv(&clamped_mv, &mv_limits); return clamped_mv; } @@ -322,6 +343,11 @@ static INLINE int av1_is_interp_needed(const MACROBLOCKD *const xd) { return 1; } +void av1_setup_address_for_obmc(MACROBLOCKD *xd, int mi_row_offset, + int mi_col_offset, MB_MODE_INFO *ref_mbmi, + struct build_prediction_ctxt *ctxt, + const int num_planes); + void av1_setup_build_prediction_by_above_pred( MACROBLOCKD *xd, int rel_mi_col, uint8_t above_mi_width, MB_MODE_INFO *above_mbmi, struct build_prediction_ctxt *ctxt, @@ -332,15 +358,13 @@ void av1_setup_build_prediction_by_left_pred(MACROBLOCKD *xd, int rel_mi_row, struct build_prediction_ctxt *ctxt, const int num_planes); void av1_build_obmc_inter_prediction(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *above[MAX_MB_PLANE], int above_stride[MAX_MB_PLANE], uint8_t *left[MAX_MB_PLANE], int left_stride[MAX_MB_PLANE]); const uint8_t *av1_get_obmc_mask(int length); -void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col); +void av1_count_overlappable_neighbors(const AV1_COMMON *cm, MACROBLOCKD *xd); #define MASK_MASTER_SIZE ((MAX_WEDGE_SIZE) << 1) #define MASK_MASTER_STRIDE (MASK_MASTER_SIZE) @@ -357,16 +381,10 @@ const uint8_t *av1_get_compound_type_mask( const INTERINTER_COMPOUND_DATA *const comp_data, BLOCK_SIZE sb_type); // build interintra_predictors for one plane -void av1_build_interintra_predictors_sbp(const AV1_COMMON *cm, MACROBLOCKD *xd, - uint8_t *pred, int stride, - const BUFFER_SET *ctx, int plane, - BLOCK_SIZE bsize); - -void av1_build_interintra_predictors_sbuv(const AV1_COMMON *cm, MACROBLOCKD *xd, - uint8_t *upred, uint8_t *vpred, - int ustride, int vstride, - const BUFFER_SET *ctx, - BLOCK_SIZE bsize); +void av1_build_interintra_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd, + uint8_t *pred, int stride, + const BUFFER_SET *ctx, int plane, + BLOCK_SIZE bsize); void av1_build_intra_predictors_for_interintra(const AV1_COMMON *cm, MACROBLOCKD *xd, diff --git a/media/libaom/src/av1/common/reconintra.c b/media/libaom/src/av1/common/reconintra.c index 0a9f5eee25..1307a03138 100644 --- a/media/libaom/src/av1/common/reconintra.c +++ b/media/libaom/src/av1/common/reconintra.c @@ -20,9 +20,9 @@ #include "aom_ports/aom_once.h" #include "aom_ports/mem.h" #include "aom_ports/system_state.h" -#include "av1/common/reconintra.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/cfl.h" +#include "av1/common/reconintra.h" enum { NEED_LEFT = 1 << 1, @@ -198,7 +198,7 @@ static int has_top_right(const AV1_COMMON *cm, BLOCK_SIZE bsize, int mi_row, int col_off, int ss_x, int ss_y) { if (!top_available || !right_available) return 0; - const int bw_unit = block_size_wide[bsize] >> tx_size_wide_log2[0]; + const int bw_unit = mi_size_wide[bsize]; const int plane_bw_unit = AOMMAX(bw_unit >> ss_x, 1); const int top_right_count_unit = tx_size_wide_unit[txsz]; @@ -405,7 +405,7 @@ static int has_bottom_left(const AV1_COMMON *cm, BLOCK_SIZE bsize, int mi_row, // Bottom-left pixels are in the bottom-left block, which is not available. return 0; } else { - const int bh_unit = block_size_high[bsize] >> tx_size_high_log2[0]; + const int bh_unit = mi_size_high[bsize]; const int plane_bh_unit = AOMMAX(bh_unit >> ss_y, 1); const int bottom_left_count_unit = tx_size_high_unit[txsz]; @@ -422,10 +422,9 @@ static int has_bottom_left(const AV1_COMMON *cm, BLOCK_SIZE bsize, int mi_row, // and/or bottom-left superblocks. But only the left superblock is // available, so check if all required pixels fall in that superblock. if (blk_col_in_sb == 0) { - const int blk_start_row_off = blk_row_in_sb - << (bh_in_mi_log2 + MI_SIZE_LOG2 - - tx_size_wide_log2[0]) >> - ss_y; + const int blk_start_row_off = + blk_row_in_sb << (bh_in_mi_log2 + MI_SIZE_LOG2 - MI_SIZE_LOG2) >> + ss_y; const int row_off_in_sb = blk_start_row_off + row_off; const int sb_height_unit = sb_mi_size >> ss_y; return row_off_in_sb + bottom_left_count_unit < sb_height_unit; @@ -855,10 +854,6 @@ void av1_filter_intra_predictor_c(uint8_t *dst, ptrdiff_t stride, assert(bw <= 32 && bh <= 32); - // The initialization is just for silencing Jenkins static analysis warnings - for (r = 0; r < bh + 1; ++r) - memset(buffer[r], 0, (bw + 1) * sizeof(buffer[0][0])); - for (r = 0; r < bh; ++r) buffer[r + 1][0] = left[r]; memcpy(buffer[0], &above[-1], (bw + 1) * sizeof(uint8_t)); @@ -906,10 +901,6 @@ static void highbd_filter_intra_predictor(uint16_t *dst, ptrdiff_t stride, assert(bw <= 32 && bh <= 32); - // The initialization is just for silencing Jenkins static analysis warnings - for (r = 0; r < bh + 1; ++r) - memset(buffer[r], 0, (bw + 1) * sizeof(buffer[0][0])); - for (r = 0; r < bh; ++r) buffer[r + 1][0] = left[r]; memcpy(buffer[0], &above[-1], (bw + 1) * sizeof(buffer[0][0])); @@ -1506,6 +1497,57 @@ static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref, } } +static INLINE BLOCK_SIZE scale_chroma_bsize(BLOCK_SIZE bsize, int subsampling_x, + int subsampling_y) { + assert(subsampling_x >= 0 && subsampling_x < 2); + assert(subsampling_y >= 0 && subsampling_y < 2); + BLOCK_SIZE bs = bsize; + switch (bsize) { + case BLOCK_4X4: + if (subsampling_x == 1 && subsampling_y == 1) + bs = BLOCK_8X8; + else if (subsampling_x == 1) + bs = BLOCK_8X4; + else if (subsampling_y == 1) + bs = BLOCK_4X8; + break; + case BLOCK_4X8: + if (subsampling_x == 1 && subsampling_y == 1) + bs = BLOCK_8X8; + else if (subsampling_x == 1) + bs = BLOCK_8X8; + else if (subsampling_y == 1) + bs = BLOCK_4X8; + break; + case BLOCK_8X4: + if (subsampling_x == 1 && subsampling_y == 1) + bs = BLOCK_8X8; + else if (subsampling_x == 1) + bs = BLOCK_8X4; + else if (subsampling_y == 1) + bs = BLOCK_8X8; + break; + case BLOCK_4X16: + if (subsampling_x == 1 && subsampling_y == 1) + bs = BLOCK_8X16; + else if (subsampling_x == 1) + bs = BLOCK_8X16; + else if (subsampling_y == 1) + bs = BLOCK_4X16; + break; + case BLOCK_16X4: + if (subsampling_x == 1 && subsampling_y == 1) + bs = BLOCK_16X8; + else if (subsampling_x == 1) + bs = BLOCK_16X4; + else if (subsampling_y == 1) + bs = BLOCK_16X8; + break; + default: break; + } + return bs; +} + void av1_predict_intra_block( const AV1_COMMON *cm, const MACROBLOCKD *xd, int wpx, int hpx, TX_SIZE tx_size, PREDICTION_MODE mode, int angle_delta, int use_palette, @@ -1514,8 +1556,8 @@ void av1_predict_intra_block( const MB_MODE_INFO *const mbmi = xd->mi[0]; const int txwpx = tx_size_wide[tx_size]; const int txhpx = tx_size_high[tx_size]; - const int x = col_off << tx_size_wide_log2[0]; - const int y = row_off << tx_size_high_log2[0]; + const int x = col_off << MI_SIZE_LOG2; + const int y = row_off << MI_SIZE_LOG2; if (use_palette) { int r, c; @@ -1541,15 +1583,15 @@ void av1_predict_intra_block( return; } - BLOCK_SIZE bsize = mbmi->sb_type; const struct macroblockd_plane *const pd = &xd->plane[plane]; const int txw = tx_size_wide_unit[tx_size]; const int txh = tx_size_high_unit[tx_size]; - const int have_top = row_off || (pd->subsampling_y ? xd->chroma_up_available - : xd->up_available); + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const int have_top = + row_off || (ss_y ? xd->chroma_up_available : xd->up_available); const int have_left = - col_off || - (pd->subsampling_x ? xd->chroma_left_available : xd->left_available); + col_off || (ss_x ? xd->chroma_left_available : xd->left_available); 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); const int xr_chr_offset = 0; @@ -1557,29 +1599,31 @@ void av1_predict_intra_block( // Distance between the right edge of this prediction block to // the frame right edge - const int xr = (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) + - (wpx - x - txwpx) - xr_chr_offset; + const int xr = + (xd->mb_to_right_edge >> (3 + ss_x)) + (wpx - x - txwpx) - xr_chr_offset; // Distance between the bottom edge of this prediction block to // the frame bottom edge - const int yd = (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) + - (hpx - y - txhpx) - yd_chr_offset; + const int yd = + (xd->mb_to_bottom_edge >> (3 + ss_y)) + (hpx - y - txhpx) - yd_chr_offset; const int right_available = - mi_col + ((col_off + txw) << pd->subsampling_x) < xd->tile.mi_col_end; + mi_col + ((col_off + txw) << ss_x) < xd->tile.mi_col_end; const int bottom_available = - (yd > 0) && - (mi_row + ((row_off + txh) << pd->subsampling_y) < xd->tile.mi_row_end); + (yd > 0) && (mi_row + ((row_off + txh) << ss_y) < xd->tile.mi_row_end); const PARTITION_TYPE partition = mbmi->partition; + BLOCK_SIZE bsize = mbmi->sb_type; // force 4x4 chroma component block size. - bsize = scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); + if (ss_x || ss_y) { + bsize = scale_chroma_bsize(bsize, ss_x, ss_y); + } - const int have_top_right = has_top_right( - cm, bsize, mi_row, mi_col, have_top, right_available, partition, tx_size, - row_off, col_off, pd->subsampling_x, pd->subsampling_y); - const int have_bottom_left = has_bottom_left( - cm, bsize, mi_row, mi_col, bottom_available, have_left, partition, - tx_size, row_off, col_off, pd->subsampling_x, pd->subsampling_y); + const int have_top_right = + has_top_right(cm, bsize, mi_row, mi_col, have_top, right_available, + partition, tx_size, row_off, col_off, ss_x, ss_y); + const int have_bottom_left = + has_bottom_left(cm, bsize, mi_row, mi_col, bottom_available, have_left, + partition, tx_size, row_off, col_off, ss_x, ss_y); const int disable_edge_filter = !cm->seq_params.enable_intra_edge_filter; #if CONFIG_AV1_HIGHBITDEPTH @@ -1609,8 +1653,7 @@ void av1_predict_intra_block_facade(const AV1_COMMON *cm, MACROBLOCKD *xd, const MB_MODE_INFO *const mbmi = xd->mi[0]; struct macroblockd_plane *const pd = &xd->plane[plane]; const int dst_stride = pd->dst.stride; - uint8_t *dst = - &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]]; + uint8_t *dst = &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2]; const PREDICTION_MODE mode = (plane == AOM_PLANE_Y) ? mbmi->mode : get_uv_mode(mbmi->uv_mode); const int use_palette = mbmi->palette_mode_info.palette_size[plane != 0] > 0; diff --git a/media/libaom/src/av1/common/reconintra.h b/media/libaom/src/av1/common/reconintra.h index 892c962f8e..9d203569c0 100644 --- a/media/libaom/src/av1/common/reconintra.h +++ b/media/libaom/src/av1/common/reconintra.h @@ -15,8 +15,8 @@ #include #include "aom/aom_integer.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" #ifdef __cplusplus extern "C" { @@ -54,8 +54,8 @@ static INLINE int av1_use_angle_delta(BLOCK_SIZE bsize) { } static INLINE int av1_allow_intrabc(const AV1_COMMON *const cm) { - return frame_is_intra_only(cm) && cm->allow_screen_content_tools && - cm->allow_intrabc; + return frame_is_intra_only(cm) && cm->features.allow_screen_content_tools && + cm->features.allow_intrabc; } static INLINE int av1_filter_intra_allowed_bsize(const AV1_COMMON *const cm, diff --git a/media/libaom/src/av1/common/resize.c b/media/libaom/src/av1/common/resize.c index 2f2efd8f5a..98f28f7b56 100644 --- a/media/libaom/src/av1/common/resize.c +++ b/media/libaom/src/av1/common/resize.c @@ -1235,7 +1235,7 @@ void av1_upscale_normative_rows(const AV1_COMMON *cm, const uint8_t *src, int32_t x0_qn = get_upscale_convolve_x0(downscaled_plane_width, upscaled_plane_width, x_step_qn); - for (int j = 0; j < cm->tile_cols; j++) { + for (int j = 0; j < cm->tiles.cols; j++) { av1_tile_set_col(&tile_col, cm, j); // Determine the limits of this tile column in both the source // and destination images. @@ -1248,7 +1248,7 @@ void av1_upscale_normative_rows(const AV1_COMMON *cm, const uint8_t *src, const int upscaled_x0 = (downscaled_x0 * superres_denom) / SCALE_NUMERATOR; int upscaled_x1; - if (j == cm->tile_cols - 1) { + if (j == cm->tiles.cols - 1) { // Note that we can't just use AOMMIN here - due to rounding, // (downscaled_x1 * superres_denom) / SCALE_NUMERATOR may be less than // upscaled_plane_width. @@ -1262,7 +1262,7 @@ void av1_upscale_normative_rows(const AV1_COMMON *cm, const uint8_t *src, const int dst_width = upscaled_x1 - upscaled_x0; const int pad_left = (j == 0); - const int pad_right = (j == cm->tile_cols - 1); + const int pad_right = (j == cm->tiles.cols - 1); #if CONFIG_AV1_HIGHBITDEPTH if (cm->seq_params.use_highbitdepth) @@ -1371,6 +1371,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool) { const int num_planes = av1_num_planes(cm); if (!av1_superres_scaled(cm)) return; const SequenceHeader *const seq_params = &cm->seq_params; + const int byte_alignment = cm->features.byte_alignment; YV12_BUFFER_CONFIG copy_buffer; memset(©_buffer, 0, sizeof(copy_buffer)); @@ -1381,7 +1382,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool) { if (aom_alloc_frame_buffer( ©_buffer, aligned_width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, cm->byte_alignment)) + AOM_BORDER_IN_PIXELS, byte_alignment)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate copy buffer for superres upscaling"); @@ -1413,7 +1414,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool) { frame_to_show, cm->superres_upscaled_width, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, cm->byte_alignment, fb, cb, cb_priv)) { + AOM_BORDER_IN_PIXELS, byte_alignment, fb, cb, cb_priv)) { unlock_buffer_pool(pool); aom_internal_error( &cm->error, AOM_CODEC_MEM_ERROR, @@ -1430,7 +1431,7 @@ void av1_superres_upscale(AV1_COMMON *cm, BufferPool *const pool) { frame_to_show, cm->superres_upscaled_width, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, cm->byte_alignment)) + AOM_BORDER_IN_PIXELS, byte_alignment)) aom_internal_error( &cm->error, AOM_CODEC_MEM_ERROR, "Failed to reallocate current frame buffer for superres upscaling"); diff --git a/media/libaom/src/av1/common/resize.h b/media/libaom/src/av1/common/resize.h index 43bea58b82..8ee859e5c0 100644 --- a/media/libaom/src/av1/common/resize.h +++ b/media/libaom/src/av1/common/resize.h @@ -14,7 +14,7 @@ #include #include "aom/aom_integer.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #ifdef __cplusplus extern "C" { diff --git a/media/libaom/src/av1/common/restoration.c b/media/libaom/src/av1/common/restoration.c index 70ad1184c6..a0f37ad637 100644 --- a/media/libaom/src/av1/common/restoration.c +++ b/media/libaom/src/av1/common/restoration.c @@ -17,7 +17,7 @@ #include "config/aom_scale_rtcd.h" #include "aom_mem/aom_mem.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/resize.h" #include "av1/common/restoration.h" #include "aom_dsp/aom_dsp_common.h" @@ -1117,7 +1117,7 @@ void av1_loop_restoration_filter_frame_init(AV1LrStruct *lr_ctxt, if (aom_realloc_frame_buffer( lr_ctxt->dst, frame_width, frame_height, seq_params->subsampling_x, seq_params->subsampling_y, highbd, AOM_RESTORATION_FRAME_BORDER, - cm->byte_alignment, NULL, NULL, NULL) < 0) + cm->features.byte_alignment, NULL, NULL, NULL) < 0) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate restoration dst buffer"); @@ -1190,7 +1190,7 @@ static void foreach_rest_unit_in_planes(AV1LrStruct *lr_ctxt, AV1_COMMON *cm, void av1_loop_restoration_filter_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int optimized_lr, void *lr_ctxt) { - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int num_planes = av1_num_planes(cm); AV1LrStruct *loop_rest_ctxt = (AV1LrStruct *)lr_ctxt; @@ -1318,7 +1318,7 @@ int av1_loop_restoration_corners_in_sb(const struct AV1Common *cm, int plane, if (bsize != cm->seq_params.sb_size) return 0; if (cm->rst_info[plane].frame_restoration_type == RESTORE_NONE) return 0; - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int is_uv = plane > 0; diff --git a/media/libaom/src/av1/common/scale.c b/media/libaom/src/av1/common/scale.c index 50d75cb72b..3b14c0a2c6 100644 --- a/media/libaom/src/av1/common/scale.c +++ b/media/libaom/src/av1/common/scale.c @@ -37,7 +37,7 @@ static INLINE int scaled_y(int val, const struct scale_factors *sf) { // Note: Expect val to be in q4 precision static int unscaled_value(int val, const struct scale_factors *sf) { (void)sf; - return val << SCALE_EXTRA_BITS; + return val * (1 << SCALE_EXTRA_BITS); } static int get_fixed_point_scale_factor(int other_size, int this_size) { diff --git a/media/libaom/src/av1/common/scan.h b/media/libaom/src/av1/common/scan.h index f9c339215b..d9620e1c53 100644 --- a/media/libaom/src/av1/common/scan.h +++ b/media/libaom/src/av1/common/scan.h @@ -15,9 +15,9 @@ #include "aom/aom_integer.h" #include "aom_ports/mem.h" -#include "av1/common/enums.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" +#include "av1/common/enums.h" #ifdef __cplusplus extern "C" { diff --git a/media/libaom/src/av1/common/thread_common.c b/media/libaom/src/av1/common/thread_common.c index 82ae952f11..f3c8795f8d 100644 --- a/media/libaom/src/av1/common/thread_common.c +++ b/media/libaom/src/av1/common/thread_common.c @@ -268,7 +268,8 @@ static INLINE void thread_loop_filter_rows( struct macroblockd_plane *planes, MACROBLOCKD *xd, AV1LfSync *const lf_sync) { const int sb_cols = - ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2) >> MAX_MIB_SIZE_LOG2; + ALIGN_POWER_OF_TWO(cm->mi_params.mi_cols, MAX_MIB_SIZE_LOG2) >> + MAX_MIB_SIZE_LOG2; int mi_row, mi_col, plane, dir; int r, c; @@ -282,7 +283,8 @@ static INLINE void thread_loop_filter_rows( r = mi_row >> MAX_MIB_SIZE_LOG2; if (dir == 0) { - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MAX_MIB_SIZE) { + for (mi_col = 0; mi_col < cm->mi_params.mi_cols; + mi_col += MAX_MIB_SIZE) { c = mi_col >> MAX_MIB_SIZE_LOG2; av1_setup_dst_planes(planes, cm->seq_params.sb_size, frame_buffer, @@ -293,7 +295,8 @@ static INLINE void thread_loop_filter_rows( sync_write(lf_sync, r, c, sb_cols, plane); } } else if (dir == 1) { - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MAX_MIB_SIZE) { + for (mi_col = 0; mi_col < cm->mi_params.mi_cols; + mi_col += MAX_MIB_SIZE) { c = mi_col >> MAX_MIB_SIZE_LOG2; // Wait for vertical edge filtering of the top-right block to be @@ -331,7 +334,8 @@ static INLINE void thread_loop_filter_bitmask_rows( struct macroblockd_plane *planes, MACROBLOCKD *xd, AV1LfSync *const lf_sync) { const int sb_cols = - ALIGN_POWER_OF_TWO(cm->mi_cols, MIN_MIB_SIZE_LOG2) >> MIN_MIB_SIZE_LOG2; + ALIGN_POWER_OF_TWO(cm->mi_params.mi_cols, MIN_MIB_SIZE_LOG2) >> + MIN_MIB_SIZE_LOG2; int mi_row, mi_col, plane, dir; int r, c; (void)xd; @@ -346,7 +350,8 @@ static INLINE void thread_loop_filter_bitmask_rows( r = mi_row >> MIN_MIB_SIZE_LOG2; if (dir == 0) { - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_SIZE_64X64) { + for (mi_col = 0; mi_col < cm->mi_params.mi_cols; + mi_col += MI_SIZE_64X64) { c = mi_col >> MIN_MIB_SIZE_LOG2; av1_setup_dst_planes(planes, BLOCK_64X64, frame_buffer, mi_row, @@ -357,7 +362,8 @@ static INLINE void thread_loop_filter_bitmask_rows( sync_write(lf_sync, r, c, sb_cols, plane); } } else if (dir == 1) { - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_SIZE_64X64) { + for (mi_col = 0; mi_col < cm->mi_params.mi_cols; + mi_col += MI_SIZE_64X64) { c = mi_col >> MIN_MIB_SIZE_LOG2; // Wait for vertical edge filtering of the top-right block to be @@ -402,16 +408,17 @@ static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, #if CONFIG_LPF_MASK int sb_rows; if (is_decoding) { - sb_rows = - ALIGN_POWER_OF_TWO(cm->mi_rows, MIN_MIB_SIZE_LOG2) >> MIN_MIB_SIZE_LOG2; + sb_rows = ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, MIN_MIB_SIZE_LOG2) >> + MIN_MIB_SIZE_LOG2; } else { - sb_rows = - ALIGN_POWER_OF_TWO(cm->mi_rows, MAX_MIB_SIZE_LOG2) >> MAX_MIB_SIZE_LOG2; + sb_rows = ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, MAX_MIB_SIZE_LOG2) >> + MAX_MIB_SIZE_LOG2; } #else // Number of superblock rows and cols const int sb_rows = - ALIGN_POWER_OF_TWO(cm->mi_rows, MAX_MIB_SIZE_LOG2) >> MAX_MIB_SIZE_LOG2; + ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, MAX_MIB_SIZE_LOG2) >> + MAX_MIB_SIZE_LOG2; #endif const int num_workers = nworkers; int i; @@ -479,11 +486,11 @@ void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int start_mi_row, end_mi_row, mi_rows_to_filter; start_mi_row = 0; - mi_rows_to_filter = cm->mi_rows; - if (partial_frame && cm->mi_rows > 8) { - start_mi_row = cm->mi_rows >> 1; + mi_rows_to_filter = cm->mi_params.mi_rows; + if (partial_frame && cm->mi_params.mi_rows > 8) { + start_mi_row = cm->mi_params.mi_rows >> 1; start_mi_row &= 0xfffffff8; - mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8); + mi_rows_to_filter = AOMMAX(cm->mi_params.mi_rows / 8, 8); } end_mi_row = start_mi_row + mi_rows_to_filter; av1_loop_filter_frame_init(cm, plane_start, plane_end); @@ -909,7 +916,7 @@ void av1_loop_restoration_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, int optimized_lr, AVxWorker *workers, int num_workers, AV1LrSync *lr_sync, void *lr_ctxt) { - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int num_planes = av1_num_planes(cm); diff --git a/media/libaom/src/av1/common/tile_common.c b/media/libaom/src/av1/common/tile_common.c index 59c8c9b725..1b11bd7606 100644 --- a/media/libaom/src/av1/common/tile_common.c +++ b/media/libaom/src/av1/common/tile_common.c @@ -9,9 +9,9 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ -#include "av1/common/tile_common.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/resize.h" +#include "av1/common/tile_common.h" #include "aom_dsp/aom_dsp_common.h" void av1_tile_init(TileInfo *tile, const AV1_COMMON *cm, int row, int col) { @@ -28,117 +28,126 @@ static int tile_log2(int blk_size, int target) { } void av1_get_tile_limits(AV1_COMMON *const cm) { - int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2); - int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); - int sb_cols = mi_cols >> cm->seq_params.mib_size_log2; - int sb_rows = mi_rows >> cm->seq_params.mib_size_log2; + const SequenceHeader *const seq_params = &cm->seq_params; + CommonTileParams *const tiles = &cm->tiles; + const int mi_cols = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_cols, seq_params->mib_size_log2); + const int mi_rows = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, seq_params->mib_size_log2); + const int sb_cols = mi_cols >> seq_params->mib_size_log2; + const int sb_rows = mi_rows >> seq_params->mib_size_log2; - int sb_size_log2 = cm->seq_params.mib_size_log2 + MI_SIZE_LOG2; - cm->max_tile_width_sb = MAX_TILE_WIDTH >> sb_size_log2; - int max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size_log2); + const int sb_size_log2 = seq_params->mib_size_log2 + MI_SIZE_LOG2; + tiles->max_width_sb = MAX_TILE_WIDTH >> sb_size_log2; + const int max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size_log2); - cm->min_log2_tile_cols = tile_log2(cm->max_tile_width_sb, sb_cols); - cm->max_log2_tile_cols = tile_log2(1, AOMMIN(sb_cols, MAX_TILE_COLS)); - cm->max_log2_tile_rows = tile_log2(1, AOMMIN(sb_rows, MAX_TILE_ROWS)); - cm->min_log2_tiles = tile_log2(max_tile_area_sb, sb_cols * sb_rows); - cm->min_log2_tiles = AOMMAX(cm->min_log2_tiles, cm->min_log2_tile_cols); + tiles->min_log2_cols = tile_log2(tiles->max_width_sb, sb_cols); + tiles->max_log2_cols = tile_log2(1, AOMMIN(sb_cols, MAX_TILE_COLS)); + tiles->max_log2_rows = tile_log2(1, AOMMIN(sb_rows, MAX_TILE_ROWS)); + tiles->min_log2 = tile_log2(max_tile_area_sb, sb_cols * sb_rows); + tiles->min_log2 = AOMMAX(tiles->min_log2, tiles->min_log2_cols); } -void av1_calculate_tile_cols(AV1_COMMON *const cm) { - int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2); - int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); - int sb_cols = mi_cols >> cm->seq_params.mib_size_log2; - int sb_rows = mi_rows >> cm->seq_params.mib_size_log2; +void av1_calculate_tile_cols(const SequenceHeader *const seq_params, + int cm_mi_rows, int cm_mi_cols, + CommonTileParams *const tiles) { + int mi_cols = ALIGN_POWER_OF_TWO(cm_mi_cols, seq_params->mib_size_log2); + int mi_rows = ALIGN_POWER_OF_TWO(cm_mi_rows, seq_params->mib_size_log2); + int sb_cols = mi_cols >> seq_params->mib_size_log2; + int sb_rows = mi_rows >> 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; + tiles->min_inner_width = -1; - if (cm->uniform_tile_spacing_flag) { + if (tiles->uniform_spacing) { int start_sb; - int size_sb = ALIGN_POWER_OF_TWO(sb_cols, cm->log2_tile_cols); - size_sb >>= cm->log2_tile_cols; + int size_sb = ALIGN_POWER_OF_TWO(sb_cols, tiles->log2_cols); + size_sb >>= tiles->log2_cols; assert(size_sb > 0); for (i = 0, start_sb = 0; start_sb < sb_cols; i++) { - cm->tile_col_start_sb[i] = start_sb; + tiles->col_start_sb[i] = start_sb; start_sb += size_sb; } - cm->tile_cols = i; - cm->tile_col_start_sb[i] = sb_cols; - cm->min_log2_tile_rows = AOMMAX(cm->min_log2_tiles - cm->log2_tile_cols, 0); - cm->max_tile_height_sb = sb_rows >> cm->min_log2_tile_rows; + tiles->cols = i; + tiles->col_start_sb[i] = sb_cols; + tiles->min_log2_rows = AOMMAX(tiles->min_log2 - tiles->log2_cols, 0); + tiles->max_height_sb = sb_rows >> tiles->min_log2_rows; - 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; + tiles->width = size_sb << seq_params->mib_size_log2; + tiles->width = AOMMIN(tiles->width, cm_mi_cols); + if (tiles->cols > 1) { + tiles->min_inner_width = tiles->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]; + tiles->log2_cols = tile_log2(1, tiles->cols); + for (i = 0; i < tiles->cols; i++) { + int size_sb = tiles->col_start_sb[i + 1] - tiles->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) + if (i < tiles->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); + if (tiles->min_log2) { + max_tile_area_sb >>= (tiles->min_log2 + 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; + tiles->max_height_sb = AOMMAX(max_tile_area_sb / widest_tile_sb, 1); + if (tiles->cols > 1) { + tiles->min_inner_width = narrowest_inner_tile_sb + << seq_params->mib_size_log2; } } } -void av1_calculate_tile_rows(AV1_COMMON *const cm) { - int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); - int sb_rows = mi_rows >> cm->seq_params.mib_size_log2; +void av1_calculate_tile_rows(const SequenceHeader *const seq_params, + int cm_mi_rows, CommonTileParams *const tiles) { + int mi_rows = ALIGN_POWER_OF_TWO(cm_mi_rows, seq_params->mib_size_log2); + int sb_rows = mi_rows >> seq_params->mib_size_log2; int start_sb, size_sb, i; - if (cm->uniform_tile_spacing_flag) { - size_sb = ALIGN_POWER_OF_TWO(sb_rows, cm->log2_tile_rows); - size_sb >>= cm->log2_tile_rows; + if (tiles->uniform_spacing) { + size_sb = ALIGN_POWER_OF_TWO(sb_rows, tiles->log2_rows); + size_sb >>= tiles->log2_rows; assert(size_sb > 0); for (i = 0, start_sb = 0; start_sb < sb_rows; i++) { - cm->tile_row_start_sb[i] = start_sb; + tiles->row_start_sb[i] = start_sb; start_sb += size_sb; } - cm->tile_rows = i; - cm->tile_row_start_sb[i] = sb_rows; + tiles->rows = i; + tiles->row_start_sb[i] = sb_rows; - cm->tile_height = size_sb << cm->seq_params.mib_size_log2; - cm->tile_height = AOMMIN(cm->tile_height, cm->mi_rows); + tiles->height = size_sb << seq_params->mib_size_log2; + tiles->height = AOMMIN(tiles->height, cm_mi_rows); } else { - cm->log2_tile_rows = tile_log2(1, cm->tile_rows); + tiles->log2_rows = tile_log2(1, tiles->rows); } } void av1_tile_set_row(TileInfo *tile, const AV1_COMMON *cm, int row) { - assert(row < cm->tile_rows); - int mi_row_start = cm->tile_row_start_sb[row] << cm->seq_params.mib_size_log2; - int mi_row_end = cm->tile_row_start_sb[row + 1] + assert(row < cm->tiles.rows); + int mi_row_start = cm->tiles.row_start_sb[row] + << cm->seq_params.mib_size_log2; + int mi_row_end = cm->tiles.row_start_sb[row + 1] << cm->seq_params.mib_size_log2; tile->tile_row = row; tile->mi_row_start = mi_row_start; - tile->mi_row_end = AOMMIN(mi_row_end, cm->mi_rows); + tile->mi_row_end = AOMMIN(mi_row_end, cm->mi_params.mi_rows); assert(tile->mi_row_end > tile->mi_row_start); } void av1_tile_set_col(TileInfo *tile, const AV1_COMMON *cm, int col) { - assert(col < cm->tile_cols); - int mi_col_start = cm->tile_col_start_sb[col] << cm->seq_params.mib_size_log2; - int mi_col_end = cm->tile_col_start_sb[col + 1] + assert(col < cm->tiles.cols); + int mi_col_start = cm->tiles.col_start_sb[col] + << cm->seq_params.mib_size_log2; + int mi_col_end = cm->tiles.col_start_sb[col + 1] << cm->seq_params.mib_size_log2; tile->tile_col = col; tile->mi_col_start = mi_col_start; - tile->mi_col_end = AOMMIN(mi_col_end, cm->mi_cols); + tile->mi_col_end = AOMMIN(mi_col_end, cm->mi_params.mi_cols); assert(tile->mi_col_end > tile->mi_col_start); } @@ -198,21 +207,22 @@ AV1PixelRect av1_get_tile_rect(const TileInfo *tile_info, const AV1_COMMON *cm, } void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { - if (cm->uniform_tile_spacing_flag) { - *w = cm->tile_width; - *h = cm->tile_height; + const CommonTileParams *const tiles = &cm->tiles; + if (tiles->uniform_spacing) { + *w = tiles->width; + *h = tiles->height; } else { - for (int i = 0; i < cm->tile_cols; ++i) { + for (int i = 0; i < tiles->cols; ++i) { const int tile_width_sb = - cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i]; + tiles->col_start_sb[i + 1] - tiles->col_start_sb[i]; const int tile_w = tile_width_sb * cm->seq_params.mib_size; assert(i == 0 || tile_w == *w); // ensure all tiles have same dimension *w = tile_w; } - for (int i = 0; i < cm->tile_rows; ++i) { + for (int i = 0; i < tiles->rows; ++i) { const int tile_height_sb = - cm->tile_row_start_sb[i + 1] - cm->tile_row_start_sb[i]; + tiles->row_start_sb[i + 1] - tiles->row_start_sb[i]; const int tile_h = tile_height_sb * cm->seq_params.mib_size; assert(i == 0 || tile_h == *h); // ensure all tiles have same dimension *h = tile_h; @@ -222,8 +232,8 @@ void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) { int av1_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; + if (cm->tiles.cols == 1) return 1; - return ((cm->min_inner_tile_width << MI_SIZE_LOG2) >= + return ((cm->tiles.min_inner_width << MI_SIZE_LOG2) >= (64 << av1_superres_scaled(cm))); } diff --git a/media/libaom/src/av1/common/tile_common.h b/media/libaom/src/av1/common/tile_common.h index 0f3d1aa545..ca7c5f496e 100644 --- a/media/libaom/src/av1/common/tile_common.h +++ b/media/libaom/src/av1/common/tile_common.h @@ -19,6 +19,8 @@ extern "C" { #include "config/aom_config.h" struct AV1Common; +struct SequenceHeader; +struct CommonTileParams; #define DEFAULT_MAX_NUM_TG 1 @@ -56,8 +58,12 @@ AV1PixelRect av1_get_tile_rect(const TileInfo *tile_info, void av1_get_uniform_tile_size(const struct AV1Common *cm, int *w, int *h); 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); +void av1_calculate_tile_cols(const struct SequenceHeader *const seq_params, + int cm_mi_rows, int cm_mi_cols, + struct CommonTileParams *const tiles); +void av1_calculate_tile_rows(const struct SequenceHeader *const seq_params, + int cm_mi_rows, + struct CommonTileParams *const tiles); // Checks if the minimum tile_width requirement is satisfied int av1_is_min_tile_width_satisfied(const struct AV1Common *cm); diff --git a/media/libaom/src/av1/common/timing.c b/media/libaom/src/av1/common/timing.c index 3adb5089f5..a959cdf768 100644 --- a/media/libaom/src/av1/common/timing.c +++ b/media/libaom/src/av1/common/timing.c @@ -15,22 +15,35 @@ * The tables are in Kbps instead of Mbps in the specification. * Note that depending on the profile, a multiplier is needed. */ +#define UNDEFINED_RATE \ + (1 << 21) // Placeholder rate for levels with undefined rate +#define INVALID_RATE \ + (0) // For invalid profile-level configuration, set rate to 0 /* Max Bitrates for levels of Main Tier in kbps. Bitrate in main_kbps [31] */ /* is a dummy value. The decoder model is not applicable for level 31. */ static int32_t main_kbps[1 << LEVEL_BITS] = { - 1500, 3000, 0, 0, 6000, 10000, 0, 0, 12000, 20000, 0, - 0, 30000, 40000, 60000, 60000, 60000, 100000, 160000, 160000, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, (1 << 26) + 1500, 3000, UNDEFINED_RATE, UNDEFINED_RATE, + 6000, 10000, UNDEFINED_RATE, UNDEFINED_RATE, + 12000, 20000, UNDEFINED_RATE, UNDEFINED_RATE, + 30000, 40000, 60000, 60000, + 60000, 100000, 160000, 160000, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE }; /* Max Bitrates for levels of High Tier in kbps. Bitrate in high_kbps [31] */ /* is a dummy value. The decoder model is not applicable for level 31. */ static int32_t high_kbps[1 << LEVEL_BITS] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 30000, 50000, 0, 0, 100000, 160000, 240000, 240000, - 240000, 480000, 800000, 800000, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, (1 << 26) + INVALID_RATE, INVALID_RATE, INVALID_RATE, INVALID_RATE, + INVALID_RATE, INVALID_RATE, INVALID_RATE, INVALID_RATE, + 30000, 50000, UNDEFINED_RATE, UNDEFINED_RATE, + 100000, 160000, 240000, 240000, + 240000, 480000, 800000, 800000, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, + UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE, UNDEFINED_RATE }; /* BitrateProfileFactor */ diff --git a/media/libaom/src/av1/common/timing.h b/media/libaom/src/av1/common/timing.h index 9aca58fbe8..9192124f72 100644 --- a/media/libaom/src/av1/common/timing.h +++ b/media/libaom/src/av1/common/timing.h @@ -42,10 +42,6 @@ typedef struct aom_dec_model_op_parameters { int initial_display_delay; } aom_dec_model_op_parameters_t; -typedef struct aom_op_timing_info_t { - uint32_t buffer_removal_time; -} aom_op_timing_info_t; - void av1_set_aom_dec_model_info(aom_dec_model_info_t *decoder_model); void av1_set_dec_model_op_parameters(aom_dec_model_op_parameters_t *op_params); diff --git a/media/libaom/src/av1/common/txb_common.c b/media/libaom/src/av1/common/txb_common.c index ec25ad65fe..4eef319cd8 100644 --- a/media/libaom/src/av1/common/txb_common.c +++ b/media/libaom/src/av1/common/txb_common.c @@ -9,7 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ #include "aom/aom_integer.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/txb_common.h" const int8_t av1_coeff_band_4x4[16] = { 0, 1, 2, 3, 4, 5, 6, 7, diff --git a/media/libaom/src/av1/common/txb_common.h b/media/libaom/src/av1/common/txb_common.h index 54a277816c..5a62fa89b1 100644 --- a/media/libaom/src/av1/common/txb_common.h +++ b/media/libaom/src/av1/common/txb_common.h @@ -12,7 +12,7 @@ #ifndef AOM_AV1_COMMON_TXB_COMMON_H_ #define AOM_AV1_COMMON_TXB_COMMON_H_ -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" extern const int16_t av1_eob_group_start[12]; extern const int16_t av1_eob_offset_bits[12]; diff --git a/media/libaom/src/av1/common/warped_motion.c b/media/libaom/src/av1/common/warped_motion.c index 8997d81180..4e9fab9bd8 100644 --- a/media/libaom/src/av1/common/warped_motion.c +++ b/media/libaom/src/av1/common/warped_motion.c @@ -1057,9 +1057,9 @@ static int find_affine_int(int np, const int *pts1, const int *pts2, return 0; } -int av1_find_projection(int np, int *pts1, int *pts2, BLOCK_SIZE bsize, int mvy, - int mvx, WarpedMotionParams *wm_params, int mi_row, - int mi_col) { +int av1_find_projection(int np, const int *pts1, const int *pts2, + BLOCK_SIZE bsize, int mvy, int mvx, + WarpedMotionParams *wm_params, int mi_row, int mi_col) { assert(wm_params->wmtype == AFFINE); if (find_affine_int(np, pts1, pts2, bsize, mvy, mvx, wm_params, mi_row, diff --git a/media/libaom/src/av1/common/warped_motion.h b/media/libaom/src/av1/common/warped_motion.h index 4b43f61aa8..14dc0fe47c 100644 --- a/media/libaom/src/av1/common/warped_motion.h +++ b/media/libaom/src/av1/common/warped_motion.h @@ -178,9 +178,9 @@ void av1_warp_plane(WarpedMotionParams *wm, int use_hbd, int bd, int p_height, int p_stride, int subsampling_x, int subsampling_y, ConvolveParams *conv_params); -int av1_find_projection(int np, int *pts1, int *pts2, BLOCK_SIZE bsize, int mvy, - int mvx, WarpedMotionParams *wm_params, int mi_row, - int mi_col); +int av1_find_projection(int np, const int *pts1, const int *pts2, + BLOCK_SIZE bsize, int mvy, int mvx, + WarpedMotionParams *wm_params, int mi_row, int mi_col); int av1_get_shear_params(WarpedMotionParams *wm); #endif // AOM_AV1_COMMON_WARPED_MOTION_H_ diff --git a/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c b/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c index cae75045f0..0fbd5eae4b 100644 --- a/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c +++ b/media/libaom/src/av1/common/x86/av1_inv_txfm_avx2.c @@ -61,8 +61,7 @@ static INLINE void idct16_stage7_avx2(__m256i *output, __m256i *x1) { btf_16_adds_subs_out_avx2(&output[7], &output[8], x1[7], x1[8]); } -static void idct16_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct16_avx2(const __m256i *input, __m256i *output, int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -133,8 +132,8 @@ static void idct16_new_avx2(const __m256i *input, __m256i *output, idct16_stage7_avx2(output, x1); } -static void idct16_low8_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct16_low8_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -181,8 +180,8 @@ static void idct16_low8_new_avx2(const __m256i *input, __m256i *output, idct16_stage7_avx2(output, x1); } -static void idct16_low1_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct16_low1_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -303,8 +302,8 @@ static INLINE void iadst16_stage9_avx2(__m256i *output, __m256i *x1) { output[15] = _mm256_subs_epi16(__zero, x1[1]); } -static void iadst16_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void iadst16_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -365,8 +364,8 @@ static void iadst16_new_avx2(const __m256i *input, __m256i *output, iadst16_stage9_avx2(output, x1); } -static void iadst16_low8_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void iadst16_low8_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -401,8 +400,8 @@ static void iadst16_low8_new_avx2(const __m256i *input, __m256i *output, iadst16_stage9_avx2(output, x1); } -static void iadst16_low1_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void iadst16_low1_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -568,8 +567,8 @@ static INLINE void idct32_stage9_avx2(__m256i *output, __m256i *x) { btf_16_adds_subs_out_avx2(&output[15], &output[16], x[15], x[16]); } -static void idct32_low1_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct32_low1_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -621,8 +620,8 @@ static void idct32_low1_new_avx2(const __m256i *input, __m256i *output, output[16] = x[0]; } -static void idct32_low8_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct32_low8_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -679,8 +678,8 @@ static void idct32_low8_new_avx2(const __m256i *input, __m256i *output, idct32_stage9_avx2(output, x); } -static void idct32_low16_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct32_low16_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -746,8 +745,7 @@ static void idct32_low16_new_avx2(const __m256i *input, __m256i *output, idct32_stage9_avx2(output, x); } -static void idct32_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct32_avx2(const __m256i *input, __m256i *output, int8_t cos_bit) { (void)(cos_bit); const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1104,8 +1102,8 @@ static INLINE void idct64_stage11_avx2(__m256i *output, __m256i *x) { btf_16_adds_subs_out_avx2(&output[31], &output[32], x[31], x[32]); } -static void idct64_low1_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct64_low1_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -1191,8 +1189,8 @@ static void idct64_low1_new_avx2(const __m256i *input, __m256i *output, output[32] = x[0]; } -static void idct64_low8_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct64_low8_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1302,7 +1300,6 @@ static void idct64_low8_new_avx2(const __m256i *input, __m256i *output, x[6] = x[1]; x[5] = x[2]; x[4] = x[3]; - x[9] = x[9]; btf_16_w16_avx2(cospi_m32_p32, cospi_p32_p32, &x[10], &x[13], _r, cos_bit); btf_16_w16_avx2(cospi_m32_p32, cospi_p32_p32, &x[11], &x[12], _r, cos_bit); idct64_stage8_high48_avx2(x, cospi, _r, cos_bit); @@ -1312,8 +1309,8 @@ static void idct64_low8_new_avx2(const __m256i *input, __m256i *output, idct64_stage11_avx2(output, x); } -static void idct64_low16_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct64_low16_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1428,8 +1425,8 @@ static void idct64_low16_new_avx2(const __m256i *input, __m256i *output, idct64_stage11_avx2(output, x); } -static void idct64_low32_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static void idct64_low32_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m256i _r = _mm256_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1592,17 +1589,15 @@ static const transform_1d_avx2 { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } }, { - { idct16_low1_new_avx2, idct16_low8_new_avx2, idct16_new_avx2, NULL }, - { iadst16_low1_new_avx2, iadst16_low8_new_avx2, iadst16_new_avx2, - NULL }, + { idct16_low1_avx2, idct16_low8_avx2, idct16_avx2, NULL }, + { iadst16_low1_avx2, iadst16_low8_avx2, iadst16_avx2, NULL }, { NULL, NULL, NULL, NULL }, }, - { { idct32_low1_new_avx2, idct32_low8_new_avx2, idct32_low16_new_avx2, - idct32_new_avx2 }, + { { idct32_low1_avx2, idct32_low8_avx2, idct32_low16_avx2, idct32_avx2 }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } }, - { { idct64_low1_new_avx2, idct64_low8_new_avx2, idct64_low16_new_avx2, - idct64_low32_new_avx2 }, + { { idct64_low1_avx2, idct64_low8_avx2, idct64_low16_avx2, + idct64_low32_avx2 }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } } }; diff --git a/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c b/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c index c8c003c416..46c051ff8c 100644 --- a/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c +++ b/media/libaom/src/av1/common/x86/av1_inv_txfm_ssse3.c @@ -24,8 +24,7 @@ static int32_t NewSqrt2list[TX_SIZES] = { 5793, 2 * 4096, 2 * 5793, 4 * 4096, // TODO(binpengsmail@gmail.com): replace some for loop with do {} while -static void idct4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct4_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -51,8 +50,8 @@ static void idct4_new_sse2(const __m128i *input, __m128i *output, btf_16_adds_subs_out_sse2(output[1], output[2], x[1], x[2]); } -static void idct4_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct4_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -78,8 +77,8 @@ static void idct4_w4_new_sse2(const __m128i *input, __m128i *output, btf_16_adds_subs_out_sse2(output[1], output[2], x[1], x[2]); } -static void idct8_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct8_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -103,8 +102,7 @@ static void idct8_low1_new_ssse3(const __m128i *input, __m128i *output, output[4] = x[0]; } -static void idct8_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct8_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -152,8 +150,8 @@ static void idct8_new_sse2(const __m128i *input, __m128i *output, btf_16_adds_subs_out_sse2(output[3], output[4], x[3], x[4]); } -static void idct8_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct8_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -239,8 +237,8 @@ static INLINE void idct16_stage7_sse2(__m128i *output, __m128i *x) { btf_16_adds_subs_out_sse2(output[7], output[8], x[7], x[8]); } -static void idct16_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct16_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -274,8 +272,8 @@ static void idct16_low1_new_ssse3(const __m128i *input, __m128i *output, output[8] = x[0]; } -static void idct16_low8_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct16_low8_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -321,8 +319,7 @@ static void idct16_low8_new_ssse3(const __m128i *input, __m128i *output, idct16_stage7_sse2(output, x); } -static void idct16_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct16_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -394,8 +391,8 @@ static void idct16_new_sse2(const __m128i *input, __m128i *output, idct16_stage7_sse2(output, x); } -static void idct16_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct16_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -605,8 +602,8 @@ static INLINE void idct32_stage9_sse2(__m128i *output, __m128i *x) { btf_16_adds_subs_out_sse2(output[15], output[16], x[15], x[16]); } -static void idct32_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct32_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -658,8 +655,8 @@ static void idct32_low1_new_ssse3(const __m128i *input, __m128i *output, output[16] = x[0]; } -static void idct32_low8_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct32_low8_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -716,8 +713,8 @@ static void idct32_low8_new_ssse3(const __m128i *input, __m128i *output, idct32_stage9_sse2(output, x); } -static void idct32_low16_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct32_low16_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -783,8 +780,7 @@ static void idct32_low16_new_ssse3(const __m128i *input, __m128i *output, idct32_stage9_sse2(output, x); } -static void idct32_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct32_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1143,8 +1139,8 @@ static INLINE void idct64_stage11_sse2(__m128i *output, __m128i *x) { btf_16_adds_subs_out_sse2(output[31], output[32], x[31], x[32]); } -static void idct64_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct64_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); @@ -1230,8 +1226,8 @@ static void idct64_low1_new_ssse3(const __m128i *input, __m128i *output, output[32] = x[0]; } -static void idct64_low8_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct64_low8_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1341,7 +1337,6 @@ static void idct64_low8_new_ssse3(const __m128i *input, __m128i *output, x[6] = x[1]; x[5] = x[2]; x[4] = x[3]; - x[9] = x[9]; btf_16_sse2(cospi_m32_p32, cospi_p32_p32, x[10], x[13], x[10], x[13]); btf_16_sse2(cospi_m32_p32, cospi_p32_p32, x[11], x[12], x[11], x[12]); idct64_stage8_high48_sse2(x, cospi, __rounding, cos_bit); @@ -1351,8 +1346,8 @@ static void idct64_low8_new_ssse3(const __m128i *input, __m128i *output, idct64_stage11_sse2(output, x); } -static void idct64_low16_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct64_low16_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1467,8 +1462,8 @@ static void idct64_low16_new_ssse3(const __m128i *input, __m128i *output, idct64_stage11_sse2(output, x); } -static void idct64_low32_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void idct64_low32_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -1616,8 +1611,7 @@ static void idct64_low32_new_ssse3(const __m128i *input, __m128i *output, idct64_stage11_sse2(output, x); } -static void iadst4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst4_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *sinpi = sinpi_arr(INV_COS_BIT); const __m128i sinpi_p01_p04 = pair_set_epi16(sinpi[1], sinpi[4]); @@ -1678,11 +1672,8 @@ static void iadst4_new_sse2(const __m128i *input, __m128i *output, } } -// TODO(binpengsmail@gmail.com): -// To explore the reuse of VP9 versions of corresponding SSE2 functions and -// evaluate whether there is a possibility for further speedup. -static void iadst4_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst4_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *sinpi = sinpi_arr(INV_COS_BIT); const __m128i sinpi_p01_p04 = pair_set_epi16(sinpi[1], sinpi[4]); @@ -1727,8 +1718,8 @@ static void iadst4_w4_new_sse2(const __m128i *input, __m128i *output, } } -static void iadst8_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst8_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __zero = _mm_setzero_si128(); @@ -1774,8 +1765,7 @@ static void iadst8_low1_new_ssse3(const __m128i *input, __m128i *output, output[7] = _mm_subs_epi16(__zero, x[1]); } -static void iadst8_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst8_sse2(const __m128i *input, __m128i *output, int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __zero = _mm_setzero_si128(); @@ -1843,8 +1833,8 @@ static void iadst8_new_sse2(const __m128i *input, __m128i *output, output[7] = _mm_subs_epi16(__zero, x[1]); } -static void iadst8_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst8_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __zero = _mm_setzero_si128(); @@ -2003,8 +1993,8 @@ static INLINE void iadst16_stage9_ssse3(__m128i *output, __m128i *x) { output[15] = _mm_subs_epi16(__zero, x[1]); } -static void iadst16_low1_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst16_low1_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -2052,8 +2042,8 @@ static void iadst16_low1_new_ssse3(const __m128i *input, __m128i *output, iadst16_stage9_ssse3(output, x); } -static void iadst16_low8_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst16_low8_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -2088,8 +2078,8 @@ static void iadst16_low8_new_ssse3(const __m128i *input, __m128i *output, iadst16_stage8_ssse3(x, cospi, __rounding, cos_bit); iadst16_stage9_ssse3(output, x); } -static void iadst16_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst16_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -2149,8 +2139,8 @@ static void iadst16_new_sse2(const __m128i *input, __m128i *output, iadst16_stage9_ssse3(output, x); } -static void iadst16_w4_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iadst16_w4_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int32_t *cospi = cospi_arr(INV_COS_BIT); const __m128i __rounding = _mm_set1_epi32(1 << (INV_COS_BIT - 1)); @@ -2243,8 +2233,8 @@ static void iadst16_w4_new_sse2(const __m128i *input, __m128i *output, iadst16_stage9_ssse3(output, x); } -static void iidentity4_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iidentity4_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int16_t scale_fractional = (NewSqrt2 - (1 << NewSqrt2Bits)); const __m128i scale = _mm_set1_epi16(scale_fractional << (15 - NewSqrt2Bits)); @@ -2254,16 +2244,16 @@ static void iidentity4_new_ssse3(const __m128i *input, __m128i *output, } } -static void iidentity8_new_sse2(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iidentity8_sse2(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; for (int i = 0; i < 8; ++i) { output[i] = _mm_adds_epi16(input[i], input[i]); } } -static void iidentity16_new_ssse3(const __m128i *input, __m128i *output, - int8_t cos_bit) { +static void iidentity16_ssse3(const __m128i *input, __m128i *output, + int8_t cos_bit) { (void)cos_bit; const int16_t scale_fractional = 2 * (NewSqrt2 - (1 << NewSqrt2Bits)); const __m128i scale = _mm_set1_epi16(scale_fractional << (15 - NewSqrt2Bits)); @@ -2310,11 +2300,11 @@ static INLINE void lowbd_write_buffer_8xn_sse2(__m128i *in, uint8_t *output, // 1D functions process process 8 pixels at one time. static const transform_1d_ssse3 lowbd_txfm_all_1d_w8_arr[TX_SIZES][ITX_TYPES_1D] = { - { idct4_new_sse2, iadst4_new_sse2, iidentity4_new_ssse3 }, - { idct8_new_sse2, iadst8_new_sse2, iidentity8_new_sse2 }, - { idct16_new_sse2, iadst16_new_sse2, iidentity16_new_ssse3 }, - { idct32_new_sse2, NULL, NULL }, - { idct64_low32_new_ssse3, NULL, NULL }, + { idct4_sse2, iadst4_sse2, iidentity4_ssse3 }, + { idct8_sse2, iadst8_sse2, iidentity8_sse2 }, + { idct16_sse2, iadst16_sse2, iidentity16_ssse3 }, + { idct32_sse2, NULL, NULL }, + { idct64_low32_ssse3, NULL, NULL }, }; // functions for blocks with eob at DC and within @@ -2322,26 +2312,24 @@ static const transform_1d_ssse3 static const transform_1d_ssse3 lowbd_txfm_all_1d_zeros_w8_arr[TX_SIZES][ITX_TYPES_1D][4] = { { - { idct4_new_sse2, idct4_new_sse2, NULL, NULL }, - { iadst4_new_sse2, iadst4_new_sse2, NULL, NULL }, - { iidentity4_new_ssse3, iidentity4_new_ssse3, NULL, NULL }, + { idct4_sse2, idct4_sse2, NULL, NULL }, + { iadst4_sse2, iadst4_sse2, NULL, NULL }, + { iidentity4_ssse3, iidentity4_ssse3, NULL, NULL }, }, - { { idct8_low1_new_ssse3, idct8_new_sse2, NULL, NULL }, - { iadst8_low1_new_ssse3, iadst8_new_sse2, NULL, NULL }, - { iidentity8_new_sse2, iidentity8_new_sse2, NULL, NULL } }, + { { idct8_low1_ssse3, idct8_sse2, NULL, NULL }, + { iadst8_low1_ssse3, iadst8_sse2, NULL, NULL }, + { iidentity8_sse2, iidentity8_sse2, NULL, NULL } }, { - { idct16_low1_new_ssse3, idct16_low8_new_ssse3, idct16_new_sse2, - NULL }, - { iadst16_low1_new_ssse3, iadst16_low8_new_ssse3, iadst16_new_sse2, - NULL }, + { idct16_low1_ssse3, idct16_low8_ssse3, idct16_sse2, NULL }, + { iadst16_low1_ssse3, iadst16_low8_ssse3, iadst16_sse2, NULL }, { NULL, NULL, NULL, NULL }, }, - { { idct32_low1_new_ssse3, idct32_low8_new_ssse3, idct32_low16_new_ssse3, - idct32_new_sse2 }, + { { idct32_low1_ssse3, idct32_low8_ssse3, idct32_low16_ssse3, + idct32_sse2 }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } }, - { { idct64_low1_new_ssse3, idct64_low8_new_ssse3, idct64_low16_new_ssse3, - idct64_low32_new_ssse3 }, + { { idct64_low1_ssse3, idct64_low8_ssse3, idct64_low16_ssse3, + idct64_low32_ssse3 }, { NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } } }; @@ -2350,9 +2338,9 @@ static const transform_1d_ssse3 // used in 4x4, 4x8, 4x16, 8x4, 16x4 static const transform_1d_ssse3 lowbd_txfm_all_1d_w4_arr[TX_SIZES][ITX_TYPES_1D] = { - { idct4_w4_new_sse2, iadst4_w4_new_sse2, iidentity4_new_ssse3 }, - { idct8_w4_new_sse2, iadst8_w4_new_sse2, iidentity8_new_sse2 }, - { idct16_w4_new_sse2, iadst16_w4_new_sse2, iidentity16_new_ssse3 }, + { idct4_w4_sse2, iadst4_w4_sse2, iidentity4_ssse3 }, + { idct8_w4_sse2, iadst8_w4_sse2, iidentity8_sse2 }, + { idct16_w4_sse2, iadst16_w4_sse2, iidentity16_ssse3 }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, }; @@ -2830,7 +2818,7 @@ static void lowbd_inv_txfm2d_add_4x16_ssse3(const int32_t *input, load_buffer_32bit_to_16bit_w4(input_cur, txfm_size_col, buf_cur, row_one_loop); transpose_16bit_4x8(buf_cur, buf_cur); - if (row_txfm == iidentity4_new_ssse3) { + if (row_txfm == iidentity4_ssse3) { const __m128i scale = pair_set_epi16(NewSqrt2, 3 << (NewSqrt2Bits - 1)); const __m128i ones = _mm_set1_epi16(1); for (int j = 0; j < 4; ++j) { @@ -2891,7 +2879,7 @@ static void lowbd_inv_txfm2d_add_16x4_ssse3(const int32_t *input, txfm_size_row); transpose_16bit_8x4(buf_cur, buf_cur); } - if (row_txfm == iidentity16_new_ssse3) { + if (row_txfm == iidentity16_ssse3) { const __m128i scale = pair_set_epi16(2 * NewSqrt2, 3 << (NewSqrt2Bits - 1)); const __m128i ones = _mm_set1_epi16(1); for (int j = 0; j < 16; ++j) { diff --git a/media/libaom/src/av1/common/x86/filterintra_sse4.c b/media/libaom/src/av1/common/x86/filterintra_sse4.c index c11edc1d45..99f4d99675 100644 --- a/media/libaom/src/av1/common/x86/filterintra_sse4.c +++ b/media/libaom/src/av1/common/x86/filterintra_sse4.c @@ -27,10 +27,6 @@ void av1_filter_intra_predictor_sse4_1(uint8_t *dst, ptrdiff_t stride, assert(bw <= 32 && bh <= 32); - // The initialization is just for silencing Jenkins static analysis warnings - for (r = 0; r < bh + 1; ++r) - memset(buffer[r], 0, (bw + 1) * sizeof(buffer[0][0])); - for (r = 0; r < bh; ++r) buffer[r + 1][0] = left[r]; memcpy(buffer[0], &above[-1], (bw + 1) * sizeof(uint8_t)); diff --git a/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c b/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c index 6713da1a5d..93e98e4b3d 100644 --- a/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c +++ b/media/libaom/src/av1/common/x86/highbd_inv_txfm_avx2.c @@ -3273,7 +3273,6 @@ static void idct64_low8_avx2(__m256i *in, __m256i *out, int bit, int do_cols, u[6] = u[1]; u[5] = u[2]; u[4] = u[3]; - u[9] = u[9]; idct64_stage8_avx2(u, &cospim32, &cospi32, &cospim16, &cospi48, &cospi16, &cospim48, &clamp_lo, &clamp_hi, &rnding, bit); diff --git a/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c b/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c index 4976d93461..03eaef832b 100644 --- a/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c +++ b/media/libaom/src/av1/common/x86/highbd_inv_txfm_sse4.c @@ -3576,7 +3576,6 @@ static void idct64x64_low8_sse4_1(__m128i *in, __m128i *out, int bit, u[6] = u[1]; u[5] = u[2]; u[4] = u[3]; - u[9] = u[9]; idct64_stage8_sse4_1(u, &cospim32, &cospi32, &cospim16, &cospi48, &cospi16, &cospim48, &clamp_lo, &clamp_hi, &rnding, bit); diff --git a/media/libaom/src/av1/decoder/decodeframe.c b/media/libaom/src/av1/decoder/decodeframe.c index 963d1fe4b9..7abfac4aaa 100644 --- a/media/libaom/src/av1/decoder/decodeframe.c +++ b/media/libaom/src/av1/decoder/decodeframe.c @@ -121,23 +121,13 @@ static AOM_INLINE void loop_restoration_read_sb_coeffs( const AV1_COMMON *const cm, MACROBLOCKD *xd, aom_reader *const r, int plane, int runit_idx); -static AOM_INLINE void setup_compound_reference_mode(AV1_COMMON *cm) { - cm->comp_fwd_ref[0] = LAST_FRAME; - cm->comp_fwd_ref[1] = LAST2_FRAME; - cm->comp_fwd_ref[2] = LAST3_FRAME; - cm->comp_fwd_ref[3] = GOLDEN_FRAME; - - cm->comp_bwd_ref[0] = BWDREF_FRAME; - cm->comp_bwd_ref[1] = ALTREF2_FRAME; - cm->comp_bwd_ref[2] = ALTREF_FRAME; -} - static int read_is_valid(const uint8_t *start, size_t len, const uint8_t *end) { return len != 0 && len <= (size_t)(end - start); } -static TX_MODE read_tx_mode(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { - if (cm->coded_lossless) return ONLY_4X4; +static TX_MODE read_tx_mode(struct aom_read_bit_buffer *rb, + int coded_lossless) { + if (coded_lossless) return ONLY_4X4; return aom_rb_read_bit(rb) ? TX_MODE_SELECT : TX_MODE_LARGEST; } @@ -200,12 +190,9 @@ static AOM_INLINE void decode_block_void(const AV1_COMMON *const cm, static AOM_INLINE void predict_inter_block_void(AV1_COMMON *const cm, MACROBLOCKD *const xd, - int mi_row, int mi_col, BLOCK_SIZE bsize) { (void)cm; (void)xd; - (void)mi_row; - (void)mi_col; (void)bsize; } @@ -228,13 +215,13 @@ static AOM_INLINE void predict_and_reconstruct_intra_block( struct macroblockd_plane *const pd = &xd->plane[plane]; eob_info *eob_data = pd->eob_data + xd->txb_offset[plane]; if (eob_data->eob) { + const bool reduced_tx_set_used = cm->features.reduced_tx_set_used; // tx_type was read out in av1_read_coeffs_txb. const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, row, col, tx_size, - cm->reduced_tx_set_used); - uint8_t *dst = - &pd->dst.buf[(row * pd->dst.stride + col) << tx_size_wide_log2[0]]; + reduced_tx_set_used); + uint8_t *dst = &pd->dst.buf[(row * pd->dst.stride + col) << MI_SIZE_LOG2]; inverse_transform_block(xd, plane, tx_type, tx_size, dst, pd->dst.stride, - cm->reduced_tx_set_used); + reduced_tx_set_used); } } if (plane == AOM_PLANE_Y && store_cfl_required(cm, xd)) { @@ -249,16 +236,15 @@ static AOM_INLINE void inverse_transform_inter_block( (void)r; PLANE_TYPE plane_type = get_plane_type(plane); const struct macroblockd_plane *const pd = &xd->plane[plane]; - + const bool reduced_tx_set_used = cm->features.reduced_tx_set_used; // tx_type was read out in av1_read_coeffs_txb. const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, cm->reduced_tx_set_used); + tx_size, reduced_tx_set_used); uint8_t *dst = - &pd->dst - .buf[(blk_row * pd->dst.stride + blk_col) << tx_size_wide_log2[0]]; + &pd->dst.buf[(blk_row * pd->dst.stride + blk_col) << MI_SIZE_LOG2]; inverse_transform_block(xd, plane, tx_type, tx_size, dst, pd->dst.stride, - cm->reduced_tx_set_used); + reduced_tx_set_used); #if CONFIG_MISMATCH_DEBUG int pixel_c, pixel_r; BLOCK_SIZE bsize = txsize_to_bsize[tx_size]; @@ -336,37 +322,31 @@ static AOM_INLINE void set_offsets(AV1_COMMON *const cm, MACROBLOCKD *const xd, BLOCK_SIZE bsize, int mi_row, int mi_col, int bw, int bh, int x_mis, int y_mis) { const int num_planes = av1_num_planes(cm); - + const CommonModeInfoParams *const mi_params = &cm->mi_params; const TileInfo *const tile = &xd->tile; - xd->mi = cm->mi_grid_base + get_mi_grid_idx(cm, mi_row, mi_col); - xd->mi[0] = &cm->mi[get_alloc_mi_idx(cm, mi_row, mi_col)]; - xd->tx_type_map = &cm->tx_type_map[mi_row * cm->mi_stride + mi_col]; - xd->tx_type_map_stride = cm->mi_stride; - // TODO(slavarnway): Generate sb_type based on bwl and bhl, instead of - // passing bsize from decode_partition(). + set_mi_offsets(mi_params, xd, mi_row, mi_col); xd->mi[0]->sb_type = bsize; #if CONFIG_RD_DEBUG xd->mi[0]->mi_row = mi_row; xd->mi[0]->mi_col = mi_col; #endif - xd->cfl.mi_row = mi_row; - xd->cfl.mi_col = mi_col; assert(x_mis && y_mis); for (int x = 1; x < x_mis; ++x) xd->mi[x] = xd->mi[0]; - int idx = cm->mi_stride; + int idx = mi_params->mi_stride; for (int y = 1; y < y_mis; ++y) { memcpy(&xd->mi[idx], &xd->mi[0], x_mis * sizeof(xd->mi[0])); - idx += cm->mi_stride; + idx += mi_params->mi_stride; } set_plane_n4(xd, bw, bh, num_planes); - set_skip_context(xd, mi_row, mi_col, num_planes); + set_entropy_context(xd, mi_row, mi_col, num_planes); // Distance of Mb to the various image edges. These are specified to 8th pel // as they are always compared to values that are in 1/8th pel units - set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols); + set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, mi_params->mi_rows, + mi_params->mi_cols); av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col, 0, num_planes); @@ -381,15 +361,15 @@ static AOM_INLINE void decode_mbmi_block(AV1Decoder *const pbi, const SequenceHeader *const seq_params = &cm->seq_params; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; - const int x_mis = AOMMIN(bw, cm->mi_cols - mi_col); - const int y_mis = AOMMIN(bh, cm->mi_rows - mi_row); + const int x_mis = AOMMIN(bw, cm->mi_params.mi_cols - mi_col); + const int y_mis = AOMMIN(bh, cm->mi_params.mi_rows - mi_row); #if CONFIG_ACCOUNTING aom_accounting_set_context(&pbi->accounting, mi_col, mi_row); #endif set_offsets(cm, xd, bsize, mi_row, mi_col, bw, bh, x_mis, y_mis); xd->mi[0]->partition = partition; - av1_read_mode_info(pbi, xd, mi_row, mi_col, r, x_mis, y_mis); + av1_read_mode_info(pbi, xd, r, x_mis, y_mis); if (bsize >= BLOCK_8X8 && (seq_params->subsampling_x || seq_params->subsampling_y)) { const BLOCK_SIZE uv_subsize = @@ -559,21 +539,25 @@ static INLINE void extend_mc_border(const struct scale_factors *const sf, } } -static INLINE void dec_calc_subpel_params( - MACROBLOCKD *xd, const struct scale_factors *const sf, const MV mv, - int plane, const int pre_x, const int pre_y, int x, int y, - struct buf_2d *const pre_buf, SubpelParams *subpel_params, int bw, int bh, - PadBlock *block, int mi_x, int mi_y, MV32 *scaled_mv, int *subpel_x_mv, - int *subpel_y_mv) { - struct macroblockd_plane *const pd = &xd->plane[plane]; +static void dec_calc_subpel_params(const MV *const src_mv, + InterPredParams *const inter_pred_params, + const MACROBLOCKD *const xd, int mi_x, + int mi_y, uint8_t **pre, + SubpelParams *subpel_params, int *src_stride, + PadBlock *block, MV32 *scaled_mv, + int *subpel_x_mv, int *subpel_y_mv) { + const struct scale_factors *sf = inter_pred_params->scale_factors; + struct buf_2d *pre_buf = &inter_pred_params->ref_frame_buf; + const int bw = inter_pred_params->block_width; + const int bh = inter_pred_params->block_height; const int is_scaled = av1_is_scaled(sf); if (is_scaled) { - int ssx = pd->subsampling_x; - int ssy = pd->subsampling_y; - int orig_pos_y = (pre_y + y) << SUBPEL_BITS; - orig_pos_y += mv.row * (1 << (1 - ssy)); - int orig_pos_x = (pre_x + x) << SUBPEL_BITS; - orig_pos_x += mv.col * (1 << (1 - ssx)); + int ssx = inter_pred_params->subsampling_x; + int ssy = inter_pred_params->subsampling_y; + int orig_pos_y = inter_pred_params->pix_row << SUBPEL_BITS; + orig_pos_y += src_mv->row * (1 << (1 - ssy)); + int orig_pos_x = inter_pred_params->pix_col << SUBPEL_BITS; + orig_pos_x += src_mv->col * (1 << (1 - ssx)); int pos_y = sf->scale_value_y(orig_pos_y, sf); int pos_x = sf->scale_value_x(orig_pos_x, sf); pos_x += SCALE_EXTRA_OFF; @@ -603,9 +587,10 @@ static INLINE void dec_calc_subpel_params( ((pos_y + (bh - 1) * subpel_params->ys) >> SCALE_SUBPEL_BITS) + 1; MV temp_mv; - temp_mv = clamp_mv_to_umv_border_sb(xd, &mv, bw, bh, pd->subsampling_x, - pd->subsampling_y); - *scaled_mv = av1_scale_mv(&temp_mv, (mi_x + x), (mi_y + y), sf); + temp_mv = clamp_mv_to_umv_border_sb(xd, src_mv, bw, bh, + inter_pred_params->subsampling_x, + inter_pred_params->subsampling_y); + *scaled_mv = av1_scale_mv(&temp_mv, mi_x, mi_y, sf); scaled_mv->row += SCALE_EXTRA_OFF; scaled_mv->col += SCALE_EXTRA_OFF; @@ -613,11 +598,12 @@ static INLINE void dec_calc_subpel_params( *subpel_y_mv = scaled_mv->row & SCALE_SUBPEL_MASK; } else { // Get block position in current frame. - int pos_x = (pre_x + x) << SUBPEL_BITS; - int pos_y = (pre_y + y) << SUBPEL_BITS; + int pos_x = inter_pred_params->pix_col << SUBPEL_BITS; + int pos_y = inter_pred_params->pix_row << SUBPEL_BITS; const MV mv_q4 = clamp_mv_to_umv_border_sb( - xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); + xd, src_mv, bw, bh, inter_pred_params->subsampling_x, + inter_pred_params->subsampling_y); subpel_params->xs = subpel_params->ys = SCALE_SUBPEL_SHIFTS; subpel_params->subpel_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; subpel_params->subpel_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; @@ -637,301 +623,79 @@ static INLINE void dec_calc_subpel_params( *subpel_x_mv = scaled_mv->col & SUBPEL_MASK; *subpel_y_mv = scaled_mv->row & SUBPEL_MASK; } + *pre = pre_buf->buf0 + block->y0 * pre_buf->stride + block->x0; + *src_stride = pre_buf->stride; } -static INLINE void dec_build_inter_predictors(const AV1_COMMON *cm, - MACROBLOCKD *xd, int plane, - const MB_MODE_INFO *mi, - int build_for_obmc, int bw, - int bh, int mi_x, int mi_y) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - int is_compound = has_second_ref(mi); - int ref; - const int is_intrabc = is_intrabc_block(mi); - assert(IMPLIES(is_intrabc, !is_compound)); - int is_global[2] = { 0, 0 }; - for (ref = 0; ref < 1 + is_compound; ++ref) { - const WarpedMotionParams *const wm = &xd->global_motion[mi->ref_frame[ref]]; - is_global[ref] = is_global_mv_block(mi, wm->wmtype); - } - - const BLOCK_SIZE bsize = mi->sb_type; - const int ss_x = pd->subsampling_x; - const int ss_y = pd->subsampling_y; - int sub8x8_inter = (block_size_wide[bsize] < 8 && ss_x) || - (block_size_high[bsize] < 8 && ss_y); - - if (is_intrabc) sub8x8_inter = 0; - - // For sub8x8 chroma blocks, we may be covering more than one luma block's - // worth of pixels. Thus (mi_x, mi_y) may not be the correct coordinates for - // the top-left corner of the prediction source - the correct top-left corner - // is at (pre_x, pre_y). - const int row_start = - (block_size_high[bsize] == 4) && ss_y && !build_for_obmc ? -1 : 0; - const int col_start = - (block_size_wide[bsize] == 4) && ss_x && !build_for_obmc ? -1 : 0; - const int pre_x = (mi_x + MI_SIZE * col_start) >> ss_x; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ss_y; - - sub8x8_inter = sub8x8_inter && !build_for_obmc; - if (sub8x8_inter) { - for (int row = row_start; row <= 0 && sub8x8_inter; ++row) { - for (int col = col_start; col <= 0; ++col) { - const MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; - if (!is_inter_block(this_mbmi)) sub8x8_inter = 0; - if (is_intrabc_block(this_mbmi)) sub8x8_inter = 0; - } - } - } - - if (sub8x8_inter) { - // block size - const int b4_w = block_size_wide[bsize] >> ss_x; - const int b4_h = block_size_high[bsize] >> ss_y; - const BLOCK_SIZE plane_bsize = scale_chroma_bsize(bsize, ss_x, ss_y); - const int b8_w = block_size_wide[plane_bsize] >> ss_x; - const int b8_h = block_size_high[plane_bsize] >> ss_y; - assert(!is_compound); - - const struct buf_2d orig_pred_buf[2] = { pd->pre[0], pd->pre[1] }; - - int row = row_start; - int src_stride; - for (int y = 0; y < b8_h; y += b4_h) { - int col = col_start; - for (int x = 0; x < b8_w; x += b4_w) { - MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; - is_compound = has_second_ref(this_mbmi); - int tmp_dst_stride = 8; - InterPredParams inter_pred_params; - assert(bw < 8 || bh < 8); - inter_pred_params.conv_params = get_conv_params_no_round( - 0, plane, xd->tmp_conv_dst, tmp_dst_stride, is_compound, xd->bd); - inter_pred_params.conv_params.use_dist_wtd_comp_avg = 0; - struct buf_2d *const dst_buf = &pd->dst; - uint8_t *dst = dst_buf->buf + dst_buf->stride * y + x; - - ref = 0; - const RefCntBuffer *ref_buf = - get_ref_frame_buf(cm, this_mbmi->ref_frame[ref]); - const struct scale_factors *ref_scale_factors = - get_ref_scale_factors_const(cm, this_mbmi->ref_frame[ref]); - - pd->pre[ref].buf0 = - (plane == 1) ? ref_buf->buf.u_buffer : ref_buf->buf.v_buffer; - pd->pre[ref].buf = - pd->pre[ref].buf0 + scaled_buffer_offset(pre_x, pre_y, - ref_buf->buf.uv_stride, - ref_scale_factors); - pd->pre[ref].width = ref_buf->buf.uv_crop_width; - pd->pre[ref].height = ref_buf->buf.uv_crop_height; - pd->pre[ref].stride = ref_buf->buf.uv_stride; - - const struct scale_factors *const sf = - is_intrabc ? &cm->sf_identity : ref_scale_factors; - struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; - - const MV mv = this_mbmi->mv[ref].as_mv; - - uint8_t *pre; - SubpelParams subpel_params; - PadBlock block; - MV32 scaled_mv; - int subpel_x_mv, subpel_y_mv; - int highbd; - - dec_calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, x, y, pre_buf, - &subpel_params, bw, bh, &block, mi_x, mi_y, - &scaled_mv, &subpel_x_mv, &subpel_y_mv); - pre = pre_buf->buf0 + block.y0 * pre_buf->stride + block.x0; - src_stride = pre_buf->stride; - highbd = is_cur_buf_hbd(xd); - extend_mc_border(sf, pre_buf, scaled_mv, block, subpel_x_mv, - subpel_y_mv, 0, is_intrabc, highbd, xd->mc_buf[ref], - &pre, &src_stride); - inter_pred_params.conv_params.do_average = ref; - - av1_init_inter_params( - &inter_pred_params, b4_w, b4_h, (mi_y >> pd->subsampling_y) + y, - (mi_x >> pd->subsampling_x) + x, pd->subsampling_x, - pd->subsampling_y, xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, - this_mbmi->interp_filters); - - av1_make_inter_predictor(pre, src_stride, dst, dst_buf->stride, - &inter_pred_params, &subpel_params); - - ++col; - } - ++row; - } - - for (ref = 0; ref < 2; ++ref) pd->pre[ref] = orig_pred_buf[ref]; - return; - } - - { - struct buf_2d *const dst_buf = &pd->dst; - uint8_t *const dst = dst_buf->buf; - uint8_t *pre[2]; - InterPredParams inter_pred_params; - SubpelParams subpel_params[2]; - int src_stride[2]; - for (ref = 0; ref < 1 + is_compound; ++ref) { - const struct scale_factors *const sf = - is_intrabc ? &cm->sf_identity : xd->block_ref_scale_factors[ref]; - struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; - const MV mv = mi->mv[ref].as_mv; - PadBlock block; - MV32 scaled_mv; - int subpel_x_mv, subpel_y_mv; - int highbd; - - 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 + (int64_t)block.y0 * pre_buf->stride + block.x0; - src_stride[ref] = pre_buf->stride; - highbd = is_cur_buf_hbd(xd); - - WarpTypesAllowed warp_types; - warp_types.global_warp_allowed = is_global[ref]; - warp_types.local_warp_allowed = mi->motion_mode == WARPED_CAUSAL; - int do_warp = (bw >= 8 && bh >= 8 && - av1_allow_warp(mi, &warp_types, - &xd->global_motion[mi->ref_frame[ref]], - build_for_obmc, sf, NULL)); - do_warp = (do_warp && xd->cur_frame_force_integer_mv == 0); - - extend_mc_border(sf, pre_buf, scaled_mv, block, subpel_x_mv, subpel_y_mv, - do_warp, is_intrabc, highbd, xd->mc_buf[ref], &pre[ref], - &src_stride[ref]); - } - - inter_pred_params.conv_params = get_conv_params_no_round( - 0, plane, xd->tmp_conv_dst, MAX_SB_SIZE, is_compound, xd->bd); - av1_dist_wtd_comp_weight_assign( - cm, mi, 0, &inter_pred_params.conv_params.fwd_offset, - &inter_pred_params.conv_params.bck_offset, - &inter_pred_params.conv_params.use_dist_wtd_comp_avg, is_compound); - - for (ref = 0; ref < 1 + is_compound; ++ref) { - const struct scale_factors *const sf = - is_intrabc ? &cm->sf_identity : xd->block_ref_scale_factors[ref]; - WarpTypesAllowed warp_types; - warp_types.global_warp_allowed = is_global[ref]; - warp_types.local_warp_allowed = mi->motion_mode == WARPED_CAUSAL; - inter_pred_params.conv_params.do_average = ref; - if (is_masked_compound_type(mi->interinter_comp.type)) { - // masked compound type has its own average mechanism - inter_pred_params.conv_params.do_average = 0; - } - - av1_init_inter_params( - &inter_pred_params, bw, bh, mi_y >> pd->subsampling_y, - mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, mi->interp_filters); - - if (!build_for_obmc) - av1_init_warp_params(&inter_pred_params, &pd->pre[ref], &warp_types, - ref, xd, mi); - - if (ref && is_masked_compound_type(mi->interinter_comp.type)) - av1_make_masked_inter_predictor(pre[ref], src_stride[ref], dst, - dst_buf->stride, &inter_pred_params, - &subpel_params[ref], bw, bh, plane, xd); - else - av1_make_inter_predictor(pre[ref], src_stride[ref], dst, - dst_buf->stride, &inter_pred_params, - &subpel_params[ref]); - } - } +static void dec_calc_subpel_params_and_extend( + const MV *const src_mv, InterPredParams *const inter_pred_params, + MACROBLOCKD *xd, int mi_x, int mi_y, int ref, uint8_t **pre, + SubpelParams *subpel_params, int *src_stride) { + PadBlock block; + MV32 scaled_mv; + int subpel_x_mv, subpel_y_mv; + dec_calc_subpel_params(src_mv, inter_pred_params, xd, mi_x, mi_y, pre, + subpel_params, src_stride, &block, &scaled_mv, + &subpel_x_mv, &subpel_y_mv); + extend_mc_border( + inter_pred_params->scale_factors, &inter_pred_params->ref_frame_buf, + scaled_mv, block, subpel_x_mv, subpel_y_mv, + inter_pred_params->mode == WARP_PRED, inter_pred_params->is_intrabc, + inter_pred_params->use_hbd_buf, xd->mc_buf[ref], pre, src_stride); } -static AOM_INLINE void dec_build_inter_predictors_for_planes( - const AV1_COMMON *cm, MACROBLOCKD *xd, BLOCK_SIZE bsize, int mi_row, - int mi_col, int plane_from, int plane_to) { - int plane; - const int mi_x = mi_col * MI_SIZE; - const int mi_y = mi_row * MI_SIZE; - for (plane = plane_from; plane <= plane_to; ++plane) { - const struct macroblockd_plane *pd = &xd->plane[plane]; - const int bw = pd->width; - const int bh = pd->height; - - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) - continue; - - dec_build_inter_predictors(cm, xd, plane, xd->mi[0], 0, bw, bh, mi_x, mi_y); - } +static void dec_build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, + int plane, const MB_MODE_INFO *mi, + int build_for_obmc, int bw, int bh, + int mi_x, int mi_y) { + av1_build_inter_predictors(cm, xd, plane, mi, build_for_obmc, bw, bh, mi_x, + mi_y, dec_calc_subpel_params_and_extend); } -static AOM_INLINE void dec_build_inter_predictors_sby(const AV1_COMMON *cm, - MACROBLOCKD *xd, - int mi_row, int mi_col, - const BUFFER_SET *ctx, - BLOCK_SIZE bsize) { - dec_build_inter_predictors_for_planes(cm, xd, bsize, mi_row, mi_col, 0, 0); - - if (is_interintra_pred(xd->mi[0])) { - BUFFER_SET default_ctx = { { xd->plane[0].dst.buf, NULL, NULL }, - { xd->plane[0].dst.stride, 0, 0 } }; - if (!ctx) ctx = &default_ctx; - av1_build_interintra_predictors_sbp(cm, xd, xd->plane[0].dst.buf, - xd->plane[0].dst.stride, ctx, 0, bsize); - } -} - -static AOM_INLINE void dec_build_inter_predictors_sbuv(const AV1_COMMON *cm, - MACROBLOCKD *xd, - int mi_row, int mi_col, - const BUFFER_SET *ctx, - BLOCK_SIZE bsize) { - dec_build_inter_predictors_for_planes(cm, xd, bsize, mi_row, mi_col, 1, - MAX_MB_PLANE - 1); - - if (is_interintra_pred(xd->mi[0])) { - BUFFER_SET default_ctx = { - { NULL, xd->plane[1].dst.buf, xd->plane[2].dst.buf }, - { 0, xd->plane[1].dst.stride, xd->plane[2].dst.stride } - }; - if (!ctx) ctx = &default_ctx; - av1_build_interintra_predictors_sbuv( - cm, xd, xd->plane[1].dst.buf, xd->plane[2].dst.buf, - xd->plane[1].dst.stride, xd->plane[2].dst.stride, ctx, bsize); - } -} - -static AOM_INLINE void dec_build_inter_predictors_sb(const AV1_COMMON *cm, - MACROBLOCKD *xd, - int mi_row, int mi_col, - BUFFER_SET *ctx, - BLOCK_SIZE bsize) { +static AOM_INLINE void dec_build_inter_predictor(const AV1_COMMON *cm, + MACROBLOCKD *xd, int mi_row, + int mi_col, BLOCK_SIZE bsize) { const int num_planes = av1_num_planes(cm); - dec_build_inter_predictors_sby(cm, xd, mi_row, mi_col, ctx, bsize); - if (num_planes > 1) - dec_build_inter_predictors_sbuv(cm, xd, mi_row, mi_col, ctx, bsize); + for (int plane = 0; plane < num_planes; ++plane) { + if (plane && !xd->is_chroma_ref) break; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; + dec_build_inter_predictors(cm, xd, plane, xd->mi[0], 0, + xd->plane[plane].width, xd->plane[plane].height, + mi_x, mi_y); + if (is_interintra_pred(xd->mi[0])) { + BUFFER_SET ctx = { { xd->plane[0].dst.buf, xd->plane[1].dst.buf, + xd->plane[2].dst.buf }, + { xd->plane[0].dst.stride, xd->plane[1].dst.stride, + xd->plane[2].dst.stride } }; + av1_build_interintra_predictor(cm, xd, xd->plane[plane].dst.buf, + xd->plane[plane].dst.stride, &ctx, plane, + bsize); + } + } } static INLINE void dec_build_prediction_by_above_pred( - MACROBLOCKD *xd, int rel_mi_col, uint8_t above_mi_width, - MB_MODE_INFO *above_mbmi, void *fun_ctxt, const int num_planes) { + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *above_mbmi, void *fun_ctxt, const int num_planes) { struct build_prediction_ctxt *ctxt = (struct build_prediction_ctxt *)fun_ctxt; - const int above_mi_col = ctxt->mi_col + rel_mi_col; + const int above_mi_col = xd->mi_col + rel_mi_col; int mi_x, mi_y; MB_MODE_INFO backup_mbmi = *above_mbmi; - av1_setup_build_prediction_by_above_pred(xd, rel_mi_col, above_mi_width, + (void)rel_mi_row; + (void)dir; + + av1_setup_build_prediction_by_above_pred(xd, rel_mi_col, op_mi_size, &backup_mbmi, ctxt, num_planes); mi_x = above_mi_col << MI_SIZE_LOG2; - mi_y = ctxt->mi_row << MI_SIZE_LOG2; + mi_y = xd->mi_row << MI_SIZE_LOG2; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; for (int j = 0; j < num_planes; ++j) { const struct macroblockd_plane *pd = &xd->plane[j]; - int bw = (above_mi_width * MI_SIZE) >> pd->subsampling_x; + int bw = (op_mi_size * MI_SIZE) >> pd->subsampling_x; int bh = clamp(block_size_high[bsize] >> (pd->subsampling_y + 1), 4, block_size_high[BLOCK_64X64] >> (pd->subsampling_y + 1)); @@ -942,43 +706,44 @@ static INLINE void dec_build_prediction_by_above_pred( } static AOM_INLINE void dec_build_prediction_by_above_preds( - const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, - uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], - int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]) { + const AV1_COMMON *cm, MACROBLOCKD *xd, uint8_t *tmp_buf[MAX_MB_PLANE], + int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], + int tmp_stride[MAX_MB_PLANE]) { if (!xd->up_available) return; // Adjust mb_to_bottom_edge to have the correct value for the OBMC // prediction block. This is half the height of the original block, // except for 128-wide blocks, where we only use a height of 32. - int this_height = xd->n4_h * MI_SIZE; - int pred_height = AOMMIN(this_height / 2, 32); - xd->mb_to_bottom_edge += (this_height - pred_height) * 8; - - struct build_prediction_ctxt ctxt = { cm, mi_row, - mi_col, tmp_buf, + const int this_height = xd->height * MI_SIZE; + const int pred_height = AOMMIN(this_height / 2, 32); + xd->mb_to_bottom_edge += GET_MV_SUBPEL(this_height - pred_height); + struct build_prediction_ctxt ctxt = { cm, tmp_buf, tmp_width, tmp_height, tmp_stride, xd->mb_to_right_edge }; - BLOCK_SIZE bsize = xd->mi[0]->sb_type; - foreach_overlappable_nb_above(cm, xd, mi_col, + const BLOCK_SIZE bsize = xd->mi[0]->sb_type; + foreach_overlappable_nb_above(cm, xd, max_neighbor_obmc[mi_size_wide_log2[bsize]], dec_build_prediction_by_above_pred, &ctxt); - xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8); + xd->mb_to_left_edge = -GET_MV_SUBPEL(xd->mi_col * MI_SIZE); xd->mb_to_right_edge = ctxt.mb_to_far_edge; - xd->mb_to_bottom_edge -= (this_height - pred_height) * 8; + xd->mb_to_bottom_edge -= GET_MV_SUBPEL(this_height - pred_height); } static INLINE void dec_build_prediction_by_left_pred( - MACROBLOCKD *xd, int rel_mi_row, uint8_t left_mi_height, - MB_MODE_INFO *left_mbmi, void *fun_ctxt, const int num_planes) { + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *left_mbmi, void *fun_ctxt, const int num_planes) { struct build_prediction_ctxt *ctxt = (struct build_prediction_ctxt *)fun_ctxt; - const int left_mi_row = ctxt->mi_row + rel_mi_row; + const int left_mi_row = xd->mi_row + rel_mi_row; int mi_x, mi_y; MB_MODE_INFO backup_mbmi = *left_mbmi; - av1_setup_build_prediction_by_left_pred(xd, rel_mi_row, left_mi_height, + (void)rel_mi_col; + (void)dir; + + av1_setup_build_prediction_by_left_pred(xd, rel_mi_row, op_mi_size, &backup_mbmi, ctxt, num_planes); - mi_x = ctxt->mi_col << MI_SIZE_LOG2; + mi_x = xd->mi_col << MI_SIZE_LOG2; mi_y = left_mi_row << MI_SIZE_LOG2; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; @@ -986,7 +751,7 @@ static INLINE void dec_build_prediction_by_left_pred( const struct macroblockd_plane *pd = &xd->plane[j]; int bw = clamp(block_size_wide[bsize] >> (pd->subsampling_x + 1), 4, block_size_wide[BLOCK_64X64] >> (pd->subsampling_x + 1)); - int bh = (left_mi_height << MI_SIZE_LOG2) >> pd->subsampling_y; + int bh = (op_mi_size << MI_SIZE_LOG2) >> pd->subsampling_y; if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue; dec_build_inter_predictors(ctxt->cm, xd, j, &backup_mbmi, 1, bw, bh, mi_x, @@ -995,29 +760,28 @@ static INLINE void dec_build_prediction_by_left_pred( } static AOM_INLINE void dec_build_prediction_by_left_preds( - const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, - uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], - int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]) { + const AV1_COMMON *cm, MACROBLOCKD *xd, uint8_t *tmp_buf[MAX_MB_PLANE], + int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], + int tmp_stride[MAX_MB_PLANE]) { if (!xd->left_available) return; // Adjust mb_to_right_edge to have the correct value for the OBMC // prediction block. This is half the width of the original block, // except for 128-wide blocks, where we only use a width of 32. - int this_width = xd->n4_w * MI_SIZE; - int pred_width = AOMMIN(this_width / 2, 32); - xd->mb_to_right_edge += (this_width - pred_width) * 8; + const int this_width = xd->width * MI_SIZE; + const int pred_width = AOMMIN(this_width / 2, 32); + xd->mb_to_right_edge += GET_MV_SUBPEL(this_width - pred_width); - struct build_prediction_ctxt ctxt = { cm, mi_row, - mi_col, tmp_buf, + struct build_prediction_ctxt ctxt = { cm, tmp_buf, tmp_width, tmp_height, tmp_stride, xd->mb_to_bottom_edge }; - BLOCK_SIZE bsize = xd->mi[0]->sb_type; - foreach_overlappable_nb_left(cm, xd, mi_row, + const BLOCK_SIZE bsize = xd->mi[0]->sb_type; + foreach_overlappable_nb_left(cm, xd, max_neighbor_obmc[mi_size_high_log2[bsize]], dec_build_prediction_by_left_pred, &ctxt); - xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8); - xd->mb_to_right_edge -= (this_width - pred_width) * 8; + xd->mb_to_top_edge = -GET_MV_SUBPEL(xd->mi_row * MI_SIZE); + xd->mb_to_right_edge -= GET_MV_SUBPEL(this_width - pred_width); xd->mb_to_bottom_edge = ctxt.mb_to_far_edge; } @@ -1047,9 +811,7 @@ static void set_dst_buf_highbd(MACROBLOCKD *xd, uint8_t **dst_buf1, #endif static AOM_INLINE void dec_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, - MACROBLOCKD *xd, - int mi_row, - int mi_col) { + MACROBLOCKD *xd) { const int num_planes = av1_num_planes(cm); uint8_t *dst_buf1[MAX_MB_PLANE], *dst_buf2[MAX_MB_PLANE]; int dst_stride1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }; @@ -1069,14 +831,16 @@ static AOM_INLINE void dec_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, set_dst_buf(xd, dst_buf1, dst_buf2); #endif - dec_build_prediction_by_above_preds(cm, xd, mi_row, mi_col, dst_buf1, - dst_width1, dst_height1, dst_stride1); - dec_build_prediction_by_left_preds(cm, xd, mi_row, mi_col, dst_buf2, - dst_width2, dst_height2, dst_stride2); + dec_build_prediction_by_above_preds(cm, xd, dst_buf1, dst_width1, dst_height1, + dst_stride1); + dec_build_prediction_by_left_preds(cm, xd, dst_buf2, dst_width2, dst_height2, + dst_stride2); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; av1_setup_dst_planes(xd->plane, xd->mi[0]->sb_type, &cm->cur_frame->buf, mi_row, mi_col, 0, num_planes); - av1_build_obmc_inter_prediction(cm, xd, mi_row, mi_col, dst_buf1, dst_stride1, - dst_buf2, dst_stride2); + av1_build_obmc_inter_prediction(cm, xd, dst_buf1, dst_stride1, dst_buf2, + dst_stride2); } static AOM_INLINE void cfl_store_inter_block(AV1_COMMON *const cm, @@ -1088,10 +852,12 @@ static AOM_INLINE void cfl_store_inter_block(AV1_COMMON *const cm, } static AOM_INLINE void predict_inter_block(AV1_COMMON *const cm, - MACROBLOCKD *const xd, int mi_row, - int mi_col, BLOCK_SIZE bsize) { + MACROBLOCKD *const xd, + BLOCK_SIZE bsize) { MB_MODE_INFO *mbmi = xd->mi[0]; const int num_planes = av1_num_planes(cm); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; for (int ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; if (frame < LAST_FRAME) { @@ -1109,9 +875,9 @@ static AOM_INLINE void predict_inter_block(AV1_COMMON *const cm, } } - dec_build_inter_predictors_sb(cm, xd, mi_row, mi_col, NULL, bsize); + dec_build_inter_predictor(cm, xd, mi_row, mi_col, bsize); if (mbmi->motion_mode == OBMC_CAUSAL) { - dec_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); + dec_build_obmc_inter_predictors_sb(cm, xd); } #if CONFIG_MISMATCH_DEBUG for (int plane = 0; plane < num_planes; ++plane) { @@ -1142,17 +908,12 @@ static AOM_INLINE void set_color_index_map_offset(MACROBLOCKD *const xd, static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, ThreadData *const td, - int mi_row, int mi_col, aom_reader *r, BLOCK_SIZE bsize) { AV1_COMMON *const cm = &pbi->common; MACROBLOCKD *const xd = &td->xd; const int num_planes = av1_num_planes(cm); - MB_MODE_INFO *mbmi = xd->mi[0]; - CFL_CTX *const cfl = &xd->cfl; - cfl->is_chroma_reference = is_chroma_reference( - mi_row, mi_col, bsize, cfl->subsampling_x, cfl->subsampling_y); if (!is_inter_block(mbmi)) { int row, col; @@ -1161,21 +922,16 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, const int max_blocks_wide = max_block_wide(xd, bsize, 0); const int max_blocks_high = max_block_high(xd, bsize, 0); const BLOCK_SIZE max_unit_bsize = BLOCK_64X64; - int mu_blocks_wide = - block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = - block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(max_blocks_wide, mu_blocks_wide); mu_blocks_high = AOMMIN(max_blocks_high, mu_blocks_high); for (row = 0; row < max_blocks_high; row += mu_blocks_high) { for (col = 0; col < max_blocks_wide; col += mu_blocks_wide) { for (int plane = 0; plane < num_planes; ++plane) { + if (plane && !xd->is_chroma_ref) break; const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) - continue; - const TX_SIZE tx_size = av1_get_tx_size(plane, xd); const int stepr = tx_size_high_unit[tx_size]; const int stepc = tx_size_wide_unit[tx_size]; @@ -1200,7 +956,7 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, } } } else { - td->predict_inter_block_visit(cm, xd, mi_row, mi_col, bsize); + td->predict_inter_block_visit(cm, xd, bsize); // Reconstruction if (!mbmi->skip) { int eobtotal = 0; @@ -1213,10 +969,8 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, assert(max_unit_bsize == get_plane_block_size(BLOCK_64X64, xd->plane[0].subsampling_x, xd->plane[0].subsampling_y)); - int mu_blocks_wide = - block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = - block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(max_blocks_wide, mu_blocks_wide); mu_blocks_high = AOMMIN(max_blocks_high, mu_blocks_high); @@ -1224,15 +978,12 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, for (row = 0; row < max_blocks_high; row += mu_blocks_high) { for (col = 0; col < max_blocks_wide; col += mu_blocks_wide) { for (int plane = 0; plane < num_planes; ++plane) { + if (plane && !xd->is_chroma_ref) break; const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) - continue; - const BLOCK_SIZE bsizec = - scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); - const BLOCK_SIZE plane_bsize = get_plane_block_size( - bsizec, pd->subsampling_x, pd->subsampling_y); - + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(bsize, ss_x, ss_y); const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, plane); const int bh_var_tx = tx_size_high_unit[max_tx_size]; @@ -1242,15 +993,13 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; int blk_row, blk_col; const int unit_height = ROUND_POWER_OF_TWO( - AOMMIN(mu_blocks_high + row, max_blocks_high), - pd->subsampling_y); + AOMMIN(mu_blocks_high + row, max_blocks_high), ss_y); const int unit_width = ROUND_POWER_OF_TWO( - AOMMIN(mu_blocks_wide + col, max_blocks_wide), - pd->subsampling_x); + AOMMIN(mu_blocks_wide + col, max_blocks_wide), ss_x); - for (blk_row = row >> pd->subsampling_y; blk_row < unit_height; + for (blk_row = row >> ss_y; blk_row < unit_height; blk_row += bh_var_tx) { - for (blk_col = col >> pd->subsampling_x; blk_col < unit_width; + for (blk_col = col >> ss_x; blk_col < unit_width; blk_col += bw_var_tx) { decode_reconstruct_tx(cm, td, r, mbmi, plane, plane_bsize, blk_row, blk_col, block, max_tx_size, @@ -1265,8 +1014,7 @@ static AOM_INLINE void decode_token_recon_block(AV1Decoder *const pbi, td->cfl_store_inter_block_visit(cm, xd); } - av1_visit_palette(pbi, xd, mi_row, mi_col, r, bsize, - set_color_index_map_offset); + av1_visit_palette(pbi, xd, r, set_color_index_map_offset); } static AOM_INLINE void set_inter_tx_size(MB_MODE_INFO *mbmi, int stride_log2, @@ -1375,7 +1123,8 @@ static AOM_INLINE void read_tx_size_vartx(MACROBLOCKD *xd, MB_MODE_INFO *mbmi, } } -static TX_SIZE read_selected_tx_size(MACROBLOCKD *xd, aom_reader *r) { +static TX_SIZE read_selected_tx_size(const MACROBLOCKD *const xd, + aom_reader *r) { // TODO(debargha): Clean up the logic here. This function should only // be called for intra. const BLOCK_SIZE bsize = xd->mi[0]->sb_type; @@ -1390,9 +1139,9 @@ static TX_SIZE read_selected_tx_size(MACROBLOCKD *xd, aom_reader *r) { return tx_size; } -static TX_SIZE read_tx_size(AV1_COMMON *cm, MACROBLOCKD *xd, int is_inter, - int allow_select_inter, aom_reader *r) { - const TX_MODE tx_mode = cm->tx_mode; +static TX_SIZE read_tx_size(const MACROBLOCKD *const xd, TX_MODE tx_mode, + int is_inter, int allow_select_inter, + aom_reader *r) { const BLOCK_SIZE bsize = xd->mi[0]->sb_type; if (xd->lossless[xd->mi[0]->segment_id]) return TX_4X4; @@ -1417,20 +1166,19 @@ static AOM_INLINE void parse_decode_block(AV1Decoder *const pbi, MACROBLOCKD *const xd = &td->xd; decode_mbmi_block(pbi, xd, mi_row, mi_col, r, partition, bsize); - av1_visit_palette(pbi, xd, mi_row, mi_col, r, bsize, - av1_decode_palette_tokens); + av1_visit_palette(pbi, xd, r, av1_decode_palette_tokens); AV1_COMMON *cm = &pbi->common; const int num_planes = av1_num_planes(cm); MB_MODE_INFO *mbmi = xd->mi[0]; int inter_block_tx = is_inter_block(mbmi) || is_intrabc_block(mbmi); - if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) && + if (cm->features.tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) && !mbmi->skip && inter_block_tx && !xd->lossless[mbmi->segment_id]) { const TX_SIZE max_tx_size = max_txsize_rect_lookup[bsize]; const int bh = tx_size_high_unit[max_tx_size]; const int bw = tx_size_wide_unit[max_tx_size]; - const int width = block_size_wide[bsize] >> tx_size_wide_log2[0]; - const int height = block_size_high[bsize] >> tx_size_high_log2[0]; + const int width = mi_size_wide[bsize]; + const int height = mi_size_high[bsize]; for (int idy = 0; idy < height; idy += bh) for (int idx = 0; idx < width; idx += bw) @@ -1440,10 +1188,11 @@ static AOM_INLINE void parse_decode_block(AV1Decoder *const pbi, #endif idy, idx, r); } else { - mbmi->tx_size = read_tx_size(cm, xd, inter_block_tx, !mbmi->skip, r); + mbmi->tx_size = + read_tx_size(xd, cm->features.tx_mode, inter_block_tx, !mbmi->skip, r); if (inter_block_tx) memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size)); - set_txfm_ctxs(mbmi->tx_size, xd->n4_w, xd->n4_h, + set_txfm_ctxs(mbmi->tx_size, xd->width, xd->height, mbmi->skip && is_inter_block(mbmi), xd); #if CONFIG_LPF_MASK const int w = mi_size_wide[bsize]; @@ -1479,12 +1228,14 @@ static AOM_INLINE void parse_decode_block(AV1Decoder *const pbi, for (int i = 0; i < MAX_SEGMENTS; i++) { const int current_qindex = av1_get_qindex(&cm->seg, i, xd->current_qindex); + const CommonQuantParams *const quant_params = &cm->quant_params; for (int j = 0; j < num_planes; ++j) { - const int dc_delta_q = - j == 0 ? cm->y_dc_delta_q - : (j == 1 ? cm->u_dc_delta_q : cm->v_dc_delta_q); - const int ac_delta_q = - j == 0 ? 0 : (j == 1 ? cm->u_ac_delta_q : cm->v_ac_delta_q); + const int dc_delta_q = j == 0 ? quant_params->y_dc_delta_q + : (j == 1 ? quant_params->u_dc_delta_q + : quant_params->v_dc_delta_q); + const int ac_delta_q = j == 0 ? 0 + : (j == 1 ? quant_params->u_ac_delta_q + : quant_params->v_ac_delta_q); xd->plane[j].seg_dequant_QTX[i][0] = av1_dc_quant_QTX( current_qindex, dc_delta_q, cm->seq_params.bit_depth); xd->plane[j].seg_dequant_QTX[i][1] = av1_ac_quant_QTX( @@ -1492,9 +1243,9 @@ static AOM_INLINE void parse_decode_block(AV1Decoder *const pbi, } } } - if (mbmi->skip) av1_reset_skip_context(xd, mi_row, mi_col, bsize, num_planes); + if (mbmi->skip) av1_reset_entropy_context(xd, bsize, num_planes); - decode_token_recon_block(pbi, td, mi_row, mi_col, r, bsize); + decode_token_recon_block(pbi, td, r, bsize); } static AOM_INLINE void set_offsets_for_pred_and_recon(AV1Decoder *const pbi, @@ -1502,25 +1253,26 @@ static AOM_INLINE void set_offsets_for_pred_and_recon(AV1Decoder *const pbi, int mi_row, int mi_col, BLOCK_SIZE bsize) { AV1_COMMON *const cm = &pbi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; MACROBLOCKD *const xd = &td->xd; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; const int num_planes = av1_num_planes(cm); - const int offset = mi_row * cm->mi_stride + mi_col; + const int offset = mi_row * mi_params->mi_stride + mi_col; const TileInfo *const tile = &xd->tile; - xd->mi = cm->mi_grid_base + offset; - xd->tx_type_map = &cm->tx_type_map[mi_row * cm->mi_stride + mi_col]; - xd->tx_type_map_stride = cm->mi_stride; - xd->cfl.mi_row = mi_row; - xd->cfl.mi_col = mi_col; + xd->mi = mi_params->mi_grid_base + offset; + xd->tx_type_map = + &mi_params->tx_type_map[mi_row * mi_params->mi_stride + mi_col]; + xd->tx_type_map_stride = mi_params->mi_stride; set_plane_n4(xd, bw, bh, num_planes); // Distance of Mb to the various image edges. These are specified to 8th pel // as they are always compared to values that are in 1/8th pel units - set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols); + set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, mi_params->mi_rows, + mi_params->mi_cols); av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col, 0, num_planes); @@ -1532,7 +1284,7 @@ static AOM_INLINE void decode_block(AV1Decoder *const pbi, ThreadData *const td, BLOCK_SIZE bsize) { (void)partition; set_offsets_for_pred_and_recon(pbi, td, mi_row, mi_col, bsize); - decode_token_recon_block(pbi, td, mi_row, mi_col, r, bsize); + decode_token_recon_block(pbi, td, r, bsize); } static PARTITION_TYPE read_partition(MACROBLOCKD *xd, int mi_row, int mi_col, @@ -1579,10 +1331,11 @@ static AOM_INLINE void decode_partition(AV1Decoder *const pbi, BLOCK_SIZE subsize; const int quarter_step = bw / 4; BLOCK_SIZE bsize2 = get_partition_subsize(bsize, PARTITION_SPLIT); - const int has_rows = (mi_row + hbs) < cm->mi_rows; - const int has_cols = (mi_col + hbs) < cm->mi_cols; + const int has_rows = (mi_row + hbs) < cm->mi_params.mi_rows; + const int has_cols = (mi_col + hbs) < cm->mi_params.mi_cols; - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= cm->mi_params.mi_rows || mi_col >= cm->mi_params.mi_cols) + return; // parse_decode_flag takes the following values : // 01 - do parse only @@ -1678,14 +1431,14 @@ static AOM_INLINE void decode_partition(AV1Decoder *const pbi, case PARTITION_HORZ_4: for (int i = 0; i < 4; ++i) { int this_mi_row = mi_row + i * quarter_step; - if (i > 0 && this_mi_row >= cm->mi_rows) break; + if (i > 0 && this_mi_row >= cm->mi_params.mi_rows) break; DEC_BLOCK(this_mi_row, mi_col, subsize); } break; case PARTITION_VERT_4: for (int i = 0; i < 4; ++i) { int this_mi_col = mi_col + i * quarter_step; - if (i > 0 && this_mi_col >= cm->mi_cols) break; + if (i > 0 && this_mi_col >= cm->mi_params.mi_cols) break; DEC_BLOCK(mi_row, this_mi_col, subsize); } break; @@ -1730,21 +1483,22 @@ static AOM_INLINE void setup_segmentation(AV1_COMMON *const cm, seg->enabled = aom_rb_read_bit(rb); if (!seg->enabled) { if (cm->cur_frame->seg_map) - memset(cm->cur_frame->seg_map, 0, (cm->mi_rows * cm->mi_cols)); + memset(cm->cur_frame->seg_map, 0, + (cm->mi_params.mi_rows * cm->mi_params.mi_cols)); memset(seg, 0, sizeof(*seg)); segfeatures_copy(&cm->cur_frame->seg, seg); return; } if (cm->seg.enabled && cm->prev_frame && - (cm->mi_rows == cm->prev_frame->mi_rows) && - (cm->mi_cols == cm->prev_frame->mi_cols)) { + (cm->mi_params.mi_rows == cm->prev_frame->mi_rows) && + (cm->mi_params.mi_cols == cm->prev_frame->mi_cols)) { cm->last_frame_seg_map = cm->prev_frame->seg_map; } else { cm->last_frame_seg_map = NULL; } // Read update flags - if (cm->primary_ref_frame == PRIMARY_REF_NONE) { + if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) { // These frames can't use previous frames, so must signal map + features seg->update_map = 1; seg->temporal_update = 0; @@ -1794,9 +1548,9 @@ static AOM_INLINE void setup_segmentation(AV1_COMMON *const cm, static AOM_INLINE void decode_restoration_mode(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int num_planes = av1_num_planes(cm); - if (cm->allow_intrabc) return; + if (cm->features.allow_intrabc) return; int all_none = 1, chroma_none = 1; for (int p = 0; p < num_planes; ++p) { RestorationInfo *rsi = &cm->rst_info[p]; @@ -1953,7 +1707,7 @@ static AOM_INLINE void loop_restoration_read_sb_coeffs( RestorationUnitInfo *rui = &rsi->unit_info[runit_idx]; if (rsi->frame_restoration_type == RESTORE_NONE) return; - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int wiener_win = (plane > 0) ? WIENER_WIN_CHROMA : WIENER_WIN; WienerInfo *wiener_info = xd->wiener_info + plane; @@ -1993,13 +1747,14 @@ static AOM_INLINE void setup_loopfilter(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { const int num_planes = av1_num_planes(cm); struct loopfilter *lf = &cm->lf; - if (cm->allow_intrabc || cm->coded_lossless) { + + if (cm->features.allow_intrabc || cm->features.coded_lossless) { // write default deltas to frame buffer av1_set_default_ref_deltas(cm->cur_frame->ref_deltas); av1_set_default_mode_deltas(cm->cur_frame->mode_deltas); return; } - assert(!cm->coded_lossless); + assert(!cm->features.coded_lossless); if (cm->prev_frame) { // write deltas to frame buffer memcpy(lf->ref_deltas, cm->prev_frame->ref_deltas, REF_FRAMES); @@ -2046,7 +1801,7 @@ static AOM_INLINE void setup_cdef(AV1_COMMON *cm, const int num_planes = av1_num_planes(cm); CdefInfo *const cdef_info = &cm->cdef_info; - if (cm->allow_intrabc) return; + if (cm->features.allow_intrabc) return; cdef_info->cdef_damping = aom_rb_read_literal(rb, 2) + 3; cdef_info->cdef_bits = aom_rb_read_literal(rb, 2); cdef_info->nb_cdef_strengths = 1 << cdef_info->cdef_bits; @@ -2061,42 +1816,42 @@ static INLINE int read_delta_q(struct aom_read_bit_buffer *rb) { return aom_rb_read_bit(rb) ? aom_rb_read_inv_signed_literal(rb, 6) : 0; } -static AOM_INLINE void setup_quantization(AV1_COMMON *const cm, +static AOM_INLINE void setup_quantization(CommonQuantParams *quant_params, + int num_planes, + bool separate_uv_delta_q, struct aom_read_bit_buffer *rb) { - const SequenceHeader *const seq_params = &cm->seq_params; - const int num_planes = av1_num_planes(cm); - cm->base_qindex = aom_rb_read_literal(rb, QINDEX_BITS); - cm->y_dc_delta_q = read_delta_q(rb); + quant_params->base_qindex = aom_rb_read_literal(rb, QINDEX_BITS); + quant_params->y_dc_delta_q = read_delta_q(rb); if (num_planes > 1) { int diff_uv_delta = 0; - if (seq_params->separate_uv_delta_q) diff_uv_delta = aom_rb_read_bit(rb); - cm->u_dc_delta_q = read_delta_q(rb); - cm->u_ac_delta_q = read_delta_q(rb); + if (separate_uv_delta_q) diff_uv_delta = aom_rb_read_bit(rb); + quant_params->u_dc_delta_q = read_delta_q(rb); + quant_params->u_ac_delta_q = read_delta_q(rb); if (diff_uv_delta) { - cm->v_dc_delta_q = read_delta_q(rb); - cm->v_ac_delta_q = read_delta_q(rb); + quant_params->v_dc_delta_q = read_delta_q(rb); + quant_params->v_ac_delta_q = read_delta_q(rb); } else { - cm->v_dc_delta_q = cm->u_dc_delta_q; - cm->v_ac_delta_q = cm->u_ac_delta_q; + quant_params->v_dc_delta_q = quant_params->u_dc_delta_q; + quant_params->v_ac_delta_q = quant_params->u_ac_delta_q; } } else { - cm->u_dc_delta_q = 0; - cm->u_ac_delta_q = 0; - cm->v_dc_delta_q = 0; - cm->v_ac_delta_q = 0; + quant_params->u_dc_delta_q = 0; + quant_params->u_ac_delta_q = 0; + quant_params->v_dc_delta_q = 0; + quant_params->v_ac_delta_q = 0; } - cm->using_qmatrix = aom_rb_read_bit(rb); - if (cm->using_qmatrix) { - cm->qm_y = aom_rb_read_literal(rb, QM_LEVEL_BITS); - cm->qm_u = aom_rb_read_literal(rb, QM_LEVEL_BITS); - if (!seq_params->separate_uv_delta_q) - cm->qm_v = cm->qm_u; + quant_params->using_qmatrix = aom_rb_read_bit(rb); + if (quant_params->using_qmatrix) { + quant_params->qmatrix_level_y = aom_rb_read_literal(rb, QM_LEVEL_BITS); + quant_params->qmatrix_level_u = aom_rb_read_literal(rb, QM_LEVEL_BITS); + if (!separate_uv_delta_q) + quant_params->qmatrix_level_v = quant_params->qmatrix_level_u; else - cm->qm_v = aom_rb_read_literal(rb, QM_LEVEL_BITS); + quant_params->qmatrix_level_v = aom_rb_read_literal(rb, QM_LEVEL_BITS); } else { - cm->qm_y = 0; - cm->qm_u = 0; - cm->qm_v = 0; + quant_params->qmatrix_level_y = 0; + quant_params->qmatrix_level_u = 0; + quant_params->qmatrix_level_v = 0; } } @@ -2104,37 +1859,43 @@ static AOM_INLINE void setup_quantization(AV1_COMMON *const cm, static AOM_INLINE void setup_segmentation_dequant(AV1_COMMON *const cm, MACROBLOCKD *const xd) { const int bit_depth = cm->seq_params.bit_depth; - const int using_qm = cm->using_qmatrix; // When segmentation is disabled, only the first value is used. The // remaining are don't cares. const int max_segments = cm->seg.enabled ? MAX_SEGMENTS : 1; + CommonQuantParams *const quant_params = &cm->quant_params; for (int i = 0; i < max_segments; ++i) { const int qindex = xd->qindex[i]; - cm->y_dequant_QTX[i][0] = - av1_dc_quant_QTX(qindex, cm->y_dc_delta_q, bit_depth); - cm->y_dequant_QTX[i][1] = av1_ac_quant_QTX(qindex, 0, bit_depth); - cm->u_dequant_QTX[i][0] = - av1_dc_quant_QTX(qindex, cm->u_dc_delta_q, bit_depth); - cm->u_dequant_QTX[i][1] = - av1_ac_quant_QTX(qindex, cm->u_ac_delta_q, bit_depth); - cm->v_dequant_QTX[i][0] = - av1_dc_quant_QTX(qindex, cm->v_dc_delta_q, bit_depth); - cm->v_dequant_QTX[i][1] = - av1_ac_quant_QTX(qindex, cm->v_ac_delta_q, bit_depth); - const int lossless = xd->lossless[i]; + quant_params->y_dequant_QTX[i][0] = + av1_dc_quant_QTX(qindex, quant_params->y_dc_delta_q, bit_depth); + quant_params->y_dequant_QTX[i][1] = av1_ac_quant_QTX(qindex, 0, bit_depth); + quant_params->u_dequant_QTX[i][0] = + av1_dc_quant_QTX(qindex, quant_params->u_dc_delta_q, bit_depth); + quant_params->u_dequant_QTX[i][1] = + av1_ac_quant_QTX(qindex, quant_params->u_ac_delta_q, bit_depth); + quant_params->v_dequant_QTX[i][0] = + av1_dc_quant_QTX(qindex, quant_params->v_dc_delta_q, bit_depth); + quant_params->v_dequant_QTX[i][1] = + av1_ac_quant_QTX(qindex, quant_params->v_ac_delta_q, bit_depth); + const int use_qmatrix = av1_use_qmatrix(quant_params, xd, i); // NB: depends on base index so there is only 1 set per frame // No quant weighting when lossless or signalled not using QM - int qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_y; + const int qmlevel_y = + use_qmatrix ? quant_params->qmatrix_level_y : NUM_QM_LEVELS - 1; for (int j = 0; j < TX_SIZES_ALL; ++j) { - cm->y_iqmatrix[i][j] = av1_iqmatrix(cm, qmlevel, AOM_PLANE_Y, j); + quant_params->y_iqmatrix[i][j] = + av1_iqmatrix(quant_params, qmlevel_y, AOM_PLANE_Y, j); } - qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_u; + const int qmlevel_u = + use_qmatrix ? quant_params->qmatrix_level_u : NUM_QM_LEVELS - 1; for (int j = 0; j < TX_SIZES_ALL; ++j) { - cm->u_iqmatrix[i][j] = av1_iqmatrix(cm, qmlevel, AOM_PLANE_U, j); + quant_params->u_iqmatrix[i][j] = + av1_iqmatrix(quant_params, qmlevel_u, AOM_PLANE_U, j); } - qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_v; + const int qmlevel_v = + use_qmatrix ? quant_params->qmatrix_level_v : NUM_QM_LEVELS - 1; for (int j = 0; j < TX_SIZES_ALL; ++j) { - cm->v_iqmatrix[i][j] = av1_iqmatrix(cm, qmlevel, AOM_PLANE_V, j); + quant_params->v_iqmatrix[i][j] = + av1_iqmatrix(quant_params, qmlevel_v, AOM_PLANE_V, j); } } } @@ -2192,7 +1953,8 @@ static AOM_INLINE void resize_context_buffers(AV1_COMMON *cm, int width, // Allocations in av1_alloc_context_buffers() depend on individual // dimensions as well as the overall size. - if (new_mi_cols > cm->mi_cols || new_mi_rows > cm->mi_rows) { + if (new_mi_cols > cm->mi_params.mi_cols || + new_mi_rows > cm->mi_params.mi_rows) { if (av1_alloc_context_buffers(cm, width, height)) { // The cm->mi_* values have been cleared and any existing context // buffers have been freed. Clear cm->width and cm->height to be @@ -2203,9 +1965,9 @@ static AOM_INLINE void resize_context_buffers(AV1_COMMON *cm, int width, "Failed to allocate context buffers"); } } else { - cm->set_mb_mi(cm, width, height); + cm->mi_params.set_mb_mi(&cm->mi_params, width, height); } - av1_init_context_buffers(cm); + av1_init_mi_buffers(&cm->mi_params); cm->width = width; cm->height = height; } @@ -2223,7 +1985,7 @@ static AOM_INLINE void setup_buffer_pool(AV1_COMMON *cm) { if (aom_realloc_frame_buffer( &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_DEC_BORDER_IN_PIXELS, cm->byte_alignment, + AOM_DEC_BORDER_IN_PIXELS, cm->features.byte_alignment, &cm->cur_frame->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv)) { unlock_buffer_pool(pool); aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, @@ -2365,66 +2127,71 @@ static int rb_read_uniform(struct aom_read_bit_buffer *const rb, int n) { static AOM_INLINE void read_tile_info_max_tile( AV1_COMMON *const cm, struct aom_read_bit_buffer *const rb) { - int width_mi = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2); - int height_mi = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); - int width_sb = width_mi >> cm->seq_params.mib_size_log2; - int height_sb = height_mi >> cm->seq_params.mib_size_log2; + const SequenceHeader *const seq_params = &cm->seq_params; + CommonTileParams *const tiles = &cm->tiles; + int width_mi = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_cols, seq_params->mib_size_log2); + int height_mi = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, seq_params->mib_size_log2); + int width_sb = width_mi >> seq_params->mib_size_log2; + int height_sb = height_mi >> seq_params->mib_size_log2; av1_get_tile_limits(cm); - cm->uniform_tile_spacing_flag = aom_rb_read_bit(rb); + tiles->uniform_spacing = aom_rb_read_bit(rb); // Read tile columns - if (cm->uniform_tile_spacing_flag) { - cm->log2_tile_cols = cm->min_log2_tile_cols; - while (cm->log2_tile_cols < cm->max_log2_tile_cols) { + if (tiles->uniform_spacing) { + tiles->log2_cols = tiles->min_log2_cols; + while (tiles->log2_cols < tiles->max_log2_cols) { if (!aom_rb_read_bit(rb)) { break; } - cm->log2_tile_cols++; + tiles->log2_cols++; } } else { int i; int start_sb; for (i = 0, start_sb = 0; width_sb > 0 && i < MAX_TILE_COLS; i++) { const int size_sb = - 1 + rb_read_uniform(rb, AOMMIN(width_sb, cm->max_tile_width_sb)); - cm->tile_col_start_sb[i] = start_sb; + 1 + rb_read_uniform(rb, AOMMIN(width_sb, tiles->max_width_sb)); + tiles->col_start_sb[i] = start_sb; start_sb += size_sb; width_sb -= size_sb; } - cm->tile_cols = i; - cm->tile_col_start_sb[i] = start_sb + width_sb; + tiles->cols = i; + tiles->col_start_sb[i] = start_sb + width_sb; } - av1_calculate_tile_cols(cm); + av1_calculate_tile_cols(seq_params, cm->mi_params.mi_rows, + cm->mi_params.mi_cols, tiles); // Read tile rows - if (cm->uniform_tile_spacing_flag) { - cm->log2_tile_rows = cm->min_log2_tile_rows; - while (cm->log2_tile_rows < cm->max_log2_tile_rows) { + if (tiles->uniform_spacing) { + tiles->log2_rows = tiles->min_log2_rows; + while (tiles->log2_rows < tiles->max_log2_rows) { if (!aom_rb_read_bit(rb)) { break; } - cm->log2_tile_rows++; + tiles->log2_rows++; } } else { int i; int start_sb; for (i = 0, start_sb = 0; height_sb > 0 && i < MAX_TILE_ROWS; i++) { const int size_sb = - 1 + rb_read_uniform(rb, AOMMIN(height_sb, cm->max_tile_height_sb)); - cm->tile_row_start_sb[i] = start_sb; + 1 + rb_read_uniform(rb, AOMMIN(height_sb, tiles->max_height_sb)); + tiles->row_start_sb[i] = start_sb; start_sb += size_sb; height_sb -= size_sb; } - cm->tile_rows = i; - cm->tile_row_start_sb[i] = start_sb + height_sb; + tiles->rows = i; + tiles->row_start_sb[i] = start_sb + height_sb; } - av1_calculate_tile_rows(cm); + av1_calculate_tile_rows(seq_params, cm->mi_params.mi_rows, tiles); } void av1_set_single_tile_decoding_mode(AV1_COMMON *const cm) { - cm->single_tile_decoding = 0; - if (cm->large_scale_tile) { + cm->tiles.single_tile_decoding = 0; + if (cm->tiles.large_scale) { struct loopfilter *lf = &cm->lf; RestorationInfo *const rst_info = cm->rst_info; const CdefInfo *const cdef_info = &cm->cdef_info; @@ -2438,9 +2205,9 @@ void av1_set_single_tile_decoding_mode(AV1_COMMON *const cm) { rst_info[0].frame_restoration_type == RESTORE_NONE && rst_info[1].frame_restoration_type == RESTORE_NONE && rst_info[2].frame_restoration_type == RESTORE_NONE; - assert(IMPLIES(cm->coded_lossless, no_loopfilter && no_cdef)); - assert(IMPLIES(cm->all_lossless, no_restoration)); - cm->single_tile_decoding = no_loopfilter && no_cdef && no_restoration; + assert(IMPLIES(cm->features.coded_lossless, no_loopfilter && no_cdef)); + assert(IMPLIES(cm->features.all_lossless, no_restoration)); + cm->tiles.single_tile_decoding = no_loopfilter && no_cdef && no_restoration; } } @@ -2450,12 +2217,12 @@ static AOM_INLINE void read_tile_info(AV1Decoder *const pbi, read_tile_info_max_tile(cm, rb); - cm->context_update_tile_id = 0; - if (cm->tile_rows * cm->tile_cols > 1) { + pbi->context_update_tile_id = 0; + if (cm->tiles.rows * cm->tiles.cols > 1) { // tile to use for cdf update - cm->context_update_tile_id = - aom_rb_read_literal(rb, cm->log2_tile_rows + cm->log2_tile_cols); - if (cm->context_update_tile_id >= cm->tile_rows * cm->tile_cols) { + pbi->context_update_tile_id = + aom_rb_read_literal(rb, cm->tiles.log2_rows + cm->tiles.log2_cols); + if (pbi->context_update_tile_id >= cm->tiles.rows * cm->tiles.cols) { aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Invalid context_update_tile_id"); } @@ -2474,7 +2241,7 @@ static AOM_INLINE void read_ext_tile_info( if (mod > 0) aom_rb_read_literal(rb, CHAR_BIT - mod); assert(rb->bit_offset % CHAR_BIT == 0); - if (cm->tile_cols * cm->tile_rows > 1) { + if (cm->tiles.cols * cm->tiles.rows > 1) { // Read the number of bytes used to store tile size pbi->tile_col_size_bytes = aom_rb_read_literal(rb, 2) + 1; pbi->tile_size_bytes = aom_rb_read_literal(rb, 2) + 1; @@ -2542,13 +2309,13 @@ static AOM_INLINE void get_ls_tile_buffer( } // Returns the end of the last tile buffer -// (tile_buffers[cm->tile_rows - 1][cm->tile_cols - 1]). +// (tile_buffers[cm->tiles.rows - 1][cm->tiles.cols - 1]). static const uint8_t *get_ls_tile_buffers( AV1Decoder *pbi, const uint8_t *data, const uint8_t *data_end, TileBufferDec (*const tile_buffers)[MAX_TILE_COLS]) { AV1_COMMON *const cm = &pbi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; const int have_tiles = tile_cols * tile_rows > 1; const uint8_t *raw_data_end; // The end of the last tile buffer @@ -2675,8 +2442,8 @@ static AOM_INLINE void get_tile_buffers( TileBufferDec (*const tile_buffers)[MAX_TILE_COLS], int start_tile, int end_tile) { AV1_COMMON *const cm = &pbi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int tc = 0; for (int r = 0; r < tile_rows; ++r) { @@ -2704,7 +2471,7 @@ static AOM_INLINE void set_cb_buffer(AV1Decoder *pbi, MACROBLOCKD *const xd, int mi_col) { AV1_COMMON *const cm = &pbi->common; int mib_size_log2 = cm->seq_params.mib_size_log2; - int stride = (cm->mi_cols >> mib_size_log2) + 1; + int stride = (cm->mi_params.mi_cols >> mib_size_log2) + 1; int offset = (mi_row >> mib_size_log2) * stride + (mi_col >> mib_size_log2); CB_BUFFER *cb_buffer = cb_buffer_base + offset; @@ -2868,7 +2635,7 @@ static AOM_INLINE void decode_tile_sb_row(AV1Decoder *pbi, ThreadData *const td, AV1_COMMON *const cm = &pbi->common; const int num_planes = av1_num_planes(cm); TileDataDec *const tile_data = - pbi->tile_data + tile_info.tile_row * cm->tile_cols + tile_info.tile_col; + pbi->tile_data + tile_info.tile_row * cm->tiles.cols + tile_info.tile_col; const int sb_cols_in_tile = av1_get_sb_cols_in_tile(cm, tile_info); const int sb_row_in_tile = (mi_row - tile_info.mi_row_start) >> cm->seq_params.mib_size_log2; @@ -2978,8 +2745,9 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, int end_tile) { AV1_COMMON *const cm = &pbi->common; ThreadData *const td = &pbi->td; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + CommonTileParams *const tiles = &cm->tiles; + const int tile_cols = tiles->cols; + const int tile_rows = tiles->rows; const int n_tiles = tile_cols * tile_rows; TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers; const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows); @@ -2996,7 +2764,7 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, uint8_t allow_update_cdf; const uint8_t *raw_data_end = NULL; - if (cm->large_scale_tile) { + if (tiles->large_scale) { tile_rows_start = single_row ? dec_tile_row : 0; tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows; tile_cols_start = single_col ? dec_tile_col : 0; @@ -3017,20 +2785,20 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, // No tiles to decode. if (tile_rows_end <= tile_rows_start || tile_cols_end <= tile_cols_start || // First tile is larger than end_tile. - tile_rows_start * cm->tile_cols + tile_cols_start > end_tile || + tile_rows_start * tiles->cols + tile_cols_start > end_tile || // Last tile is smaller than start_tile. - (tile_rows_end - 1) * cm->tile_cols + tile_cols_end - 1 < start_tile) + (tile_rows_end - 1) * tiles->cols + tile_cols_end - 1 < start_tile) return data; - allow_update_cdf = allow_update_cdf && !cm->disable_cdf_update; + allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update; assert(tile_rows <= MAX_TILE_ROWS); assert(tile_cols <= MAX_TILE_COLS); #if EXT_TILE_DEBUG - if (cm->large_scale_tile && !pbi->ext_tile_debug) + if (tiles->large_scale && !pbi->ext_tile_debug) raw_data_end = get_ls_single_tile_buffer(pbi, data, tile_buffers); - else if (cm->large_scale_tile && pbi->ext_tile_debug) + else if (tiles->large_scale && pbi->ext_tile_debug) raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers); else #endif // EXT_TILE_DEBUG @@ -3062,17 +2830,17 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, for (tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) { const int col = inv_col_order ? tile_cols - 1 - tile_col : tile_col; - TileDataDec *const tile_data = pbi->tile_data + row * cm->tile_cols + col; + TileDataDec *const tile_data = pbi->tile_data + row * tiles->cols + col; const TileBufferDec *const tile_bs_buf = &tile_buffers[row][col]; - if (row * cm->tile_cols + col < start_tile || - row * cm->tile_cols + col > end_tile) + if (row * tiles->cols + col < start_tile || + row * tiles->cols + col > end_tile) continue; td->bit_reader = &tile_data->bit_reader; av1_zero(td->cb_buffer_base.dqcoeff); av1_tile_init(&td->xd.tile, cm, row, col); - td->xd.current_qindex = cm->base_qindex; + td->xd.current_qindex = cm->quant_params.base_qindex; setup_bool_decoder(tile_bs_buf->data, data_end, tile_bs_buf->size, &cm->error, td->bit_reader, allow_update_cdf); #if CONFIG_ACCOUNTING @@ -3085,7 +2853,8 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, } #endif av1_init_macroblockd(cm, &td->xd, NULL); - av1_init_above_context(cm, &td->xd, row); + av1_init_above_context(&cm->above_contexts, av1_num_planes(cm), row, + &td->xd); // Initialise the tile context from the frame context tile_data->tctx = *cm->fc; @@ -3100,7 +2869,7 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data, } } - if (cm->large_scale_tile) { + if (tiles->large_scale) { if (n_tiles == 1) { // Find the end of the single tile buffer return aom_reader_find_end(&pbi->tile_data->bit_reader); @@ -3142,7 +2911,7 @@ static AOM_INLINE void tile_worker_hook_init( td->bit_reader = &tile_data->bit_reader; av1_zero(td->cb_buffer_base.dqcoeff); av1_tile_init(&td->xd.tile, cm, tile_row, tile_col); - td->xd.current_qindex = cm->base_qindex; + td->xd.current_qindex = cm->quant_params.base_qindex; setup_bool_decoder(tile_buffer->data, thread_data->data_end, tile_buffer->size, &thread_data->error_info, td->bit_reader, allow_update_cdf); @@ -3157,7 +2926,8 @@ static AOM_INLINE void tile_worker_hook_init( #endif av1_init_macroblockd(cm, &td->xd, NULL); td->xd.error_info = &thread_data->error_info; - av1_init_above_context(cm, &td->xd, tile_row); + av1_init_above_context(&cm->above_contexts, av1_num_planes(cm), tile_row, + &td->xd); // Initialise the tile context from the frame context tile_data->tctx = *cm->fc; @@ -3187,12 +2957,12 @@ static int tile_worker_hook(void *arg1, void *arg2) { } thread_data->error_info.setjmp = 1; - allow_update_cdf = cm->large_scale_tile ? 0 : 1; - allow_update_cdf = allow_update_cdf && !cm->disable_cdf_update; + allow_update_cdf = cm->tiles.large_scale ? 0 : 1; + allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update; set_decode_func_pointers(td, 0x3); - assert(cm->tile_cols > 0); + assert(cm->tiles.cols > 0); while (!td->xd.corrupted) { TileJobsDec *cur_job_info = get_dec_job_info(&pbi->tile_mt_info); @@ -3282,11 +3052,11 @@ static int get_next_job_info(AV1Decoder *const pbi, ++tile_row_idx) { for (tile_col_idx = tile_cols_start; tile_col_idx < tile_cols_end; ++tile_col_idx) { - if (tile_row_idx * cm->tile_cols + tile_col_idx < start_tile || - tile_row_idx * cm->tile_cols + tile_col_idx > end_tile) + if (tile_row_idx * cm->tiles.cols + tile_col_idx < start_tile || + tile_row_idx * cm->tiles.cols + tile_col_idx > end_tile) continue; - tile_data = pbi->tile_data + tile_row_idx * cm->tile_cols + tile_col_idx; + tile_data = pbi->tile_data + tile_row_idx * cm->tiles.cols + tile_col_idx; dec_row_mt_sync = &tile_data->dec_row_mt_sync; num_threads_working = dec_row_mt_sync->num_threads_working; @@ -3319,7 +3089,7 @@ static int get_next_job_info(AV1Decoder *const pbi, // No job found to process if (tile_row == -1 || tile_col == -1) return 0; - tile_data = pbi->tile_data + tile_row * cm->tile_cols + tile_col; + tile_data = pbi->tile_data + tile_row * cm->tiles.cols + tile_col; tile_info = tile_data->tile_info; dec_row_mt_sync = &tile_data->dec_row_mt_sync; @@ -3432,12 +3202,12 @@ static int row_mt_worker_hook(void *arg1, void *arg2) { } thread_data->error_info.setjmp = 1; - allow_update_cdf = cm->large_scale_tile ? 0 : 1; - allow_update_cdf = allow_update_cdf && !cm->disable_cdf_update; + allow_update_cdf = cm->tiles.large_scale ? 0 : 1; + allow_update_cdf = allow_update_cdf && !cm->features.disable_cdf_update; set_decode_func_pointers(td, 0x1); - assert(cm->tile_cols > 0); + assert(cm->tiles.cols > 0); while (!td->xd.corrupted) { TileJobsDec *cur_job_info = get_dec_job_info(&pbi->tile_mt_info); @@ -3505,7 +3275,7 @@ static int row_mt_worker_hook(void *arg1, void *arg2) { int mi_row = next_job_info.mi_row; TileDataDec *tile_data = - pbi->tile_data + tile_row * cm->tile_cols + tile_col; + pbi->tile_data + tile_row * cm->tiles.cols + tile_col; AV1DecRowMTSync *dec_row_mt_sync = &tile_data->dec_row_mt_sync; TileInfo tile_info = tile_data->tile_info; @@ -3545,11 +3315,11 @@ static AOM_INLINE void enqueue_tile_jobs(AV1Decoder *pbi, AV1_COMMON *cm, for (int row = tile_rows_start; row < tile_rows_end; row++) { for (int col = tile_cols_start; col < tile_cols_end; col++) { - if (row * cm->tile_cols + col < start_tile || - row * cm->tile_cols + col > end_tile) + if (row * cm->tiles.cols + col < start_tile || + row * cm->tiles.cols + col > end_tile) continue; tile_job_queue->tile_buffer = &pbi->tile_buffers[row][col]; - tile_job_queue->tile_data = pbi->tile_data + row * cm->tile_cols + col; + tile_job_queue->tile_data = pbi->tile_data + row * cm->tiles.cols + col; tile_job_queue++; tile_mt_info->jobs_enqueued++; } @@ -3755,8 +3525,9 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, const uint8_t *data_end, int start_tile, int end_tile) { AV1_COMMON *const cm = &pbi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + CommonTileParams *const tiles = &cm->tiles; + const int tile_cols = tiles->cols; + const int tile_rows = tiles->rows; const int n_tiles = tile_cols * tile_rows; TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers; const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows); @@ -3771,7 +3542,7 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, int num_workers; const uint8_t *raw_data_end = NULL; - if (cm->large_scale_tile) { + if (tiles->large_scale) { tile_rows_start = single_row ? dec_tile_row : 0; tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows; tile_cols_start = single_col ? dec_tile_col : 0; @@ -3804,8 +3575,8 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, // get tile size in tile group #if EXT_TILE_DEBUG - if (cm->large_scale_tile) assert(pbi->ext_tile_debug == 1); - if (cm->large_scale_tile) + if (tiles->large_scale) assert(pbi->ext_tile_debug == 1); + if (tiles->large_scale) raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers); else #endif // EXT_TILE_DEBUG @@ -3817,7 +3588,7 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, for (int row = 0; row < tile_rows; row++) { for (int col = 0; col < tile_cols; col++) { - TileDataDec *tile_data = pbi->tile_data + row * cm->tile_cols + col; + TileDataDec *tile_data = pbi->tile_data + row * tiles->cols + col; av1_tile_init(&tile_data->tile_info, cm, row, col); } } @@ -3833,7 +3604,7 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Failed to decode tile data"); - if (cm->large_scale_tile) { + if (tiles->large_scale) { if (n_tiles == 1) { // Find the end of the single tile buffer return aom_reader_find_end(&pbi->tile_data->bit_reader); @@ -3848,8 +3619,8 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data, static AOM_INLINE void dec_alloc_cb_buf(AV1Decoder *pbi) { AV1_COMMON *const cm = &pbi->common; - int size = ((cm->mi_rows >> cm->seq_params.mib_size_log2) + 1) * - ((cm->mi_cols >> cm->seq_params.mib_size_log2) + 1); + int size = ((cm->mi_params.mi_rows >> cm->seq_params.mib_size_log2) + 1) * + ((cm->mi_params.mi_cols >> cm->seq_params.mib_size_log2) + 1); if (pbi->cb_buffer_alloc_size < size) { av1_dec_free_cb_buf(pbi); @@ -3880,12 +3651,12 @@ static AOM_INLINE void row_mt_frame_init(AV1Decoder *pbi, int tile_rows_start, for (int tile_row = tile_rows_start; tile_row < tile_rows_end; ++tile_row) { for (int tile_col = tile_cols_start; tile_col < tile_cols_end; ++tile_col) { - if (tile_row * cm->tile_cols + tile_col < start_tile || - tile_row * cm->tile_cols + tile_col > end_tile) + if (tile_row * cm->tiles.cols + tile_col < start_tile || + tile_row * cm->tiles.cols + tile_col > end_tile) continue; TileDataDec *const tile_data = - pbi->tile_data + tile_row * cm->tile_cols + tile_col; + pbi->tile_data + tile_row * cm->tiles.cols + tile_col; TileInfo tile_info = tile_data->tile_info; tile_data->dec_row_mt_sync.mi_rows_parse_done = 0; @@ -3930,8 +3701,9 @@ static const uint8_t *decode_tiles_row_mt(AV1Decoder *pbi, const uint8_t *data, const uint8_t *data_end, int start_tile, int end_tile) { AV1_COMMON *const cm = &pbi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + CommonTileParams *const tiles = &cm->tiles; + const int tile_cols = tiles->cols; + const int tile_rows = tiles->rows; const int n_tiles = tile_cols * tile_rows; TileBufferDec(*const tile_buffers)[MAX_TILE_COLS] = pbi->tile_buffers; const int dec_tile_row = AOMMIN(pbi->dec_tile_row, tile_rows); @@ -3948,7 +3720,7 @@ static const uint8_t *decode_tiles_row_mt(AV1Decoder *pbi, const uint8_t *data, const uint8_t *raw_data_end = NULL; int max_sb_rows = 0; - if (cm->large_scale_tile) { + if (tiles->large_scale) { tile_rows_start = single_row ? dec_tile_row : 0; tile_rows_end = single_row ? dec_tile_row + 1 : tile_rows; tile_cols_start = single_col ? dec_tile_col : 0; @@ -3983,24 +3755,26 @@ static const uint8_t *decode_tiles_row_mt(AV1Decoder *pbi, const uint8_t *data, // get tile size in tile group #if EXT_TILE_DEBUG - if (cm->large_scale_tile) assert(pbi->ext_tile_debug == 1); - if (cm->large_scale_tile) + if (tiles->large_scale) assert(pbi->ext_tile_debug == 1); + if (tiles->large_scale) raw_data_end = get_ls_tile_buffers(pbi, data, data_end, tile_buffers); else #endif // EXT_TILE_DEBUG get_tile_buffers(pbi, data, data_end, tile_buffers, start_tile, end_tile); if (pbi->tile_data == NULL || n_tiles != pbi->allocated_tiles) { - for (int i = 0; i < pbi->allocated_tiles; i++) { - TileDataDec *const tile_data = pbi->tile_data + i; - av1_dec_row_mt_dealloc(&tile_data->dec_row_mt_sync); + if (pbi->tile_data != NULL) { + for (int i = 0; i < pbi->allocated_tiles; i++) { + TileDataDec *const tile_data = pbi->tile_data + i; + av1_dec_row_mt_dealloc(&tile_data->dec_row_mt_sync); + } } decoder_alloc_tile_data(pbi, n_tiles); } for (int row = 0; row < tile_rows; row++) { for (int col = 0; col < tile_cols; col++) { - TileDataDec *tile_data = pbi->tile_data + row * cm->tile_cols + col; + TileDataDec *tile_data = pbi->tile_data + row * tiles->cols + col; av1_tile_init(&tile_data->tile_info, cm, row, col); max_sb_rows = AOMMAX(max_sb_rows, @@ -4035,7 +3809,7 @@ static const uint8_t *decode_tiles_row_mt(AV1Decoder *pbi, const uint8_t *data, aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Failed to decode tile data"); - if (cm->large_scale_tile) { + if (tiles->large_scale) { if (n_tiles == 1) { // Find the end of the single tile buffer return aom_reader_find_end(&pbi->tile_data->bit_reader); @@ -4333,64 +4107,59 @@ void av1_read_color_config(struct aom_read_bit_buffer *rb, seq_params->separate_uv_delta_q = aom_rb_read_bit(rb); } -void av1_read_timing_info_header(AV1_COMMON *cm, +void av1_read_timing_info_header(aom_timing_info_t *timing_info, + struct aom_internal_error_info *error, struct aom_read_bit_buffer *rb) { - cm->timing_info.num_units_in_display_tick = aom_rb_read_unsigned_literal( - rb, 32); // Number of units in a display tick - cm->timing_info.time_scale = - aom_rb_read_unsigned_literal(rb, 32); // Time scale - if (cm->timing_info.num_units_in_display_tick == 0 || - cm->timing_info.time_scale == 0) { + timing_info->num_units_in_display_tick = + aom_rb_read_unsigned_literal(rb, + 32); // Number of units in a display tick + timing_info->time_scale = aom_rb_read_unsigned_literal(rb, 32); // Time scale + if (timing_info->num_units_in_display_tick == 0 || + timing_info->time_scale == 0) { aom_internal_error( - &cm->error, AOM_CODEC_UNSUP_BITSTREAM, + error, AOM_CODEC_UNSUP_BITSTREAM, "num_units_in_display_tick and time_scale must be greater than 0."); } - cm->timing_info.equal_picture_interval = + timing_info->equal_picture_interval = aom_rb_read_bit(rb); // Equal picture interval bit - if (cm->timing_info.equal_picture_interval) { + if (timing_info->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) { aom_internal_error( - &cm->error, AOM_CODEC_UNSUP_BITSTREAM, + 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; + timing_info->num_ticks_per_picture = num_ticks_per_picture_minus_1 + 1; } } -void av1_read_decoder_model_info(AV1_COMMON *cm, +void av1_read_decoder_model_info(aom_dec_model_info_t *decoder_model_info, struct aom_read_bit_buffer *rb) { - cm->buffer_model.encoder_decoder_buffer_delay_length = + decoder_model_info->encoder_decoder_buffer_delay_length = aom_rb_read_literal(rb, 5) + 1; - cm->buffer_model.num_units_in_decoding_tick = aom_rb_read_unsigned_literal( - rb, 32); // Number of units in a decoding tick - cm->buffer_model.buffer_removal_time_length = aom_rb_read_literal(rb, 5) + 1; - cm->buffer_model.frame_presentation_time_length = + decoder_model_info->num_units_in_decoding_tick = + aom_rb_read_unsigned_literal(rb, + 32); // Number of units in a decoding tick + decoder_model_info->buffer_removal_time_length = + aom_rb_read_literal(rb, 5) + 1; + decoder_model_info->frame_presentation_time_length = aom_rb_read_literal(rb, 5) + 1; } -void av1_read_op_parameters_info(AV1_COMMON *const cm, - struct aom_read_bit_buffer *rb, int op_num) { - // The cm->op_params array has MAX_NUM_OPERATING_POINTS + 1 elements. - if (op_num > MAX_NUM_OPERATING_POINTS) { - aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, - "AV1 does not support %d decoder model operating points", - op_num + 1); - } - - cm->op_params[op_num].decoder_buffer_delay = aom_rb_read_unsigned_literal( - rb, cm->buffer_model.encoder_decoder_buffer_delay_length); - - cm->op_params[op_num].encoder_buffer_delay = aom_rb_read_unsigned_literal( - rb, cm->buffer_model.encoder_decoder_buffer_delay_length); - - cm->op_params[op_num].low_delay_mode_flag = aom_rb_read_bit(rb); +void av1_read_op_parameters_info(aom_dec_model_op_parameters_t *op_params, + int buffer_delay_length, + struct aom_read_bit_buffer *rb) { + op_params->decoder_buffer_delay = + aom_rb_read_unsigned_literal(rb, buffer_delay_length); + op_params->encoder_buffer_delay = + aom_rb_read_unsigned_literal(rb, buffer_delay_length); + op_params->low_delay_mode_flag = aom_rb_read_bit(rb); } static AOM_INLINE void read_temporal_point_info( AV1_COMMON *const cm, struct aom_read_bit_buffer *rb) { cm->frame_presentation_time = aom_rb_read_unsigned_literal( - rb, cm->buffer_model.frame_presentation_time_length); + rb, cm->seq_params.decoder_model_info.frame_presentation_time_length); } void av1_read_sequence_header(AV1_COMMON *cm, struct aom_read_bit_buffer *rb, @@ -4555,8 +4324,9 @@ static AOM_INLINE void read_global_motion(AV1_COMMON *cm, const WarpedMotionParams *ref_params = cm->prev_frame ? &cm->prev_frame->global_motion[frame] : &default_warp_params; - int good_params = read_global_motion_params( - &cm->global_motion[frame], ref_params, rb, cm->allow_high_precision_mv); + int good_params = + read_global_motion_params(&cm->global_motion[frame], ref_params, rb, + cm->features.allow_high_precision_mv); if (!good_params) { #if WARPED_MOTION_DEBUG printf("Warning: unexpected global motion shear params from aomenc\n"); @@ -4573,7 +4343,7 @@ static AOM_INLINE void read_global_motion(AV1_COMMON *cm, cm->height == ref_buf->y_crop_height) { read_global_motion_params(&cm->global_motion[frame], &cm->prev_frame->global_motion[frame], rb, - cm->allow_high_precision_mv); + cm->features.allow_high_precision_mv); } else { cm->global_motion[frame] = default_warp_params; } @@ -4604,12 +4374,13 @@ static AOM_INLINE void reset_ref_frame_map(AV1_COMMON *const cm) { // If the refresh_frame_flags bitmask is set, update reference frame id values // and mark frames as valid for reference. -static AOM_INLINE void update_ref_frame_id(AV1_COMMON *const cm, int frame_id) { +static AOM_INLINE void update_ref_frame_id(AV1Decoder *const pbi) { + AV1_COMMON *const cm = &pbi->common; int refresh_frame_flags = cm->current_frame.refresh_frame_flags; for (int i = 0; i < REF_FRAMES; i++) { if ((refresh_frame_flags >> i) & 1) { - cm->ref_frame_id[i] = frame_id; - cm->valid_for_referencing[i] = 1; + cm->ref_frame_id[i] = cm->current_frame_id; + pbi->valid_for_referencing[i] = 1; } } } @@ -4636,9 +4407,9 @@ static AOM_INLINE void show_existing_frame_reset(AV1Decoder *const pbi, // Note that the displayed frame must be valid for referencing in order to // have been selected. cm->current_frame_id = cm->ref_frame_id[existing_frame_idx]; - update_ref_frame_id(cm, cm->current_frame_id); + update_ref_frame_id(pbi); - cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; + cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; } static INLINE void reset_frame_buffers(AV1_COMMON *cm) { @@ -4668,6 +4439,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, AV1_COMMON *const cm = &pbi->common; const SequenceHeader *const seq_params = &cm->seq_params; CurrentFrame *const current_frame = &cm->current_frame; + FeatureFlags *const features = &cm->features; MACROBLOCKD *const xd = &pbi->mb; BufferPool *const pool = cm->buffer_pool; RefCntBuffer *const frame_bufs = pool->frame_bufs; @@ -4677,8 +4449,6 @@ static int read_uncompressed_header(AV1Decoder *pbi, "No sequence header"); } - cm->last_frame_type = current_frame->frame_type; - if (seq_params->reduced_still_picture_hdr) { cm->show_existing_frame = 0; cm->show_frame = 1; @@ -4689,7 +4459,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, pbi->decoding_first_frame = 1; reset_frame_buffers(cm); } - cm->error_resilient_mode = 1; + features->error_resilient_mode = 1; } else { cm->show_existing_frame = aom_rb_read_bit(rb); pbi->reset_decoder_state = 0; @@ -4708,7 +4478,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, "Buffer does not contain a decoded frame"); } if (seq_params->decoder_model_info_present_flag && - cm->timing_info.equal_picture_interval == 0) { + seq_params->timing_info.equal_picture_interval == 0) { read_temporal_point_info(cm, rb); } if (seq_params->frame_id_numbers_present_flag) { @@ -4717,7 +4487,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, /* Compare display_frame_id with ref_frame_id and check valid for * referencing */ if (display_frame_id != cm->ref_frame_id[existing_frame_idx] || - cm->valid_for_referencing[existing_frame_idx] == 0) + pbi->valid_for_referencing[existing_frame_idx] == 0) aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Reference buffer frame ID mismatch"); } @@ -4786,14 +4556,14 @@ static int read_uncompressed_header(AV1Decoder *pbi, cm->showable_frame = current_frame->frame_type != KEY_FRAME; if (cm->show_frame) { if (seq_params->decoder_model_info_present_flag && - cm->timing_info.equal_picture_interval == 0) + seq_params->timing_info.equal_picture_interval == 0) read_temporal_point_info(cm, rb); } else { // See if this frame can be used as show_existing_frame in future cm->showable_frame = aom_rb_read_bit(rb); } cm->cur_frame->showable_frame = cm->showable_frame; - cm->error_resilient_mode = + features->error_resilient_mode = frame_is_sframe(cm) || (current_frame->frame_type == KEY_FRAME && cm->show_frame) ? 1 @@ -4803,29 +4573,30 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (current_frame->frame_type == KEY_FRAME && cm->show_frame) { /* All frames need to be marked as not valid for referencing */ for (int i = 0; i < REF_FRAMES; i++) { - cm->valid_for_referencing[i] = 0; + pbi->valid_for_referencing[i] = 0; } } - cm->disable_cdf_update = aom_rb_read_bit(rb); + features->disable_cdf_update = aom_rb_read_bit(rb); if (seq_params->force_screen_content_tools == 2) { - cm->allow_screen_content_tools = aom_rb_read_bit(rb); + features->allow_screen_content_tools = aom_rb_read_bit(rb); } else { - cm->allow_screen_content_tools = seq_params->force_screen_content_tools; + features->allow_screen_content_tools = + seq_params->force_screen_content_tools; } - if (cm->allow_screen_content_tools) { + if (features->allow_screen_content_tools) { if (seq_params->force_integer_mv == 2) { - cm->cur_frame_force_integer_mv = aom_rb_read_bit(rb); + features->cur_frame_force_integer_mv = aom_rb_read_bit(rb); } else { - cm->cur_frame_force_integer_mv = seq_params->force_integer_mv; + features->cur_frame_force_integer_mv = seq_params->force_integer_mv; } } else { - cm->cur_frame_force_integer_mv = 0; + features->cur_frame_force_integer_mv = 0; } int frame_size_override_flag = 0; - cm->allow_intrabc = 0; - cm->primary_ref_frame = PRIMARY_REF_NONE; + features->allow_intrabc = 0; + features->primary_ref_frame = PRIMARY_REF_NONE; if (!seq_params->reduced_still_picture_hdr) { if (seq_params->frame_id_numbers_present_flag) { @@ -4860,12 +4631,12 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (cm->current_frame_id - (1 << diff_len) > 0) { if (cm->ref_frame_id[i] > cm->current_frame_id || cm->ref_frame_id[i] < cm->current_frame_id - (1 << diff_len)) - cm->valid_for_referencing[i] = 0; + pbi->valid_for_referencing[i] = 0; } else { if (cm->ref_frame_id[i] > cm->current_frame_id && cm->ref_frame_id[i] < (1 << frame_id_length) + cm->current_frame_id - (1 << diff_len)) - cm->valid_for_referencing[i] = 0; + pbi->valid_for_referencing[i] = 0; } } } @@ -4876,8 +4647,8 @@ static int read_uncompressed_header(AV1Decoder *pbi, rb, seq_params->order_hint_info.order_hint_bits_minus_1 + 1); current_frame->frame_number = current_frame->order_hint; - if (!cm->error_resilient_mode && !frame_is_intra_only(cm)) { - cm->primary_ref_frame = aom_rb_read_literal(rb, PRIMARY_REF_BITS); + if (!features->error_resilient_mode && !frame_is_intra_only(cm)) { + features->primary_ref_frame = aom_rb_read_literal(rb, PRIMARY_REF_BITS); } } @@ -4886,7 +4657,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (cm->buffer_removal_time_present) { for (int op_num = 0; op_num < seq_params->operating_points_cnt_minus_1 + 1; op_num++) { - if (cm->op_params[op_num].decoder_model_param_present_flag) { + if (seq_params->op_params[op_num].decoder_model_param_present_flag) { if ((((seq_params->operating_point_idc[op_num] >> cm->temporal_layer_id) & 0x1) && @@ -4894,14 +4665,13 @@ static int read_uncompressed_header(AV1Decoder *pbi, (cm->spatial_layer_id + 8)) & 0x1)) || seq_params->operating_point_idc[op_num] == 0) { - cm->op_frame_timing[op_num].buffer_removal_time = - aom_rb_read_unsigned_literal( - rb, cm->buffer_model.buffer_removal_time_length); + cm->buffer_removal_times[op_num] = aom_rb_read_unsigned_literal( + rb, seq_params->decoder_model_info.buffer_removal_time_length); } else { - cm->op_frame_timing[op_num].buffer_removal_time = 0; + cm->buffer_removal_times[op_num] = 0; } } else { - cm->op_frame_timing[op_num].buffer_removal_time = 0; + cm->buffer_removal_times[op_num] = 0; } } } @@ -4939,7 +4709,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (!frame_is_intra_only(cm) || current_frame->refresh_frame_flags != 0xFF) { // Read all ref frame order hints if error_resilient_mode == 1 - if (cm->error_resilient_mode && + if (features->error_resilient_mode && seq_params->order_hint_info.enable_order_hint) { for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) { // Read order hint from bit stream @@ -4956,8 +4726,6 @@ static int read_uncompressed_header(AV1Decoder *pbi, } // If no corresponding buffer exists, allocate a new buffer with all // pixels set to neutral grey. - // TODO(https://crbug.com/aomedia/2420): The spec seems to say we - // just need to set cm->valid_for_referencing[ref_idx] to 0. int buf_idx = get_free_fb(cm); if (buf_idx == INVALID_IDX) { aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, @@ -4969,7 +4737,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, &buf->buf, seq_params->max_frame_width, seq_params->max_frame_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_BORDER_IN_PIXELS, cm->byte_alignment, + AOM_BORDER_IN_PIXELS, features->byte_alignment, &buf->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv)) { decrease_ref_count(buf, pool); unlock_buffer_pool(pool); @@ -4977,8 +4745,23 @@ static int read_uncompressed_header(AV1Decoder *pbi, "Failed to allocate frame buffer"); } unlock_buffer_pool(pool); - set_planes_to_neutral_grey(seq_params, &buf->buf, 0); + // According to the specification, valid bitstreams are required to + // never use missing reference frames so the filling process for + // missing frames is not normatively defined and RefValid for missing + // frames is set to 0. + // To make libaom more robust when the bitstream has been corrupted + // by the loss of some frames of data, this code adds a neutral grey + // buffer in place of missing frames, i.e. + // + set_planes_to_neutral_grey(seq_params, &buf->buf, 0); + // + // and allows the frames to be used for referencing, i.e. + // + pbi->valid_for_referencing[ref_idx] = 1; + // + // Please note such behavior is not normative and other decoders may + // use a different approach. cm->ref_frame_map[ref_idx] = buf; buf->order_hint = order_hint; } @@ -4989,19 +4772,19 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (current_frame->frame_type == KEY_FRAME) { setup_frame_size(cm, frame_size_override_flag, rb); - if (cm->allow_screen_content_tools && !av1_superres_scaled(cm)) - cm->allow_intrabc = aom_rb_read_bit(rb); - cm->allow_ref_frame_mvs = 0; + if (features->allow_screen_content_tools && !av1_superres_scaled(cm)) + features->allow_intrabc = aom_rb_read_bit(rb); + features->allow_ref_frame_mvs = 0; cm->prev_frame = NULL; } else { - cm->allow_ref_frame_mvs = 0; + features->allow_ref_frame_mvs = 0; if (current_frame->frame_type == INTRA_ONLY_FRAME) { cm->cur_frame->film_grain_params_present = seq_params->film_grain_params_present; setup_frame_size(cm, frame_size_override_flag, rb); - if (cm->allow_screen_content_tools && !av1_superres_scaled(cm)) - cm->allow_intrabc = aom_rb_read_bit(rb); + if (features->allow_screen_content_tools && !av1_superres_scaled(cm)) + features->allow_intrabc = aom_rb_read_bit(rb); } else if (pbi->need_resync != 1) { /* Skip if need resync */ int frame_refs_short_signaling = 0; @@ -5053,7 +4836,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, ref = cm->remapped_ref_idx[i]; } // Check valid for referencing - if (cm->valid_for_referencing[ref] == 0) + if (pbi->valid_for_referencing[ref] == 0) aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Reference frame not valid for referencing"); @@ -5075,23 +4858,23 @@ static int read_uncompressed_header(AV1Decoder *pbi, } } - if (!cm->error_resilient_mode && frame_size_override_flag) { + if (!features->error_resilient_mode && frame_size_override_flag) { setup_frame_size_with_refs(cm, rb); } else { setup_frame_size(cm, frame_size_override_flag, rb); } - if (cm->cur_frame_force_integer_mv) { - cm->allow_high_precision_mv = 0; + if (features->cur_frame_force_integer_mv) { + features->allow_high_precision_mv = 0; } else { - cm->allow_high_precision_mv = aom_rb_read_bit(rb); + features->allow_high_precision_mv = aom_rb_read_bit(rb); } - cm->interp_filter = read_frame_interp_filter(rb); - cm->switchable_motion_mode = aom_rb_read_bit(rb); + features->interp_filter = read_frame_interp_filter(rb); + features->switchable_motion_mode = aom_rb_read_bit(rb); } cm->prev_frame = get_primary_ref_frame_buf(cm); - if (cm->primary_ref_frame != PRIMARY_REF_NONE && + if (features->primary_ref_frame != PRIMARY_REF_NONE && get_primary_ref_frame_buf(cm) == NULL) { aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Reference frame containing this frame's initial " @@ -5101,9 +4884,9 @@ static int read_uncompressed_header(AV1Decoder *pbi, if (!(current_frame->frame_type == INTRA_ONLY_FRAME) && pbi->need_resync != 1) { if (frame_might_allow_ref_frame_mvs(cm)) - cm->allow_ref_frame_mvs = aom_rb_read_bit(rb); + features->allow_ref_frame_mvs = aom_rb_read_bit(rb); else - cm->allow_ref_frame_mvs = 0; + features->allow_ref_frame_mvs = 0; for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { const RefCntBuffer *const ref_buf = get_ref_frame_buf(cm, i); @@ -5125,16 +4908,16 @@ static int read_uncompressed_header(AV1Decoder *pbi, cm->cur_frame->frame_type = current_frame->frame_type; - update_ref_frame_id(cm, cm->current_frame_id); + update_ref_frame_id(pbi); - const int might_bwd_adapt = - !(seq_params->reduced_still_picture_hdr) && !(cm->disable_cdf_update); + const int might_bwd_adapt = !(seq_params->reduced_still_picture_hdr) && + !(features->disable_cdf_update); if (might_bwd_adapt) { - cm->refresh_frame_context = aom_rb_read_bit(rb) - ? REFRESH_FRAME_CONTEXT_DISABLED - : REFRESH_FRAME_CONTEXT_BACKWARD; + features->refresh_frame_context = aom_rb_read_bit(rb) + ? REFRESH_FRAME_CONTEXT_DISABLED + : REFRESH_FRAME_CONTEXT_BACKWARD; } else { - cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; + features->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; } cm->cur_frame->buf.bit_depth = seq_params->bit_depth; @@ -5155,7 +4938,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, " state"); } - if (cm->allow_intrabc) { + if (features->allow_intrabc) { // Set parameters corresponding to no filtering. struct loopfilter *lf = &cm->lf; lf->filter_level[0] = 0; @@ -5175,19 +4958,25 @@ static int read_uncompressed_header(AV1Decoder *pbi, "Minimum tile width requirement not satisfied"); } - setup_quantization(cm, rb); + CommonQuantParams *const quant_params = &cm->quant_params; + setup_quantization(quant_params, av1_num_planes(cm), + cm->seq_params.separate_uv_delta_q, rb); xd->bd = (int)seq_params->bit_depth; - if (cm->num_allocated_above_context_planes < av1_num_planes(cm) || - cm->num_allocated_above_context_mi_col < cm->mi_cols || - cm->num_allocated_above_contexts < cm->tile_rows) { - av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts); - if (av1_alloc_above_context_buffers(cm, cm->tile_rows)) + CommonContexts *const above_contexts = &cm->above_contexts; + if (above_contexts->num_planes < av1_num_planes(cm) || + above_contexts->num_mi_cols < cm->mi_params.mi_cols || + above_contexts->num_tile_rows < cm->tiles.rows) { + av1_free_above_context_buffers(above_contexts); + if (av1_alloc_above_context_buffers(above_contexts, cm->tiles.rows, + cm->mi_params.mi_cols, + av1_num_planes(cm))) { aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate context buffers"); + } } - if (cm->primary_ref_frame == PRIMARY_REF_NONE) { + if (features->primary_ref_frame == PRIMARY_REF_NONE) { av1_setup_past_independence(cm); } @@ -5198,11 +4987,11 @@ static int read_uncompressed_header(AV1Decoder *pbi, cm->delta_q_info.delta_lf_present_flag = 0; cm->delta_q_info.delta_lf_multi = 0; cm->delta_q_info.delta_q_present_flag = - cm->base_qindex > 0 ? aom_rb_read_bit(rb) : 0; + quant_params->base_qindex > 0 ? aom_rb_read_bit(rb) : 0; if (cm->delta_q_info.delta_q_present_flag) { - xd->current_qindex = cm->base_qindex; + xd->current_qindex = quant_params->base_qindex; cm->delta_q_info.delta_q_res = 1 << aom_rb_read_literal(rb, 2); - if (!cm->allow_intrabc) + if (!features->allow_intrabc) cm->delta_q_info.delta_lf_present_flag = aom_rb_read_bit(rb); if (cm->delta_q_info.delta_lf_present_flag) { cm->delta_q_info.delta_lf_res = 1 << aom_rb_read_literal(rb, 2); @@ -5211,58 +5000,57 @@ static int read_uncompressed_header(AV1Decoder *pbi, } } - xd->cur_frame_force_integer_mv = cm->cur_frame_force_integer_mv; + xd->cur_frame_force_integer_mv = features->cur_frame_force_integer_mv; for (int i = 0; i < MAX_SEGMENTS; ++i) { - const int qindex = av1_get_qindex(&cm->seg, i, cm->base_qindex); - xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 && - cm->u_dc_delta_q == 0 && cm->u_ac_delta_q == 0 && - cm->v_dc_delta_q == 0 && cm->v_ac_delta_q == 0; + const int qindex = av1_get_qindex(&cm->seg, i, quant_params->base_qindex); + xd->lossless[i] = + qindex == 0 && quant_params->y_dc_delta_q == 0 && + quant_params->u_dc_delta_q == 0 && quant_params->u_ac_delta_q == 0 && + quant_params->v_dc_delta_q == 0 && quant_params->v_ac_delta_q == 0; xd->qindex[i] = qindex; } - cm->coded_lossless = is_coded_lossless(cm, xd); - cm->all_lossless = cm->coded_lossless && !av1_superres_scaled(cm); + features->coded_lossless = is_coded_lossless(cm, xd); + features->all_lossless = features->coded_lossless && !av1_superres_scaled(cm); setup_segmentation_dequant(cm, xd); - if (cm->coded_lossless) { + if (features->coded_lossless) { cm->lf.filter_level[0] = 0; cm->lf.filter_level[1] = 0; } - if (cm->coded_lossless || !seq_params->enable_cdef) { + if (features->coded_lossless || !seq_params->enable_cdef) { cm->cdef_info.cdef_bits = 0; cm->cdef_info.cdef_strengths[0] = 0; cm->cdef_info.cdef_uv_strengths[0] = 0; } - if (cm->all_lossless || !seq_params->enable_restoration) { + if (features->all_lossless || !seq_params->enable_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; } setup_loopfilter(cm, rb); - if (!cm->coded_lossless && seq_params->enable_cdef) { + if (!features->coded_lossless && seq_params->enable_cdef) { setup_cdef(cm, rb); } - if (!cm->all_lossless && seq_params->enable_restoration) { + if (!features->all_lossless && seq_params->enable_restoration) { decode_restoration_mode(cm, rb); } - cm->tx_mode = read_tx_mode(cm, rb); + features->tx_mode = read_tx_mode(rb, features->coded_lossless); current_frame->reference_mode = read_frame_reference_mode(cm, rb); - if (current_frame->reference_mode != SINGLE_REFERENCE) - setup_compound_reference_mode(cm); av1_setup_skip_mode_allowed(cm); current_frame->skip_mode_info.skip_mode_flag = current_frame->skip_mode_info.skip_mode_allowed ? aom_rb_read_bit(rb) : 0; if (frame_might_allow_warped_motion(cm)) - cm->allow_warped_motion = aom_rb_read_bit(rb); + features->allow_warped_motion = aom_rb_read_bit(rb); else - cm->allow_warped_motion = 0; + features->allow_warped_motion = 0; - cm->reduced_tx_set_used = aom_rb_read_bit(rb); + features->reduced_tx_set_used = aom_rb_read_bit(rb); - if (cm->allow_ref_frame_mvs && !frame_might_allow_ref_frame_mvs(cm)) { + if (features->allow_ref_frame_mvs && !frame_might_allow_ref_frame_mvs(cm)) { aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, "Frame wrongly requests reference frame MVs"); } @@ -5274,7 +5062,7 @@ static int read_uncompressed_header(AV1Decoder *pbi, read_film_grain(cm, rb); #if EXT_TILE_DEBUG - if (pbi->ext_tile_debug && cm->large_scale_tile) { + if (pbi->ext_tile_debug && cm->tiles.large_scale) { read_ext_tile_info(pbi, rb); av1_set_single_tile_decoding_mode(cm); } @@ -5309,7 +5097,7 @@ static AOM_INLINE void superres_post_decode(AV1Decoder *pbi) { BufferPool *const pool = cm->buffer_pool; if (!av1_superres_scaled(cm)) return; - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); av1_superres_upscale(cm, pool); } @@ -5341,9 +5129,7 @@ uint32_t av1_decode_frame_headers_and_setup(AV1Decoder *pbi, if (trailing_bits_present) av1_check_trailing_bits(pbi, rb); - // If cm->single_tile_decoding = 0, the independent decoding of a single tile - // or a section of a frame is not allowed. - if (!cm->single_tile_decoding && + if (!cm->tiles.single_tile_decoding && (pbi->dec_tile_row >= 0 || pbi->dec_tile_col >= 0)) { pbi->dec_tile_row = -1; pbi->dec_tile_col = -1; @@ -5372,13 +5158,13 @@ uint32_t av1_decode_frame_headers_and_setup(AV1Decoder *pbi, return uncomp_hdr_size; } - cm->setup_mi(cm); + cm->mi_params.setup_mi(&cm->mi_params); av1_setup_motion_field(cm); av1_setup_block_planes(xd, cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, num_planes); - if (cm->primary_ref_frame == PRIMARY_REF_NONE) { + if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) { // use the default frame context values *cm->fc = *cm->default_frame_context; } else { @@ -5414,6 +5200,7 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, const uint8_t **p_data_end, int start_tile, int end_tile, int initialize_flag) { AV1_COMMON *const cm = &pbi->common; + CommonTileParams *const tiles = &cm->tiles; MACROBLOCKD *const xd = &pbi->mb; const int tile_count_tg = end_tile - start_tile + 1; @@ -5423,12 +5210,12 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, av1_loop_filter_frame_init(cm, 0, num_planes); #endif - if (pbi->max_threads > 1 && !(cm->large_scale_tile && !pbi->ext_tile_debug) && + if (pbi->max_threads > 1 && !(tiles->large_scale && !pbi->ext_tile_debug) && pbi->row_mt) *p_data_end = decode_tiles_row_mt(pbi, data, data_end, start_tile, end_tile); else if (pbi->max_threads > 1 && tile_count_tg > 1 && - !(cm->large_scale_tile && !pbi->ext_tile_debug)) + !(tiles->large_scale && !pbi->ext_tile_debug)) *p_data_end = decode_tiles_mt(pbi, data, data_end, start_tile, end_tile); else *p_data_end = decode_tiles(pbi, data, data_end, start_tile, end_tile); @@ -5438,11 +5225,11 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, set_planes_to_neutral_grey(&cm->seq_params, xd->cur_buf, 1); } - if (end_tile != cm->tile_rows * cm->tile_cols - 1) { + if (end_tile != tiles->rows * tiles->cols - 1) { return; } - if (!cm->allow_intrabc && !cm->single_tile_decoding) { + if (!cm->features.allow_intrabc && !tiles->single_tile_decoding) { if (cm->lf.filter_level[0] || cm->lf.filter_level[1]) { if (pbi->num_workers > 1) { av1_loop_filter_frame_mt( @@ -5465,7 +5252,7 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, cm->rst_info[1].frame_restoration_type != RESTORE_NONE || cm->rst_info[2].frame_restoration_type != RESTORE_NONE; const int do_cdef = - !cm->skip_loop_filter && !cm->coded_lossless && + !pbi->skip_loop_filter && !cm->features.coded_lossless && (cm->cdef_info.cdef_bits || cm->cdef_info.cdef_strengths[0] || cm->cdef_info.cdef_uv_strengths[0]); const int do_superres = av1_superres_scaled(cm); @@ -5516,9 +5303,9 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, #endif if (!xd->corrupted) { - if (cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) { - assert(cm->context_update_tile_id < pbi->allocated_tiles); - *cm->fc = pbi->tile_data[cm->context_update_tile_id].tctx; + if (cm->features.refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) { + assert(pbi->context_update_tile_id < pbi->allocated_tiles); + *cm->fc = pbi->tile_data[pbi->context_update_tile_id].tctx; av1_reset_cdf_symbol_counters(cm->fc); } } else { @@ -5533,7 +5320,7 @@ void av1_decode_tg_tiles_and_wrapup(AV1Decoder *pbi, const uint8_t *data, #endif // Non frame parallel update frame context here. - if (!cm->large_scale_tile) { + if (!tiles->large_scale) { cm->cur_frame->frame_context = *cm->fc; } } diff --git a/media/libaom/src/av1/decoder/decodeframe.h b/media/libaom/src/av1/decoder/decodeframe.h index 13b969663b..95b3c9f22c 100644 --- a/media/libaom/src/av1/decoder/decodeframe.h +++ b/media/libaom/src/av1/decoder/decodeframe.h @@ -56,19 +56,21 @@ void av1_read_color_config(struct aom_read_bit_buffer *rb, struct aom_internal_error_info *error_info); // Implements the timing_info() function in the spec. Reports errors by calling -// rb->error_handler(). -void av1_read_timing_info_header(AV1_COMMON *cm, +// rb->error_handler() or aom_internal_error(). +void av1_read_timing_info_header(aom_timing_info_t *timing_info, + struct aom_internal_error_info *error, struct aom_read_bit_buffer *rb); // Implements the decoder_model_info() function in the spec. Reports errors by // calling rb->error_handler(). -void av1_read_decoder_model_info(AV1_COMMON *cm, +void av1_read_decoder_model_info(aom_dec_model_info_t *decoder_model_info, struct aom_read_bit_buffer *rb); // Implements the operating_parameters_info() function in the spec. Reports -// errors by calling rb->error_handler() or aom_internal_error(). -void av1_read_op_parameters_info(AV1_COMMON *const cm, - struct aom_read_bit_buffer *rb, int op_num); +// errors by calling rb->error_handler(). +void av1_read_op_parameters_info(aom_dec_model_op_parameters_t *op_params, + int buffer_delay_length, + struct aom_read_bit_buffer *rb); struct aom_read_bit_buffer *av1_init_read_bit_buffer( struct AV1Decoder *pbi, struct aom_read_bit_buffer *rb, const uint8_t *data, diff --git a/media/libaom/src/av1/decoder/decodemv.c b/media/libaom/src/av1/decoder/decodemv.c index df70f7c530..e97cec42cb 100644 --- a/media/libaom/src/av1/decoder/decodemv.c +++ b/media/libaom/src/av1/decoder/decodemv.c @@ -36,40 +36,57 @@ static PREDICTION_MODE read_intra_mode(aom_reader *r, aom_cdf_prob *cdf) { return (PREDICTION_MODE)aom_read_symbol(r, cdf, INTRA_MODES, ACCT_STR); } -static void read_cdef(AV1_COMMON *cm, aom_reader *r, MACROBLOCKD *const xd, - int mi_col, int mi_row) { - MB_MODE_INFO *const mbmi = xd->mi[0]; - if (cm->coded_lossless) return; - if (cm->allow_intrabc) { +static void read_cdef(AV1_COMMON *cm, aom_reader *r, MACROBLOCKD *const xd) { + const int skip = xd->mi[0]->skip; + if (cm->features.coded_lossless) return; + if (cm->features.allow_intrabc) { assert(cm->cdef_info.cdef_bits == 0); return; } - if (!(mi_col & (cm->seq_params.mib_size - 1)) && - !(mi_row & (cm->seq_params.mib_size - 1))) { // Top left? - xd->cdef_preset[0] = xd->cdef_preset[1] = xd->cdef_preset[2] = - xd->cdef_preset[3] = -1; + // At the start of a superblock, mark that we haven't yet read CDEF strengths + // for any of the CDEF units contained in this superblock. + const int sb_mask = (cm->seq_params.mib_size - 1); + const int mi_row_in_sb = (xd->mi_row & sb_mask); + const int mi_col_in_sb = (xd->mi_col & sb_mask); + if (mi_row_in_sb == 0 && mi_col_in_sb == 0) { + xd->cdef_transmitted[0] = xd->cdef_transmitted[1] = + xd->cdef_transmitted[2] = xd->cdef_transmitted[3] = false; } - // Read CDEF param at the first non-skip coding block - const int mask = (1 << (6 - MI_SIZE_LOG2)); - const int m = ~(mask - 1); - const int index = cm->seq_params.sb_size == BLOCK_128X128 - ? !!(mi_col & mask) + 2 * !!(mi_row & mask) + + // CDEF unit size is 64x64 irrespective of the superblock size. + const int cdef_size = 1 << (6 - MI_SIZE_LOG2); + + // Find index of this CDEF unit in this superblock. + const int index_mask = cdef_size; + const int cdef_unit_row_in_sb = ((xd->mi_row & index_mask) != 0); + const int cdef_unit_col_in_sb = ((xd->mi_col & index_mask) != 0); + const int index = (cm->seq_params.sb_size == BLOCK_128X128) + ? cdef_unit_col_in_sb + 2 * cdef_unit_row_in_sb : 0; - cm->mi_grid_base[(mi_row & m) * cm->mi_stride + (mi_col & m)]->cdef_strength = - xd->cdef_preset[index] = - xd->cdef_preset[index] == -1 && !mbmi->skip - ? aom_read_literal(r, cm->cdef_info.cdef_bits, ACCT_STR) - : xd->cdef_preset[index]; + + // Read CDEF strength from the first non-skip coding block in this CDEF unit. + if (!xd->cdef_transmitted[index] && !skip) { + // CDEF strength for this CDEF unit needs to be read into the MB_MODE_INFO + // of the 1st block in this CDEF unit. + const int first_block_mask = ~(cdef_size - 1); + CommonModeInfoParams *const mi_params = &cm->mi_params; + const int grid_idx = + get_mi_grid_idx(mi_params, xd->mi_row & first_block_mask, + xd->mi_col & first_block_mask); + MB_MODE_INFO *const mbmi = mi_params->mi_grid_base[grid_idx]; + mbmi->cdef_strength = + aom_read_literal(r, cm->cdef_info.cdef_bits, ACCT_STR); + xd->cdef_transmitted[index] = true; + } } static int read_delta_qindex(AV1_COMMON *cm, const MACROBLOCKD *xd, - aom_reader *r, MB_MODE_INFO *const mbmi, - int mi_col, int mi_row) { + aom_reader *r, MB_MODE_INFO *const mbmi) { int sign, abs, reduced_delta_qindex = 0; BLOCK_SIZE bsize = mbmi->sb_type; - const int b_col = mi_col & (cm->seq_params.mib_size - 1); - const int b_row = mi_row & (cm->seq_params.mib_size - 1); + const int b_col = xd->mi_col & (cm->seq_params.mib_size - 1); + const int b_row = xd->mi_row & (cm->seq_params.mib_size - 1); const int read_delta_q_flag = (b_col == 0 && b_row == 0); FRAME_CONTEXT *ec_ctx = xd->tile_ctx; @@ -207,11 +224,11 @@ static void read_drl_idx(FRAME_CONTEXT *ec_ctx, MACROBLOCKD *xd, static MOTION_MODE read_motion_mode(AV1_COMMON *cm, MACROBLOCKD *xd, MB_MODE_INFO *mbmi, aom_reader *r) { - if (cm->switchable_motion_mode == 0) return SIMPLE_TRANSLATION; + if (cm->features.switchable_motion_mode == 0) return SIMPLE_TRANSLATION; if (mbmi->skip_mode) return SIMPLE_TRANSLATION; - const MOTION_MODE last_motion_mode_allowed = - motion_mode_allowed(xd->global_motion, xd, mbmi, cm->allow_warped_motion); + const MOTION_MODE last_motion_mode_allowed = motion_mode_allowed( + xd->global_motion, xd, mbmi, cm->features.allow_warped_motion); int motion_mode; if (last_motion_mode_allowed == SIMPLE_TRANSLATION) return SIMPLE_TRANSLATION; @@ -260,9 +277,9 @@ int av1_neg_deinterleave(int diff, int ref, int max) { } static int read_segment_id(AV1_COMMON *const cm, const MACROBLOCKD *const xd, - int mi_row, int mi_col, aom_reader *r, int skip) { + aom_reader *r, int skip) { int cdf_num; - const int pred = av1_get_spatial_seg_pred(cm, xd, mi_row, mi_col, &cdf_num); + const int pred = av1_get_spatial_seg_pred(cm, xd, &cdf_num); if (skip) return pred; FRAME_CONTEXT *ec_ctx = xd->tile_ctx; @@ -286,8 +303,8 @@ static int dec_get_segment_id(const AV1_COMMON *cm, const uint8_t *segment_ids, for (int y = 0; y < y_mis; y++) for (int x = 0; x < x_mis; x++) - segment_id = - AOMMIN(segment_id, segment_ids[mi_offset + y * cm->mi_cols + x]); + segment_id = AOMMIN( + segment_id, segment_ids[mi_offset + y * cm->mi_params.mi_cols + x]); assert(segment_id >= 0 && segment_id < MAX_SEGMENTS); return segment_id; @@ -299,37 +316,40 @@ static void set_segment_id(AV1_COMMON *cm, int mi_offset, int x_mis, int y_mis, for (int y = 0; y < y_mis; y++) for (int x = 0; x < x_mis; x++) - cm->cur_frame->seg_map[mi_offset + y * cm->mi_cols + x] = segment_id; + cm->cur_frame->seg_map[mi_offset + y * cm->mi_params.mi_cols + x] = + segment_id; } static int read_intra_segment_id(AV1_COMMON *const cm, - const MACROBLOCKD *const xd, int mi_row, - int mi_col, int bsize, aom_reader *r, - int skip) { + const MACROBLOCKD *const xd, int bsize, + aom_reader *r, int skip) { struct segmentation *const seg = &cm->seg; if (!seg->enabled) return 0; // Default for disabled segmentation - assert(seg->update_map && !seg->temporal_update); - const int mi_offset = mi_row * cm->mi_cols + mi_col; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int mi_offset = mi_row * mi_params->mi_cols + mi_col; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; - const int x_mis = AOMMIN(cm->mi_cols - mi_col, bw); - const int y_mis = AOMMIN(cm->mi_rows - mi_row, bh); - const int segment_id = read_segment_id(cm, xd, mi_row, mi_col, r, skip); + const int x_mis = AOMMIN(mi_params->mi_cols - mi_col, bw); + const int y_mis = AOMMIN(mi_params->mi_rows - mi_row, bh); + const int segment_id = read_segment_id(cm, xd, r, skip); set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id); return segment_id; } -static void copy_segment_id(const AV1_COMMON *cm, +static void copy_segment_id(const CommonModeInfoParams *const mi_params, const uint8_t *last_segment_ids, uint8_t *current_segment_ids, int mi_offset, int x_mis, int y_mis) { for (int y = 0; y < y_mis; y++) for (int x = 0; x < x_mis; x++) - current_segment_ids[mi_offset + y * cm->mi_cols + x] = - last_segment_ids ? last_segment_ids[mi_offset + y * cm->mi_cols + x] - : 0; + current_segment_ids[mi_offset + y * mi_params->mi_cols + x] = + last_segment_ids + ? last_segment_ids[mi_offset + y * mi_params->mi_cols + x] + : 0; } static int get_predicted_segment_id(AV1_COMMON *const cm, int mi_offset, @@ -340,22 +360,24 @@ static int get_predicted_segment_id(AV1_COMMON *const cm, int mi_offset, } static int read_inter_segment_id(AV1_COMMON *const cm, MACROBLOCKD *const xd, - int mi_row, int mi_col, int preskip, - aom_reader *r) { + int preskip, aom_reader *r) { struct segmentation *const seg = &cm->seg; + const CommonModeInfoParams *const mi_params = &cm->mi_params; MB_MODE_INFO *const mbmi = xd->mi[0]; - const int mi_offset = mi_row * cm->mi_cols + mi_col; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int mi_offset = mi_row * mi_params->mi_cols + mi_col; const int bw = mi_size_wide[mbmi->sb_type]; const int bh = mi_size_high[mbmi->sb_type]; // TODO(slavarnway): move x_mis, y_mis into xd ????? - const int x_mis = AOMMIN(cm->mi_cols - mi_col, bw); - const int y_mis = AOMMIN(cm->mi_rows - mi_row, bh); + const int x_mis = AOMMIN(mi_params->mi_cols - mi_col, bw); + const int y_mis = AOMMIN(mi_params->mi_rows - mi_row, bh); if (!seg->enabled) return 0; // Default for disabled segmentation if (!seg->update_map) { - copy_segment_id(cm, cm->last_frame_seg_map, cm->cur_frame->seg_map, + copy_segment_id(mi_params, cm->last_frame_seg_map, cm->cur_frame->seg_map, mi_offset, x_mis, y_mis); return get_predicted_segment_id(cm, mi_offset, x_mis, y_mis); } @@ -368,7 +390,7 @@ static int read_inter_segment_id(AV1_COMMON *const cm, MACROBLOCKD *const xd, if (seg->temporal_update) { mbmi->seg_id_predicted = 0; } - segment_id = read_segment_id(cm, xd, mi_row, mi_col, r, 1); + segment_id = read_segment_id(cm, xd, r, 1); set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id); return segment_id; } @@ -383,10 +405,10 @@ static int read_inter_segment_id(AV1_COMMON *const cm, MACROBLOCKD *const xd, if (mbmi->seg_id_predicted) { segment_id = get_predicted_segment_id(cm, mi_offset, x_mis, y_mis); } else { - segment_id = read_segment_id(cm, xd, mi_row, mi_col, r, 0); + segment_id = read_segment_id(cm, xd, r, 0); } } else { - segment_id = read_segment_id(cm, xd, mi_row, mi_col, r, 0); + segment_id = read_segment_id(cm, xd, r, 0); } set_segment_id(cm, mi_offset, x_mis, y_mis, segment_id); return segment_id; @@ -538,11 +560,11 @@ static void read_palette_colors_uv(MACROBLOCKD *const xd, int bit_depth, } static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, - int mi_row, int mi_col, aom_reader *r) { + aom_reader *r) { const int num_planes = av1_num_planes(cm); MB_MODE_INFO *const mbmi = xd->mi[0]; const BLOCK_SIZE bsize = mbmi->sb_type; - assert(av1_allow_palette(cm->allow_screen_content_tools, bsize)); + assert(av1_allow_palette(cm->features.allow_screen_content_tools, bsize)); PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); @@ -559,9 +581,7 @@ static void read_palette_mode_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, read_palette_colors_y(xd, cm->seq_params.bit_depth, pmi, r); } } - if (num_planes > 1 && mbmi->uv_mode == UV_DC_PRED && - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y)) { + if (num_planes > 1 && mbmi->uv_mode == UV_DC_PRED && xd->is_chroma_ref) { const int palette_uv_mode_ctx = (pmi->palette_size[0] > 0); const int modev = aom_read_symbol( r, xd->tile_ctx->palette_uv_mode_cdf[palette_uv_mode_ctx], 2, ACCT_STR); @@ -614,11 +634,12 @@ void av1_read_tx_type(const AV1_COMMON *const cm, MACROBLOCKD *xd, int blk_row, if (qindex == 0) return; const int inter_block = is_inter_block(mbmi); - if (get_ext_tx_types(tx_size, inter_block, cm->reduced_tx_set_used) > 1) { - const TxSetType tx_set_type = - av1_get_ext_tx_set_type(tx_size, inter_block, cm->reduced_tx_set_used); + if (get_ext_tx_types(tx_size, inter_block, cm->features.reduced_tx_set_used) > + 1) { + const TxSetType tx_set_type = av1_get_ext_tx_set_type( + tx_size, inter_block, cm->features.reduced_tx_set_used); const int eset = - get_ext_tx_set(tx_size, inter_block, cm->reduced_tx_set_used); + get_ext_tx_set(tx_size, inter_block, cm->features.reduced_tx_set_used); // eset == 0 should correspond to a set with only DCT_DCT and // there is no need to read the tx_type assert(eset != 0); @@ -664,7 +685,7 @@ static INLINE int assign_dv(AV1_COMMON *cm, MACROBLOCKD *xd, int_mv *mv, } static void read_intrabc_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, - int mi_row, int mi_col, aom_reader *r) { + aom_reader *r) { MB_MODE_INFO *const mbmi = xd->mi[0]; FRAME_CONTEXT *ec_ctx = xd->tile_ctx; mbmi->use_intrabc = aom_read_symbol(r, ec_ctx->intrabc_cdf, 2, ACCT_STR); @@ -680,21 +701,20 @@ static void read_intrabc_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, av1_find_mv_refs(cm, xd, mbmi, INTRA_FRAME, xd->ref_mv_count, xd->ref_mv_stack, xd->weight, ref_mvs, /*global_mvs=*/NULL, - mi_row, mi_col, inter_mode_ctx); + inter_mode_ctx); int_mv nearestmv, nearmv; av1_find_best_ref_mvs(0, ref_mvs[INTRA_FRAME], &nearestmv, &nearmv, 0); int_mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv; if (dv_ref.as_int == 0) - av1_find_ref_dv(&dv_ref, &xd->tile, cm->seq_params.mib_size, mi_row, - mi_col); + av1_find_ref_dv(&dv_ref, &xd->tile, cm->seq_params.mib_size, xd->mi_row); // Ref DV should not have sub-pel. int valid_dv = (dv_ref.as_mv.col & 7) == 0 && (dv_ref.as_mv.row & 7) == 0; dv_ref.as_mv.col = (dv_ref.as_mv.col >> 3) * 8; dv_ref.as_mv.row = (dv_ref.as_mv.row >> 3) * 8; - valid_dv = valid_dv && assign_dv(cm, xd, &mbmi->mv[0], &dv_ref, mi_row, - mi_col, bsize, r); + valid_dv = valid_dv && assign_dv(cm, xd, &mbmi->mv[0], &dv_ref, xd->mi_row, + xd->mi_col, bsize, r); if (!valid_dv) { // Intra bc motion vectors are not valid - signal corrupt frame aom_internal_error(xd->error_info, AOM_CODEC_CORRUPT_FRAME, @@ -706,18 +726,19 @@ static void read_intrabc_info(AV1_COMMON *const cm, MACROBLOCKD *const xd, // If delta q is present, reads delta_q index. // Also reads delta_q loop filter levels, if present. static void read_delta_q_params(AV1_COMMON *const cm, MACROBLOCKD *const xd, - const int mi_row, const int mi_col, aom_reader *r) { DeltaQInfo *const delta_q_info = &cm->delta_q_info; if (delta_q_info->delta_q_present_flag) { MB_MODE_INFO *const mbmi = xd->mi[0]; - xd->current_qindex += read_delta_qindex(cm, xd, r, mbmi, mi_col, mi_row) * - delta_q_info->delta_q_res; + xd->current_qindex += + read_delta_qindex(cm, xd, r, mbmi) * delta_q_info->delta_q_res; /* Normative: Clamp to [1,MAXQ] to not interfere with lossless mode */ xd->current_qindex = clamp(xd->current_qindex, 1, MAXQ); FRAME_CONTEXT *const ec_ctx = xd->tile_ctx; if (delta_q_info->delta_lf_present_flag) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (delta_q_info->delta_lf_multi) { const int frame_lf_count = av1_num_planes(cm) > 1 ? FRAME_LF_COUNT : FRAME_LF_COUNT - 2; @@ -743,8 +764,7 @@ static void read_delta_q_params(AV1_COMMON *const cm, MACROBLOCKD *const xd, } static void read_intra_frame_mode_info(AV1_COMMON *const cm, - MACROBLOCKD *const xd, int mi_row, - int mi_col, aom_reader *r) { + MACROBLOCKD *const xd, aom_reader *r) { MB_MODE_INFO *const mbmi = xd->mi[0]; const MB_MODE_INFO *above_mi = xd->above_mbmi; const MB_MODE_INFO *left_mi = xd->left_mbmi; @@ -754,18 +774,16 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, FRAME_CONTEXT *ec_ctx = xd->tile_ctx; if (seg->segid_preskip) - mbmi->segment_id = - read_intra_segment_id(cm, xd, mi_row, mi_col, bsize, r, 0); + mbmi->segment_id = read_intra_segment_id(cm, xd, bsize, r, 0); mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r); if (!seg->segid_preskip) - mbmi->segment_id = - read_intra_segment_id(cm, xd, mi_row, mi_col, bsize, r, mbmi->skip); + mbmi->segment_id = read_intra_segment_id(cm, xd, bsize, r, mbmi->skip); - read_cdef(cm, r, xd, mi_col, mi_row); + read_cdef(cm, r, xd); - read_delta_q_params(cm, xd, mi_row, mi_col, r); + read_delta_q_params(cm, xd, r); mbmi->current_qindex = xd->current_qindex; @@ -775,12 +793,14 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, mbmi->palette_mode_info.palette_size[1] = 0; mbmi->filter_intra_mode_info.use_filter_intra = 0; - xd->above_txfm_context = cm->above_txfm_context[xd->tile.tile_row] + mi_col; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + xd->above_txfm_context = cm->above_contexts.txfm[xd->tile.tile_row] + mi_col; xd->left_txfm_context = xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); if (av1_allow_intrabc(cm)) { - read_intrabc_info(cm, xd, mi_row, mi_col, r); + read_intrabc_info(cm, xd, r); if (is_intrabc_block(mbmi)) return; } @@ -792,10 +812,7 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, ? read_angle_delta(r, ec_ctx->angle_delta_cdf[mbmi->mode - V_PRED]) : 0; - if (!cm->seq_params.monochrome && - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y)) { - xd->cfl.is_chroma_reference = 1; + if (!cm->seq_params.monochrome && xd->is_chroma_ref) { mbmi->uv_mode = read_intra_mode_uv(ec_ctx, r, is_cfl_allowed(xd), mbmi->mode); if (mbmi->uv_mode == UV_CFL_PRED) { @@ -809,12 +826,11 @@ static void read_intra_frame_mode_info(AV1_COMMON *const cm, } else { // Avoid decoding angle_info if there is is no chroma prediction mbmi->uv_mode = UV_DC_PRED; - xd->cfl.is_chroma_reference = 0; } xd->cfl.store_y = store_cfl_required(cm, xd); - if (av1_allow_palette(cm->allow_screen_content_tools, bsize)) - read_palette_mode_info(cm, xd, mi_row, mi_col, r); + if (av1_allow_palette(cm->features.allow_screen_content_tools, bsize)) + read_palette_mode_info(cm, xd, r); read_filter_intra_mode_info(cm, xd, r); } @@ -965,19 +981,19 @@ static void read_ref_frames(AV1_COMMON *const cm, MACROBLOCKD *const xd, // Decode forward references. if (!bit) { const int bit1 = READ_REF_BIT(comp_ref_p1); - ref_frame[!idx] = cm->comp_fwd_ref[bit1 ? 1 : 0]; + ref_frame[!idx] = bit1 ? LAST2_FRAME : LAST_FRAME; } else { const int bit2 = READ_REF_BIT(comp_ref_p2); - ref_frame[!idx] = cm->comp_fwd_ref[bit2 ? 3 : 2]; + ref_frame[!idx] = bit2 ? GOLDEN_FRAME : LAST3_FRAME; } // Decode backward references. const int bit_bwd = READ_REF_BIT(comp_bwdref_p); if (!bit_bwd) { const int bit1_bwd = READ_REF_BIT(comp_bwdref_p1); - ref_frame[idx] = cm->comp_bwd_ref[bit1_bwd]; + ref_frame[idx] = bit1_bwd ? ALTREF2_FRAME : BWDREF_FRAME; } else { - ref_frame[idx] = cm->comp_bwd_ref[2]; + ref_frame[idx] = ALTREF_FRAME; } } else if (mode == SINGLE_REFERENCE) { const int bit0 = READ_REF_BIT(single_ref_p1); @@ -1007,26 +1023,27 @@ static void read_ref_frames(AV1_COMMON *const cm, MACROBLOCKD *const xd, } } -static INLINE void read_mb_interp_filter(AV1_COMMON *const cm, - MACROBLOCKD *const xd, +static INLINE void read_mb_interp_filter(const MACROBLOCKD *const xd, + InterpFilter interp_filter, + bool enable_dual_filter, MB_MODE_INFO *const mbmi, aom_reader *r) { FRAME_CONTEXT *ec_ctx = xd->tile_ctx; if (!av1_is_interp_needed(xd)) { - set_default_interp_filters(mbmi, cm->interp_filter); + set_default_interp_filters(mbmi, interp_filter); return; } - if (cm->interp_filter != SWITCHABLE) { - mbmi->interp_filters = av1_broadcast_interp_filter(cm->interp_filter); + if (interp_filter != SWITCHABLE) { + mbmi->interp_filters = av1_broadcast_interp_filter(interp_filter); } else { InterpFilter ref0_filter[2] = { EIGHTTAP_REGULAR, EIGHTTAP_REGULAR }; for (int dir = 0; dir < 2; ++dir) { const int ctx = av1_get_pred_context_switchable_interp(xd, dir); ref0_filter[dir] = (InterpFilter)aom_read_symbol( r, ec_ctx->switchable_interp_cdf[ctx], SWITCHABLE_FILTERS, ACCT_STR); - if (cm->seq_params.enable_dual_filter == 0) { + if (!enable_dual_filter) { ref0_filter[1] = ref0_filter[0]; break; } @@ -1037,8 +1054,8 @@ static INLINE void read_mb_interp_filter(AV1_COMMON *const cm, } } -static void read_intra_block_mode_info(AV1_COMMON *const cm, const int mi_row, - const int mi_col, MACROBLOCKD *const xd, +static void read_intra_block_mode_info(AV1_COMMON *const cm, + MACROBLOCKD *const xd, MB_MODE_INFO *const mbmi, aom_reader *r) { const BLOCK_SIZE bsize = mbmi->sb_type; @@ -1055,11 +1072,7 @@ static void read_intra_block_mode_info(AV1_COMMON *const cm, const int mi_row, use_angle_delta && av1_is_directional_mode(mbmi->mode) ? read_angle_delta(r, ec_ctx->angle_delta_cdf[mbmi->mode - V_PRED]) : 0; - const int has_chroma = - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y); - xd->cfl.is_chroma_reference = has_chroma; - if (!cm->seq_params.monochrome && has_chroma) { + if (!cm->seq_params.monochrome && xd->is_chroma_ref) { mbmi->uv_mode = read_intra_mode_uv(ec_ctx, r, is_cfl_allowed(xd), mbmi->mode); if (mbmi->uv_mode == UV_CFL_PRED) { @@ -1079,8 +1092,8 @@ static void read_intra_block_mode_info(AV1_COMMON *const cm, const int mi_row, mbmi->palette_mode_info.palette_size[0] = 0; mbmi->palette_mode_info.palette_size[1] = 0; - if (av1_allow_palette(cm->allow_screen_content_tools, bsize)) - read_palette_mode_info(cm, xd, mi_row, mi_col, r); + if (av1_allow_palette(cm->features.allow_screen_content_tools, bsize)) + read_palette_mode_info(cm, xd, r); read_filter_intra_mode_info(cm, xd, r); } @@ -1094,12 +1107,13 @@ static INLINE int assign_mv(AV1_COMMON *cm, MACROBLOCKD *xd, PREDICTION_MODE mode, MV_REFERENCE_FRAME ref_frame[2], int_mv mv[2], int_mv ref_mv[2], int_mv nearest_mv[2], - int_mv near_mv[2], int mi_row, int mi_col, - int is_compound, int allow_hp, aom_reader *r) { + int_mv near_mv[2], int is_compound, int allow_hp, + aom_reader *r) { FRAME_CONTEXT *ec_ctx = xd->tile_ctx; MB_MODE_INFO *mbmi = xd->mi[0]; BLOCK_SIZE bsize = mbmi->sb_type; - if (cm->cur_frame_force_integer_mv) { + FeatureFlags *const features = &cm->features; + if (features->cur_frame_force_integer_mv) { allow_hp = MV_SUBPEL_NONE; } switch (mode) { @@ -1117,11 +1131,11 @@ static INLINE int assign_mv(AV1_COMMON *cm, MACROBLOCKD *xd, break; } case GLOBALMV: { - mv[0].as_int = - gm_get_motion_vector(&cm->global_motion[ref_frame[0]], - cm->allow_high_precision_mv, bsize, mi_col, - mi_row, cm->cur_frame_force_integer_mv) - .as_int; + mv[0].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[0]], + features->allow_high_precision_mv, + bsize, xd->mi_col, xd->mi_row, + features->cur_frame_force_integer_mv) + .as_int; break; } case NEW_NEWMV: { @@ -1174,16 +1188,16 @@ static INLINE int assign_mv(AV1_COMMON *cm, MACROBLOCKD *xd, } case GLOBAL_GLOBALMV: { assert(is_compound); - mv[0].as_int = - gm_get_motion_vector(&cm->global_motion[ref_frame[0]], - cm->allow_high_precision_mv, bsize, mi_col, - mi_row, cm->cur_frame_force_integer_mv) - .as_int; - mv[1].as_int = - gm_get_motion_vector(&cm->global_motion[ref_frame[1]], - cm->allow_high_precision_mv, bsize, mi_col, - mi_row, cm->cur_frame_force_integer_mv) - .as_int; + mv[0].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[0]], + features->allow_high_precision_mv, + bsize, xd->mi_col, xd->mi_row, + features->cur_frame_force_integer_mv) + .as_int; + mv[1].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[1]], + features->allow_high_precision_mv, + bsize, xd->mi_col, xd->mi_row, + features->cur_frame_force_integer_mv) + .as_int; break; } default: { return 0; } @@ -1248,11 +1262,12 @@ static void dec_dump_logs(AV1_COMMON *cm, MB_MODE_INFO *const mbmi, int mi_row, static void read_inter_block_mode_info(AV1Decoder *const pbi, MACROBLOCKD *const xd, - MB_MODE_INFO *const mbmi, int mi_row, - int mi_col, aom_reader *r) { + MB_MODE_INFO *const mbmi, + aom_reader *r) { AV1_COMMON *const cm = &pbi->common; + FeatureFlags *const features = &cm->features; const BLOCK_SIZE bsize = mbmi->sb_type; - const int allow_hp = cm->allow_high_precision_mv; + const int allow_hp = features->allow_high_precision_mv; int_mv nearestmv[2], nearmv[2]; int_mv ref_mvs[MODE_CTX_REF_FRAMES][MAX_MV_REF_CANDIDATES] = { { { 0 } } }; int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES]; @@ -1270,8 +1285,7 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, const MV_REFERENCE_FRAME ref_frame = av1_ref_frame_type(mbmi->ref_frame); av1_find_mv_refs(cm, xd, mbmi, ref_frame, xd->ref_mv_count, xd->ref_mv_stack, - xd->weight, ref_mvs, /*global_mvs=*/NULL, mi_row, mi_col, - inter_mode_ctx); + xd->weight, ref_mvs, /*global_mvs=*/NULL, inter_mode_ctx); mbmi->ref_mv_idx = 0; @@ -1303,7 +1317,7 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, if (!is_compound && mbmi->mode != GLOBALMV) { av1_find_best_ref_mvs(allow_hp, ref_mvs[mbmi->ref_frame[0]], &nearestmv[0], - &nearmv[0], cm->cur_frame_force_integer_mv); + &nearmv[0], features->cur_frame_force_integer_mv); } if (is_compound && mbmi->mode != GLOBAL_GLOBALMV) { @@ -1313,13 +1327,13 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, nearmv[0] = xd->ref_mv_stack[ref_frame][ref_mv_idx].this_mv; nearmv[1] = xd->ref_mv_stack[ref_frame][ref_mv_idx].comp_mv; lower_mv_precision(&nearestmv[0].as_mv, allow_hp, - cm->cur_frame_force_integer_mv); + features->cur_frame_force_integer_mv); lower_mv_precision(&nearestmv[1].as_mv, allow_hp, - cm->cur_frame_force_integer_mv); + features->cur_frame_force_integer_mv); lower_mv_precision(&nearmv[0].as_mv, allow_hp, - cm->cur_frame_force_integer_mv); + features->cur_frame_force_integer_mv); lower_mv_precision(&nearmv[1].as_mv, allow_hp, - cm->cur_frame_force_integer_mv); + features->cur_frame_force_integer_mv); } else if (mbmi->ref_mv_idx > 0 && mbmi->mode == NEARMV) { nearmv[0] = xd->ref_mv_stack[mbmi->ref_frame[0]][1 + mbmi->ref_mv_idx].this_mv; @@ -1350,9 +1364,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, if (mbmi->skip_mode) assert(mbmi->mode == NEAREST_NEARESTMV); - int mv_corrupted_flag = + const int mv_corrupted_flag = !assign_mv(cm, xd, mbmi->mode, mbmi->ref_frame, mbmi->mv, ref_mv, - nearestmv, nearmv, mi_row, mi_col, is_compound, allow_hp, r); + nearestmv, nearmv, is_compound, allow_hp, r); aom_merge_corrupted_flag(&xd->corrupted, mv_corrupted_flag); mbmi->use_wedge_interintra = 0; @@ -1370,12 +1384,12 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, mbmi->angle_delta[PLANE_TYPE_Y] = 0; mbmi->angle_delta[PLANE_TYPE_UV] = 0; mbmi->filter_intra_mode_info.use_filter_intra = 0; - if (is_interintra_wedge_used(bsize)) { + if (av1_is_wedge_used(bsize)) { mbmi->use_wedge_interintra = aom_read_symbol( r, ec_ctx->wedge_interintra_cdf[bsize], 2, ACCT_STR); if (mbmi->use_wedge_interintra) { mbmi->interintra_wedge_index = (int8_t)aom_read_symbol( - r, ec_ctx->wedge_idx_cdf[bsize], 16, ACCT_STR); + r, ec_ctx->wedge_idx_cdf[bsize], MAX_WEDGE_TYPES, ACCT_STR); } } } @@ -1389,10 +1403,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, mbmi->motion_mode = SIMPLE_TRANSLATION; if (is_motion_variation_allowed_bsize(mbmi->sb_type) && !mbmi->skip_mode && !has_second_ref(mbmi)) { - mbmi->num_proj_ref = - av1_findSamples(cm, xd, mi_row, mi_col, pts, pts_inref); + mbmi->num_proj_ref = av1_findSamples(cm, xd, pts, pts_inref); } - av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); + av1_count_overlappable_neighbors(cm, xd); if (mbmi->ref_frame[1] != INTRA_FRAME) mbmi->motion_mode = read_motion_mode(cm, xd, mbmi, r); @@ -1444,7 +1457,7 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, if (mbmi->interinter_comp.type == COMPOUND_WEDGE) { assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize)); mbmi->interinter_comp.wedge_index = (int8_t)aom_read_symbol( - r, ec_ctx->wedge_idx_cdf[bsize], 16, ACCT_STR); + r, ec_ctx->wedge_idx_cdf[bsize], MAX_WEDGE_TYPES, ACCT_STR); mbmi->interinter_comp.wedge_sign = (int8_t)aom_read_bit(r, ACCT_STR); } else { assert(mbmi->interinter_comp.type == COMPOUND_DIFFWTD); @@ -1454,7 +1467,11 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } } - read_mb_interp_filter(cm, xd, mbmi, r); + read_mb_interp_filter(xd, features->interp_filter, + cm->seq_params.enable_dual_filter, mbmi, r); + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (mbmi->motion_mode == WARPED_CAUSAL) { mbmi->wm_params.wmtype = DEFAULT_WMTYPE; @@ -1475,9 +1492,6 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } } - xd->cfl.is_chroma_reference = - is_chroma_reference(mi_row, mi_col, bsize, cm->seq_params.subsampling_x, - cm->seq_params.subsampling_y); xd->cfl.store_y = store_cfl_required(cm, xd); #if DEC_MISMATCH_DEBUG @@ -1486,15 +1500,14 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } static void read_inter_frame_mode_info(AV1Decoder *const pbi, - MACROBLOCKD *const xd, int mi_row, - int mi_col, aom_reader *r) { + MACROBLOCKD *const xd, aom_reader *r) { AV1_COMMON *const cm = &pbi->common; MB_MODE_INFO *const mbmi = xd->mi[0]; int inter_block = 1; mbmi->mv[0].as_int = 0; mbmi->mv[1].as_int = 0; - mbmi->segment_id = read_inter_segment_id(cm, xd, mi_row, mi_col, 1, r); + mbmi->segment_id = read_inter_segment_id(cm, xd, 1, r); mbmi->skip_mode = read_skip_mode(cm, xd, mbmi->segment_id, r); @@ -1504,30 +1517,31 @@ static void read_inter_frame_mode_info(AV1Decoder *const pbi, mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r); if (!cm->seg.segid_preskip) - mbmi->segment_id = read_inter_segment_id(cm, xd, mi_row, mi_col, 0, r); + mbmi->segment_id = read_inter_segment_id(cm, xd, 0, r); - read_cdef(cm, r, xd, mi_col, mi_row); + read_cdef(cm, r, xd); - read_delta_q_params(cm, xd, mi_row, mi_col, r); + read_delta_q_params(cm, xd, r); if (!mbmi->skip_mode) inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r); mbmi->current_qindex = xd->current_qindex; - xd->above_txfm_context = cm->above_txfm_context[xd->tile.tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[xd->tile.tile_row] + xd->mi_col; xd->left_txfm_context = - xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + xd->left_txfm_context_buffer + (xd->mi_row & MAX_MIB_MASK); if (inter_block) - read_inter_block_mode_info(pbi, xd, mbmi, mi_row, mi_col, r); + read_inter_block_mode_info(pbi, xd, mbmi, r); else - read_intra_block_mode_info(cm, mi_row, mi_col, xd, mbmi, r); + read_intra_block_mode_info(cm, xd, mbmi, r); } static void intra_copy_frame_mvs(AV1_COMMON *const cm, int mi_row, int mi_col, int x_mis, int y_mis) { - const int frame_mvs_stride = ROUND_POWER_OF_TWO(cm->mi_cols, 1); + const int frame_mvs_stride = ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, 1); MV_REF *frame_mvs = cm->cur_frame->mvs + (mi_row >> 1) * frame_mvs_stride + (mi_col >> 1); x_mis = ROUND_POWER_OF_TWO(x_mis, 1); @@ -1543,19 +1557,19 @@ static void intra_copy_frame_mvs(AV1_COMMON *const cm, int mi_row, int mi_col, } } -void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, int mi_row, - int mi_col, aom_reader *r, int x_mis, int y_mis) { +void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, aom_reader *r, + int x_mis, int y_mis) { AV1_COMMON *const cm = &pbi->common; MB_MODE_INFO *const mi = xd->mi[0]; mi->use_intrabc = 0; if (frame_is_intra_only(cm)) { - read_intra_frame_mode_info(cm, xd, mi_row, mi_col, r); + read_intra_frame_mode_info(cm, xd, r); if (pbi->common.seq_params.order_hint_info.enable_ref_frame_mvs) - intra_copy_frame_mvs(cm, mi_row, mi_col, x_mis, y_mis); + intra_copy_frame_mvs(cm, xd->mi_row, xd->mi_col, x_mis, y_mis); } else { - read_inter_frame_mode_info(pbi, xd, mi_row, mi_col, r); + read_inter_frame_mode_info(pbi, xd, r); if (pbi->common.seq_params.order_hint_info.enable_ref_frame_mvs) - av1_copy_frame_mvs(cm, mi, mi_row, mi_col, x_mis, y_mis); + av1_copy_frame_mvs(cm, mi, xd->mi_row, xd->mi_col, x_mis, y_mis); } } diff --git a/media/libaom/src/av1/decoder/decodemv.h b/media/libaom/src/av1/decoder/decodemv.h index 1625e5bd23..289e66ae1e 100644 --- a/media/libaom/src/av1/decoder/decodemv.h +++ b/media/libaom/src/av1/decoder/decodemv.h @@ -20,10 +20,8 @@ extern "C" { #endif -void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, - - int mi_row, int mi_col, aom_reader *r, int x_mis, - int y_mis); +void av1_read_mode_info(AV1Decoder *const pbi, MACROBLOCKD *xd, aom_reader *r, + int x_mis, int y_mis); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/decoder/decoder.c b/media/libaom/src/av1/decoder/decoder.c index 6d765c2b03..fc5f2cd20d 100644 --- a/media/libaom/src/av1/decoder/decoder.c +++ b/media/libaom/src/av1/decoder/decoder.c @@ -26,8 +26,8 @@ #include "aom_util/aom_thread.h" #include "av1/common/alloccommon.h" +#include "av1/common/av1_common_int.h" #include "av1/common/av1_loopfilter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/quant_common.h" #include "av1/common/reconinter.h" #include "av1/common/reconintra.h" @@ -45,7 +45,8 @@ static void initialize_dec(void) { av1_init_wedge_masks(); } -static void dec_set_mb_mi(AV1_COMMON *cm, int width, int height) { +static void dec_set_mb_mi(CommonModeInfoParams *mi_params, int width, + int height) { // Ensure that the decoded width and height are both multiples of // 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if // subsampling is used). @@ -54,62 +55,40 @@ static void dec_set_mb_mi(AV1_COMMON *cm, int width, int height) { const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); const int aligned_height = ALIGN_POWER_OF_TWO(height, 3); - cm->mi_cols = aligned_width >> MI_SIZE_LOG2; - cm->mi_rows = aligned_height >> MI_SIZE_LOG2; - cm->mi_stride = calc_mi_size(cm->mi_cols); + mi_params->mi_cols = aligned_width >> MI_SIZE_LOG2; + mi_params->mi_rows = aligned_height >> MI_SIZE_LOG2; + mi_params->mi_stride = calc_mi_size(mi_params->mi_cols); - cm->mb_cols = (cm->mi_cols + 2) >> 2; - cm->mb_rows = (cm->mi_rows + 2) >> 2; - cm->MBs = cm->mb_rows * cm->mb_cols; + mi_params->mb_cols = (mi_params->mi_cols + 2) >> 2; + mi_params->mb_rows = (mi_params->mi_rows + 2) >> 2; + mi_params->MBs = mi_params->mb_rows * mi_params->mb_cols; - cm->mi_alloc_bsize = BLOCK_4X4; - cm->mi_alloc_rows = cm->mi_rows; - cm->mi_alloc_cols = cm->mi_cols; - cm->mi_alloc_stride = cm->mi_stride; + mi_params->mi_alloc_bsize = BLOCK_4X4; + mi_params->mi_alloc_stride = mi_params->mi_stride; - assert(mi_size_wide[cm->mi_alloc_bsize] == mi_size_high[cm->mi_alloc_bsize]); + assert(mi_size_wide[mi_params->mi_alloc_bsize] == + mi_size_high[mi_params->mi_alloc_bsize]); #if CONFIG_LPF_MASK - av1_alloc_loop_filter_mask(cm); + av1_alloc_loop_filter_mask(mi_params); #endif } -static void dec_setup_mi(AV1_COMMON *cm) { - const int mi_grid_size = cm->mi_stride * calc_mi_size(cm->mi_rows); - memset(cm->mi_grid_base, 0, mi_grid_size * sizeof(*cm->mi_grid_base)); +static void dec_setup_mi(CommonModeInfoParams *mi_params) { + const int mi_grid_size = + mi_params->mi_stride * calc_mi_size(mi_params->mi_rows); + memset(mi_params->mi_grid_base, 0, + mi_grid_size * sizeof(*mi_params->mi_grid_base)); } -static int dec_alloc_mi(AV1_COMMON *cm) { - const int mi_grid_size = cm->mi_stride * calc_mi_size(cm->mi_rows); - - if (cm->mi_alloc_size < mi_grid_size || cm->mi_grid_size < mi_grid_size) { - cm->free_mi(cm); - - cm->mi = aom_calloc(mi_grid_size, sizeof(*cm->mi)); - if (!cm->mi) return 1; - cm->mi_alloc_size = mi_grid_size; - - cm->mi_grid_base = - (MB_MODE_INFO **)aom_calloc(mi_grid_size, sizeof(MB_MODE_INFO *)); - if (!cm->mi_grid_base) return 1; - cm->mi_grid_size = mi_grid_size; - - cm->tx_type_map = aom_calloc(calc_mi_size(cm->mi_rows) * cm->mi_stride, - sizeof(*cm->tx_type_map)); - if (!cm->tx_type_map) return 1; - } - - return 0; -} - -static void dec_free_mi(AV1_COMMON *cm) { - aom_free(cm->mi); - cm->mi = NULL; - aom_free(cm->mi_grid_base); - cm->mi_grid_base = NULL; - cm->mi_alloc_size = 0; - aom_free(cm->tx_type_map); - cm->tx_type_map = NULL; +static void dec_free_mi(CommonModeInfoParams *mi_params) { + aom_free(mi_params->mi_alloc); + mi_params->mi_alloc = NULL; + aom_free(mi_params->mi_grid_base); + mi_params->mi_grid_base = NULL; + mi_params->mi_alloc_size = 0; + aom_free(mi_params->tx_type_map); + mi_params->tx_type_map = NULL; } AV1Decoder *av1_decoder_create(BufferPool *const pool) { @@ -152,14 +131,13 @@ AV1Decoder *av1_decoder_create(BufferPool *const pool) { cm->seq_params.bit_depth = AOM_BITS_8; - cm->alloc_mi = dec_alloc_mi; - cm->free_mi = dec_free_mi; - cm->setup_mi = dec_setup_mi; - cm->set_mb_mi = dec_set_mb_mi; + cm->mi_params.free_mi = dec_free_mi; + cm->mi_params.setup_mi = dec_setup_mi; + cm->mi_params.set_mb_mi = dec_set_mb_mi; av1_loop_filter_init(cm); - av1_qm_init(cm); + av1_qm_init(&cm->quant_params, av1_num_planes(cm)); av1_loop_restoration_precal(); #if CONFIG_ACCOUNTING pbi->acct_enabled = 1; @@ -247,19 +225,16 @@ void av1_decoder_remove(AV1Decoder *pbi) { aom_accounting_clear(&pbi->accounting); #endif av1_free_mc_tmp_buf(&pbi->td); - + aom_img_metadata_array_free(pbi->metadata); aom_free(pbi); } -void av1_visit_palette(AV1Decoder *const pbi, MACROBLOCKD *const xd, int mi_row, - int mi_col, aom_reader *r, BLOCK_SIZE bsize, - palette_visitor_fn_t visit) { +void av1_visit_palette(AV1Decoder *const pbi, MACROBLOCKD *const xd, + aom_reader *r, palette_visitor_fn_t visit) { if (!is_inter_block(xd->mi[0])) { for (int plane = 0; plane < AOMMIN(2, av1_num_planes(&pbi->common)); ++plane) { - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) { + if (plane == 0 || xd->is_chroma_ref) { if (xd->mi[0]->palette_mode_info.palette_size[plane]) visit(xd, plane, r); } else { @@ -528,8 +503,9 @@ int av1_receive_compressed_data(AV1Decoder *pbi, size_t size, if (!cm->show_existing_frame) { if (cm->seg.enabled) { - if (cm->prev_frame && (cm->mi_rows == cm->prev_frame->mi_rows) && - (cm->mi_cols == cm->prev_frame->mi_cols)) { + if (cm->prev_frame && + (cm->mi_params.mi_rows == cm->prev_frame->mi_rows) && + (cm->mi_params.mi_cols == cm->prev_frame->mi_cols)) { cm->last_frame_seg_map = cm->prev_frame->seg_map; } else { cm->last_frame_seg_map = NULL; diff --git a/media/libaom/src/av1/decoder/decoder.h b/media/libaom/src/av1/decoder/decoder.h index 140ff4f87e..4580de2ac7 100644 --- a/media/libaom/src/av1/decoder/decoder.h +++ b/media/libaom/src/av1/decoder/decoder.h @@ -19,8 +19,8 @@ #include "aom_scale/yv12config.h" #include "aom_util/aom_thread.h" +#include "av1/common/av1_common_int.h" #include "av1/common/thread_common.h" -#include "av1/common/onyxc_int.h" #include "av1/decoder/dthread.h" #if CONFIG_ACCOUNTING #include "av1/decoder/accounting.h" @@ -41,7 +41,6 @@ typedef void (*decode_block_visitor_fn_t)(const AV1_COMMON *const cm, typedef void (*predict_inter_block_visitor_fn_t)(AV1_COMMON *const cm, MACROBLOCKD *const xd, - int mi_row, int mi_col, BLOCK_SIZE bsize); typedef void (*cfl_store_inter_block_visitor_fn_t)(AV1_COMMON *const cm, @@ -244,6 +243,13 @@ typedef struct AV1Decoder { #endif AV1DecRowMTInfo frame_row_mt_info; + aom_metadata_array_t *metadata; + + int context_update_tile_id; + int skip_loop_filter; + int skip_film_grain; + int is_annexb; + int valid_for_referencing[REF_FRAMES]; } AV1Decoder; // Returns 0 on success. Sets pbi->common.error.error_code to a nonzero error @@ -311,9 +317,8 @@ static INLINE int av1_read_uniform(aom_reader *r, int n) { typedef void (*palette_visitor_fn_t)(MACROBLOCKD *const xd, int plane, aom_reader *r); -void av1_visit_palette(AV1Decoder *const pbi, MACROBLOCKD *const xd, int mi_row, - int mi_col, aom_reader *r, BLOCK_SIZE bsize, - palette_visitor_fn_t visit); +void av1_visit_palette(AV1Decoder *const pbi, MACROBLOCKD *const xd, + aom_reader *r, palette_visitor_fn_t visit); typedef void (*block_visitor_fn_t)(AV1Decoder *const pbi, ThreadData *const td, int mi_row, int mi_col, aom_reader *r, diff --git a/media/libaom/src/av1/decoder/decodetxb.c b/media/libaom/src/av1/decoder/decodetxb.c index dd69dd2454..541f4c9846 100644 --- a/media/libaom/src/av1/decoder/decodetxb.c +++ b/media/libaom/src/av1/decoder/decodetxb.c @@ -157,14 +157,12 @@ uint8_t av1_read_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCKD *const xd, // only y plane's tx_type is transmitted av1_read_tx_type(cm, xd, blk_row, blk_col, tx_size, r); } - const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, cm->reduced_tx_set_used); + const TX_TYPE tx_type = + av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size, + cm->features.reduced_tx_set_used); const TX_CLASS tx_class = tx_type_to_class[tx_type]; - const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); const qm_val_t *iqmatrix = - IS_2D_TRANSFORM(tx_type) - ? pd->seg_iqmatrix[mbmi->segment_id][qm_tx_size] - : cm->giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; + av1_get_iqmatrix(&cm->quant_params, xd, plane, tx_size, tx_type); const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type); const int16_t *const scan = scan_order->scan; int eob_extra = 0; @@ -339,17 +337,18 @@ void av1_read_coeffs_txb_facade(const AV1_COMMON *const cm, get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); TXB_CTX txb_ctx; - get_txb_ctx(plane_bsize, tx_size, plane, pd->above_context + col, - pd->left_context + row, &txb_ctx); + get_txb_ctx(plane_bsize, tx_size, plane, pd->above_entropy_context + col, + pd->left_entropy_context + row, &txb_ctx); const uint8_t cul_level = av1_read_coeffs_txb(cm, xd, r, row, col, plane, &txb_ctx, tx_size); - av1_set_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level, col, row); + av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level, col, + row); if (is_inter_block(mbmi)) { const PLANE_TYPE plane_type = get_plane_type(plane); // tx_type will be read out in av1_read_coeffs_txb_facade const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, row, col, tx_size, - cm->reduced_tx_set_used); + cm->features.reduced_tx_set_used); if (plane == 0) { const int txw = tx_size_wide_unit[tx_size]; diff --git a/media/libaom/src/av1/decoder/decodetxb.h b/media/libaom/src/av1/decoder/decodetxb.h index fe04f6abdd..39bf0bf78f 100644 --- a/media/libaom/src/av1/decoder/decodetxb.h +++ b/media/libaom/src/av1/decoder/decodetxb.h @@ -14,8 +14,8 @@ #include "config/aom_config.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" #include "av1/common/txb_common.h" #include "aom_dsp/bitreader.h" diff --git a/media/libaom/src/av1/decoder/dthread.h b/media/libaom/src/av1/decoder/dthread.h index c1b8719af8..f82b9d8ccf 100644 --- a/media/libaom/src/av1/decoder/dthread.h +++ b/media/libaom/src/av1/decoder/dthread.h @@ -39,7 +39,6 @@ typedef struct FrameWorkerData { const uint8_t *data_end; size_t data_size; void *user_priv; - int worker_id; int received_frame; int frame_context_ready; // Current frame's context is ready to read. int frame_decoded; // Finished decoding current frame. diff --git a/media/libaom/src/av1/decoder/inspection.c b/media/libaom/src/av1/decoder/inspection.c index 26041e3e23..d121a70348 100644 --- a/media/libaom/src/av1/decoder/inspection.c +++ b/media/libaom/src/av1/decoder/inspection.c @@ -36,16 +36,18 @@ void ifd_clear(insp_frame_data *fd) { int ifd_inspect(insp_frame_data *fd, void *decoder, int skip_not_transform) { struct AV1Decoder *pbi = (struct AV1Decoder *)decoder; AV1_COMMON *const cm = &pbi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const CommonQuantParams *quant_params = &cm->quant_params; - if (fd->mi_rows != cm->mi_rows || fd->mi_cols != cm->mi_cols) { + if (fd->mi_rows != mi_params->mi_rows || fd->mi_cols != mi_params->mi_cols) { ifd_clear(fd); - ifd_init_mi_rc(fd, cm->mi_rows, cm->mi_cols); + ifd_init_mi_rc(fd, mi_params->mi_rows, mi_params->mi_cols); } fd->show_existing_frame = cm->show_existing_frame; fd->frame_number = cm->current_frame.frame_number; fd->show_frame = cm->show_frame; fd->frame_type = cm->current_frame.frame_type; - fd->base_qindex = cm->base_qindex; + fd->base_qindex = quant_params->base_qindex; // Set width and height of the first tile until generic support can be added TileInfo tile_info; av1_tile_set_row(&tile_info, cm, 0); @@ -61,15 +63,16 @@ int ifd_inspect(insp_frame_data *fd, void *decoder, int skip_not_transform) { int i, j; for (i = 0; i < MAX_SEGMENTS; i++) { for (j = 0; j < 2; j++) { - fd->y_dequant[i][j] = cm->y_dequant_QTX[i][j]; - fd->u_dequant[i][j] = cm->u_dequant_QTX[i][j]; - fd->v_dequant[i][j] = cm->v_dequant_QTX[i][j]; + fd->y_dequant[i][j] = quant_params->y_dequant_QTX[i][j]; + fd->u_dequant[i][j] = quant_params->u_dequant_QTX[i][j]; + fd->v_dequant[i][j] = quant_params->v_dequant_QTX[i][j]; } } - for (j = 0; j < cm->mi_rows; j++) { - for (i = 0; i < cm->mi_cols; i++) { - const MB_MODE_INFO *mbmi = cm->mi_grid_base[j * cm->mi_stride + i]; - insp_mi_data *mi = &fd->mi_grid[j * cm->mi_cols + i]; + for (j = 0; j < mi_params->mi_rows; j++) { + for (i = 0; i < mi_params->mi_cols; i++) { + const MB_MODE_INFO *mbmi = + mi_params->mi_grid_base[j * mi_params->mi_stride + i]; + insp_mi_data *mi = &fd->mi_grid[j * mi_params->mi_cols + i]; // Segment mi->segment_id = mbmi->segment_id; // Motion Vectors @@ -119,8 +122,9 @@ int ifd_inspect(insp_frame_data *fd, void *decoder, int skip_not_transform) { if (mi->skip) { const int tx_type_row = j - j % tx_size_high_unit[mi->tx_size]; const int tx_type_col = i - i % tx_size_wide_unit[mi->tx_size]; - const int tx_type_map_idx = tx_type_row * cm->mi_stride + tx_type_col; - mi->tx_type = cm->tx_type_map[tx_type_map_idx]; + const int tx_type_map_idx = + tx_type_row * mi_params->mi_stride + tx_type_col; + mi->tx_type = mi_params->tx_type_map[tx_type_map_idx]; } else { mi->tx_type = 0; } diff --git a/media/libaom/src/av1/decoder/obu.c b/media/libaom/src/av1/decoder/obu.c index 3619264434..791e5965b5 100644 --- a/media/libaom/src/av1/decoder/obu.c +++ b/media/libaom/src/av1/decoder/obu.c @@ -87,10 +87,14 @@ static int read_bitstream_level(AV1_LEVEL *seq_level_idx, } // Returns whether two sequence headers are consistent with each other. -// TODO(huisu,wtc@google.com): make sure the code matches the spec exactly. +// Note that the 'op_params' field is not compared per Section 7.5 in the spec: +// Within a particular coded video sequence, the contents of +// sequence_header_obu must be bit-identical each time the sequence header +// appears except for the contents of operating_parameters_info. static int are_seq_headers_consistent(const SequenceHeader *seq_params_old, const SequenceHeader *seq_params_new) { - return !memcmp(seq_params_old, seq_params_new, sizeof(SequenceHeader)); + return !memcmp(seq_params_old, seq_params_new, + offsetof(SequenceHeader, op_params)); } // On success, sets pbi->sequence_header_ready to 1 and returns the number of @@ -125,7 +129,7 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, } if (seq_params->reduced_still_picture_hdr) { - cm->timing_info_present = 0; + seq_params->timing_info_present = 0; seq_params->decoder_model_info_present_flag = 0; seq_params->display_model_info_present_flag = 0; seq_params->operating_points_cnt_minus_1 = 0; @@ -135,16 +139,16 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, return 0; } seq_params->tier[0] = 0; - cm->op_params[0].decoder_model_param_present_flag = 0; - cm->op_params[0].display_model_param_present_flag = 0; + seq_params->op_params[0].decoder_model_param_present_flag = 0; + seq_params->op_params[0].display_model_param_present_flag = 0; } else { - cm->timing_info_present = aom_rb_read_bit(rb); // timing_info_present_flag - if (cm->timing_info_present) { - av1_read_timing_info_header(cm, rb); + seq_params->timing_info_present = aom_rb_read_bit(rb); + if (seq_params->timing_info_present) { + av1_read_timing_info_header(&seq_params->timing_info, &cm->error, rb); seq_params->decoder_model_info_present_flag = aom_rb_read_bit(rb); if (seq_params->decoder_model_info_present_flag) - av1_read_decoder_model_info(cm, rb); + av1_read_decoder_model_info(&seq_params->decoder_model_info, rb); } else { seq_params->decoder_model_info_present_flag = 0; } @@ -165,51 +169,57 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi, else seq_params->tier[i] = 0; if (seq_params->decoder_model_info_present_flag) { - cm->op_params[i].decoder_model_param_present_flag = aom_rb_read_bit(rb); - if (cm->op_params[i].decoder_model_param_present_flag) - av1_read_op_parameters_info(cm, rb, i); + seq_params->op_params[i].decoder_model_param_present_flag = + aom_rb_read_bit(rb); + if (seq_params->op_params[i].decoder_model_param_present_flag) + av1_read_op_parameters_info(&seq_params->op_params[i], + seq_params->decoder_model_info + .encoder_decoder_buffer_delay_length, + rb); } else { - cm->op_params[i].decoder_model_param_present_flag = 0; + seq_params->op_params[i].decoder_model_param_present_flag = 0; } - 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 = av1_max_level_bitrate( + if (seq_params->timing_info_present && + (seq_params->timing_info.equal_picture_interval || + seq_params->op_params[i].decoder_model_param_present_flag)) { + seq_params->op_params[i].bitrate = av1_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) + if (seq_params->op_params[i].bitrate == 0) aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, "AV1 does not support this combination of " "profile, level, and tier."); // Buffer size in bits/s is bitrate in bits/s * 1 s - cm->op_params[i].buffer_size = cm->op_params[i].bitrate; + seq_params->op_params[i].buffer_size = seq_params->op_params[i].bitrate; } - if (cm->timing_info_present && cm->timing_info.equal_picture_interval && - !cm->op_params[i].decoder_model_param_present_flag) { + if (seq_params->timing_info_present && + seq_params->timing_info.equal_picture_interval && + !seq_params->op_params[i].decoder_model_param_present_flag) { // When the decoder_model_parameters are not sent for this op, set // the default ones that can be used with the resource availability mode - cm->op_params[i].decoder_buffer_delay = 70000; - cm->op_params[i].encoder_buffer_delay = 20000; - cm->op_params[i].low_delay_mode_flag = 0; + seq_params->op_params[i].decoder_buffer_delay = 70000; + seq_params->op_params[i].encoder_buffer_delay = 20000; + seq_params->op_params[i].low_delay_mode_flag = 0; } if (seq_params->display_model_info_present_flag) { - cm->op_params[i].display_model_param_present_flag = aom_rb_read_bit(rb); - if (cm->op_params[i].display_model_param_present_flag) { - cm->op_params[i].initial_display_delay = + seq_params->op_params[i].display_model_param_present_flag = + aom_rb_read_bit(rb); + if (seq_params->op_params[i].display_model_param_present_flag) { + seq_params->op_params[i].initial_display_delay = aom_rb_read_literal(rb, 4) + 1; - if (cm->op_params[i].initial_display_delay > 10) + if (seq_params->op_params[i].initial_display_delay > 10) aom_internal_error( &cm->error, AOM_CODEC_UNSUP_BITSTREAM, "AV1 does not support more than 10 decoded frames delay"); } else { - cm->op_params[i].initial_display_delay = 10; + seq_params->op_params[i].initial_display_delay = 10; } } else { - cm->op_params[i].display_model_param_present_flag = 0; - cm->op_params[i].initial_display_delay = 10; + seq_params->op_params[i].display_model_param_present_flag = 0; + seq_params->op_params[i].initial_display_delay = 10; } } } @@ -278,11 +288,12 @@ static int32_t read_tile_group_header(AV1Decoder *pbi, int *start_tile, int *end_tile, int tile_start_implicit) { AV1_COMMON *const cm = &pbi->common; + CommonTileParams *const tiles = &cm->tiles; uint32_t saved_bit_offset = rb->bit_offset; int tile_start_and_end_present_flag = 0; - const int num_tiles = pbi->common.tile_rows * pbi->common.tile_cols; + const int num_tiles = tiles->rows * tiles->cols; - if (!pbi->common.large_scale_tile && num_tiles > 1) { + if (!tiles->large_scale && num_tiles > 1) { tile_start_and_end_present_flag = aom_rb_read_bit(rb); if (tile_start_implicit && tile_start_and_end_present_flag) { aom_internal_error( @@ -291,12 +302,12 @@ static int32_t read_tile_group_header(AV1Decoder *pbi, return -1; } } - if (pbi->common.large_scale_tile || num_tiles == 1 || + if (tiles->large_scale || num_tiles == 1 || !tile_start_and_end_present_flag) { *start_tile = 0; *end_tile = num_tiles - 1; } else { - int tile_bits = cm->log2_tile_rows + cm->log2_tile_cols; + int tile_bits = tiles->log2_rows + tiles->log2_cols; *start_tile = aom_rb_read_literal(rb, tile_bits); *end_tile = aom_rb_read_literal(rb, tile_bits); } @@ -346,7 +357,7 @@ static uint32_t read_one_tile_group_obu( tg_payload_size = (uint32_t)(*p_data_end - data); - *is_last_tg = end_tile == cm->tile_rows * cm->tile_cols - 1; + *is_last_tg = end_tile == cm->tiles.rows * cm->tiles.cols - 1; return header_size + tg_payload_size; } @@ -378,7 +389,7 @@ static void alloc_tile_list_buffer(AV1Decoder *pbi) { cm->seq_params.subsampling_y, (cm->seq_params.use_highbitdepth && (cm->seq_params.bit_depth > AOM_BITS_8)), - 0, cm->byte_alignment)) + 0, cm->features.byte_alignment)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate the tile list output buffer"); } @@ -474,7 +485,7 @@ static uint32_t read_and_decode_one_tile_list(AV1Decoder *pbi, int *frame_decoding_finished) { AV1_COMMON *const cm = &pbi->common; uint32_t tile_list_payload_size = 0; - const int num_tiles = cm->tile_cols * cm->tile_rows; + const int num_tiles = cm->tiles.cols * cm->tiles.rows; const int start_tile = 0; const int end_tile = num_tiles - 1; int i = 0; @@ -516,8 +527,8 @@ static uint32_t read_and_decode_one_tile_list(AV1Decoder *pbi, pbi->dec_tile_row = aom_rb_read_literal(rb, 8); pbi->dec_tile_col = aom_rb_read_literal(rb, 8); if (pbi->dec_tile_row < 0 || pbi->dec_tile_col < 0 || - pbi->dec_tile_row >= cm->tile_rows || - pbi->dec_tile_col >= cm->tile_cols) { + pbi->dec_tile_row >= cm->tiles.rows || + pbi->dec_tile_col >= cm->tiles.cols) { cm->error.error_code = AOM_CODEC_CORRUPT_FRAME; return 0; } @@ -548,50 +559,119 @@ static uint32_t read_and_decode_one_tile_list(AV1Decoder *pbi, return tile_list_payload_size; } -// Reads the country code as specified in Recommendation ITU-T T.35. On -// success, returns the number of bytes read from 'data'. On failure, calls -// aom_internal_error() and does not return. -// -// Note: This function does not read itu_t_t35_payload_bytes because the exact -// syntax of itu_t_t35_payload_bytes is not defined in the spec. -static size_t read_metadata_itut_t35(AV1_COMMON *const cm, const uint8_t *data, - size_t sz) { - size_t i = 0; - // itu_t_t35_country_code f(8) - if (i >= sz) { - aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, - "itu_t_t35_country_code is missing"); +// Returns the last nonzero byte index in 'data'. If there is no nonzero byte in +// 'data', returns -1. +static int get_last_nonzero_byte_index(const uint8_t *data, size_t sz) { + // Scan backward and return on the first nonzero byte. + int i = (int)sz - 1; + while (i >= 0 && data[i] == 0) { + --i; } - const int itu_t_t35_country_code = data[i]; - ++i; - if (itu_t_t35_country_code == 0xFF) { - // itu_t_t35_country_code_extension_byte f(8) - if (i >= sz) { - aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, - "itu_t_t35_country_code_extension_byte is missing"); - } - ++i; - } - // itu_t_t35_payload_bytes return i; } -static void read_metadata_hdr_cll(struct aom_read_bit_buffer *rb) { - aom_rb_read_literal(rb, 16); // max_cll - aom_rb_read_literal(rb, 16); // max_fall +// Allocates metadata that was read and adds it to the decoders metadata array. +static void alloc_read_metadata(AV1Decoder *const pbi, + OBU_METADATA_TYPE metadata_type, + const uint8_t *data, size_t sz, + aom_metadata_insert_flags_t insert_flag) { + AV1_COMMON *const cm = &pbi->common; + aom_metadata_t *metadata = + aom_img_metadata_alloc(metadata_type, data, sz, insert_flag); + if (!metadata) { + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Error allocating metadata"); + } + if (!pbi->metadata) { + pbi->metadata = aom_img_metadata_array_alloc(1); + if (!pbi->metadata) { + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Failed to allocate metadata array"); + } + } else { + aom_metadata_t **metadata_array = + (aom_metadata_t **)realloc(pbi->metadata->metadata_array, + (pbi->metadata->sz + 1) * sizeof(metadata)); + if (!metadata_array) { + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Error allocating metadata"); + } + pbi->metadata->metadata_array = metadata_array; + pbi->metadata->sz++; + } + pbi->metadata->metadata_array[pbi->metadata->sz - 1] = metadata; } -static void read_metadata_hdr_mdcv(struct aom_read_bit_buffer *rb) { - for (int i = 0; i < 3; i++) { - aom_rb_read_literal(rb, 16); // primary_chromaticity_x[ i ] - aom_rb_read_literal(rb, 16); // primary_chromaticity_y[ i ] +// On success, returns the number of bytes read from 'data'. On failure, calls +// aom_internal_error() and does not return. +static size_t read_metadata_itut_t35(AV1Decoder *const pbi, const uint8_t *data, + size_t sz) { + const int kMinItuT35PayloadSize = 2; + AV1_COMMON *const cm = &pbi->common; + if (sz == 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "itu_t_t35_country_code is missing"); } + int bytes_read = get_last_nonzero_byte_index(data, sz); + if (bytes_read < 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "No trailing bits found on metadata"); + } + if (*data == 0xFF && bytes_read < kMinItuT35PayloadSize) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "itu_t_t35_country_code_extension_byte is missing"); + } + alloc_read_metadata(pbi, OBU_METADATA_TYPE_ITUT_T35, data, (size_t)bytes_read, + AOM_MIF_ANY_FRAME); + return (size_t)bytes_read; +} - aom_rb_read_literal(rb, 16); // white_point_chromaticity_x - aom_rb_read_literal(rb, 16); // white_point_chromaticity_y +// On success, returns the number of bytes read from 'data'. On failure, calls +// aom_internal_error() and does not return. +static size_t read_metadata_hdr_cll(AV1Decoder *const pbi, const uint8_t *data, + size_t sz) { + const int kHdrCllPayloadSize = 4; + AV1_COMMON *const cm = &pbi->common; + if (sz == 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "HDR CLL metadata payload is missing"); + } + int bytes_read = get_last_nonzero_byte_index(data, sz); + if (bytes_read < 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "No trailing bits found on metadata"); + } + if (bytes_read != kHdrCllPayloadSize) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "Incorrect HDR CLL metadata payload size"); + } + alloc_read_metadata(pbi, OBU_METADATA_TYPE_HDR_CLL, data, (size_t)bytes_read, + AOM_MIF_ANY_FRAME); + return (size_t)bytes_read; +} - aom_rb_read_unsigned_literal(rb, 32); // luminance_max - aom_rb_read_unsigned_literal(rb, 32); // luminance_min +// On success, returns the number of bytes read from 'data'. On failure, calls +// aom_internal_error() and does not return. +static size_t read_metadata_hdr_mdcv(AV1Decoder *const pbi, const uint8_t *data, + size_t sz) { + const int kMdcvPayloadSize = 24; + AV1_COMMON *const cm = &pbi->common; + if (sz == 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "HDR MDCV metadata payload is missing"); + } + int bytes_read = get_last_nonzero_byte_index(data, sz); + if (bytes_read < 0) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "No trailing bits found on HDR MDCV metadata"); + } + if (bytes_read != kMdcvPayloadSize) { + aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, + "Incorrect HDR MDCV metadata payload size"); + } + alloc_read_metadata(pbi, OBU_METADATA_TYPE_HDR_MDCV, data, (size_t)bytes_read, + AOM_MIF_ANY_FRAME); + return (size_t)bytes_read; } static void scalability_structure(struct aom_read_bit_buffer *rb) { @@ -709,26 +789,37 @@ static size_t read_metadata(AV1Decoder *pbi, const uint8_t *data, size_t sz) { if (metadata_type == OBU_METADATA_TYPE_ITUT_T35) { size_t bytes_read = type_length + - read_metadata_itut_t35(cm, data + type_length, sz - type_length); - // Ignore itu_t_t35_payload_bytes and check trailing bits. Section 6.7.2 - // of the spec says: - // itu_t_t35_payload_bytes shall be bytes containing data registered as - // specified in Recommendation ITU-T T.35. - // Therefore itu_t_t35_payload_bytes is byte aligned and the first + read_metadata_itut_t35(pbi, data + type_length, sz - type_length); + // itu_t_t35_payload_bytes is byte aligned and the first // trailing byte should be 0x80. if (get_last_nonzero_byte(data + bytes_read, sz - bytes_read) != 0x80) { pbi->common.error.error_code = AOM_CODEC_CORRUPT_FRAME; return 0; } return sz; + } else if (metadata_type == OBU_METADATA_TYPE_HDR_CLL) { + size_t bytes_read = + type_length + + read_metadata_hdr_cll(pbi, data + type_length, sz - type_length); + if (get_last_nonzero_byte(data + bytes_read, sz - bytes_read) != 0x80) { + pbi->common.error.error_code = AOM_CODEC_CORRUPT_FRAME; + return 0; + } + return sz; + } else if (metadata_type == OBU_METADATA_TYPE_HDR_MDCV) { + size_t bytes_read = + type_length + + read_metadata_hdr_mdcv(pbi, data + type_length, sz - type_length); + if (get_last_nonzero_byte(data + bytes_read, sz - bytes_read) != 0x80) { + pbi->common.error.error_code = AOM_CODEC_CORRUPT_FRAME; + return 0; + } + return sz; } + struct aom_read_bit_buffer rb; av1_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); - if (metadata_type == OBU_METADATA_TYPE_HDR_CLL) { - read_metadata_hdr_cll(&rb); - } else if (metadata_type == OBU_METADATA_TYPE_HDR_MDCV) { - read_metadata_hdr_mdcv(&rb); - } else if (metadata_type == OBU_METADATA_TYPE_SCALABILITY) { + if (metadata_type == OBU_METADATA_TYPE_SCALABILITY) { read_metadata_scalability(&rb); } else { assert(metadata_type == OBU_METADATA_TYPE_TIMECODE); @@ -742,6 +833,24 @@ static size_t read_metadata(AV1Decoder *pbi, const uint8_t *data, size_t sz) { return type_length + (rb.bit_offset >> 3); } +// On success, returns 'sz'. On failure, sets pbi->common.error.error_code and +// returns 0. +static size_t read_padding(AV1_COMMON *const cm, const uint8_t *data, + size_t sz) { + // The spec allows a padding OBU to be header-only (i.e., obu_size = 0). So + // check trailing bits only if sz > 0. + if (sz > 0) { + // The payload of a padding OBU is byte aligned. Therefore the first + // trailing byte should be 0x80. See https://crbug.com/aomedia/2393. + const uint8_t last_nonzero_byte = get_last_nonzero_byte(data, sz); + if (last_nonzero_byte != 0x80) { + cm->error.error_code = AOM_CODEC_CORRUPT_FRAME; + return 0; + } + } + return sz; +} + // On success, returns a boolean that indicates whether the decoding of the // current frame is finished. On failure, sets cm->error.error_code and // returns -1. @@ -762,8 +871,8 @@ int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data, return -1; } - // Reset pbi->camera_frame_header_ready to 0 if cm->large_scale_tile = 0. - if (!cm->large_scale_tile) pbi->camera_frame_header_ready = 0; + // Reset pbi->camera_frame_header_ready to 0 if cm->tiles.large_scale = 0. + if (!cm->tiles.large_scale) pbi->camera_frame_header_ready = 0; // decode frame as a series of OBUs while (!frame_decoding_finished && cm->error.error_code == AOM_CODEC_OK) { @@ -781,7 +890,7 @@ int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data, } aom_codec_err_t status = - aom_read_obu_header_and_size(data, bytes_available, cm->is_annexb, + aom_read_obu_header_and_size(data, bytes_available, pbi->is_annexb, &obu_header, &payload_size, &bytes_read); if (status != AOM_CODEC_OK) { @@ -849,11 +958,11 @@ int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data, } // Only decode first frame header received if (!pbi->seen_frame_header || - (cm->large_scale_tile && !pbi->camera_frame_header_ready)) { + (cm->tiles.large_scale && !pbi->camera_frame_header_ready)) { frame_header_size = read_frame_header_obu( pbi, &rb, data, p_data_end, obu_header.type != OBU_FRAME); pbi->seen_frame_header = 1; - if (!pbi->ext_tile_debug && cm->large_scale_tile) + if (!pbi->ext_tile_debug && cm->tiles.large_scale) pbi->camera_frame_header_ready = 1; } else { // TODO(wtc): Verify that the frame_header_obu is identical to the @@ -931,7 +1040,7 @@ int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data, return -1; } - cm->large_scale_tile = 1; + cm->tiles.large_scale = 1; av1_set_single_tile_decoding_mode(cm); decoded_payload_size = read_and_decode_one_tile_list(pbi, &rb, data, data + payload_size, @@ -939,8 +1048,8 @@ int aom_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data, if (cm->error.error_code != AOM_CODEC_OK) return -1; break; case OBU_PADDING: - // TODO(wtc): Check trailing bits. - decoded_payload_size = payload_size; + decoded_payload_size = read_padding(&pbi->common, data, payload_size); + if (cm->error.error_code != AOM_CODEC_OK) return -1; break; default: // Skip unrecognized OBUs diff --git a/media/libaom/src/av1/encoder/aq_complexity.c b/media/libaom/src/av1/encoder/aq_complexity.c index e3514514e5..36580063d6 100644 --- a/media/libaom/src/av1/encoder/aq_complexity.c +++ b/media/libaom/src/av1/encoder/aq_complexity.c @@ -45,10 +45,25 @@ static int get_aq_c_strength(int q_index, aom_bit_depth_t bit_depth) { return (base_quant > 10) + (base_quant > 25); } +static bool is_frame_aq_enabled(const AV1_COMP *const cpi) { + const AV1_COMMON *const cm = &cpi->common; + + return frame_is_intra_only(cm) || cm->features.error_resilient_mode || + cpi->refresh_alt_ref_frame || + (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref); +} + +// Segmentation only makes sense if the target bits per SB is above a threshold. +// Below this the overheads will usually outweigh any benefit. +static bool is_sb_aq_enabled(const AV1_COMP *const cpi) { + return cpi->rc.sb64_target_rate >= 256; +} + void av1_setup_in_frame_q_adj(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; + const int base_qindex = cm->quant_params.base_qindex; struct segmentation *const seg = &cm->seg; - int resolution_change = + const int resolution_change = cm->prev_frame && (cm->width != cm->prev_frame->width || cm->height != cm->prev_frame->height); @@ -56,27 +71,24 @@ void av1_setup_in_frame_q_adj(AV1_COMP *cpi) { aom_clear_system_state(); if (resolution_change) { - memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); av1_clearall_segfeatures(seg); av1_disable_segmentation(seg); return; } - if (frame_is_intra_only(cm) || cm->error_resilient_mode || - cpi->refresh_alt_ref_frame || - (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { + if (is_frame_aq_enabled(cpi)) { int segment; const int aq_strength = - get_aq_c_strength(cm->base_qindex, cm->seq_params.bit_depth); + get_aq_c_strength(base_qindex, cm->seq_params.bit_depth); // Clear down the segment map. - memset(cpi->segmentation_map, DEFAULT_AQ2_SEG, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, DEFAULT_AQ2_SEG, + cm->mi_params.mi_rows * cm->mi_params.mi_cols); av1_clearall_segfeatures(seg); - // Segmentation only makes sense if the target bits per SB is above a - // threshold. Below this the overheads will usually outweigh any benefit. - if (cpi->rc.sb64_target_rate < 256) { + if (!is_sb_aq_enabled(cpi)) { av1_disable_segmentation(seg); return; } @@ -93,17 +105,17 @@ void av1_setup_in_frame_q_adj(AV1_COMP *cpi) { if (segment == DEFAULT_AQ2_SEG) continue; qindex_delta = av1_compute_qdelta_by_rate( - &cpi->rc, cm->current_frame.frame_type, cm->base_qindex, + &cpi->rc, cm->current_frame.frame_type, base_qindex, aq_c_q_adj_factor[aq_strength][segment], cm->seq_params.bit_depth); // For AQ complexity mode, we dont allow Q0 in a segment if the base // Q is not 0. Q0 (lossless) implies 4x4 only and in AQ mode 2 a segment // Q delta is sometimes applied without going back around the rd loop. // This could lead to an illegal combination of partition size and q. - if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) { - qindex_delta = -cm->base_qindex + 1; + if ((base_qindex != 0) && ((base_qindex + qindex_delta) == 0)) { + qindex_delta = -base_qindex + 1; } - if ((cm->base_qindex + qindex_delta) > 0) { + if ((base_qindex + qindex_delta) > 0) { av1_enable_segfeature(seg, segment, SEG_LVL_ALT_Q); av1_set_segdata(seg, segment, SEG_LVL_ALT_Q, qindex_delta); } @@ -118,12 +130,13 @@ void av1_setup_in_frame_q_adj(AV1_COMP *cpi) { // bits for the block vs a target average and its spatial complexity. void av1_caq_select_segment(const AV1_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs, int mi_row, int mi_col, int projected_rate) { + if ((!is_frame_aq_enabled(cpi)) || (!is_sb_aq_enabled(cpi))) return; const AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - const int mi_offset = mi_row * cm->mi_cols + mi_col; - const int xmis = AOMMIN(cm->mi_cols - mi_col, mi_size_wide[bs]); - const int ymis = AOMMIN(cm->mi_rows - mi_row, mi_size_high[bs]); + const int mi_offset = mi_row * cm->mi_params.mi_cols + mi_col; + const int xmis = AOMMIN(cm->mi_params.mi_cols - mi_col, mi_size_wide[bs]); + const int ymis = AOMMIN(cm->mi_params.mi_rows - mi_row, mi_size_high[bs]); int x, y; int i; unsigned char segment; @@ -139,12 +152,12 @@ void av1_caq_select_segment(const AV1_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs, const int target_rate = (int)(num / denom); double logvar; double low_var_thresh; - const int aq_strength = - get_aq_c_strength(cm->base_qindex, cm->seq_params.bit_depth); + const int aq_strength = get_aq_c_strength(cm->quant_params.base_qindex, + cm->seq_params.bit_depth); aom_clear_system_state(); low_var_thresh = - (cpi->oxcf.pass == 2) + (is_stat_consumption_stage_twopass(cpi)) ? AOMMAX(exp(cpi->twopass.mb_av_energy), MIN_DEFAULT_LV_THRESH) : DEFAULT_LV_THRESH; @@ -166,7 +179,7 @@ void av1_caq_select_segment(const AV1_COMP *cpi, MACROBLOCK *mb, BLOCK_SIZE bs, // Fill in the entires in the segment map corresponding to this SB64. for (y = 0; y < ymis; y++) { for (x = 0; x < xmis; x++) { - cpi->segmentation_map[mi_offset + y * cm->mi_cols + x] = segment; + cpi->enc_seg.map[mi_offset + y * cm->mi_params.mi_cols + x] = segment; } } } diff --git a/media/libaom/src/av1/encoder/aq_cyclicrefresh.c b/media/libaom/src/av1/encoder/aq_cyclicrefresh.c index 854adbbd93..b8884942ad 100644 --- a/media/libaom/src/av1/encoder/aq_cyclicrefresh.c +++ b/media/libaom/src/av1/encoder/aq_cyclicrefresh.c @@ -96,28 +96,27 @@ static int compute_deltaq(const AV1_COMP *cpi, int q, double rate_factor) { int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi, double correction_factor) { const AV1_COMMON *const cm = &cpi->common; + const FRAME_TYPE frame_type = cm->current_frame.frame_type; + const int base_qindex = cm->quant_params.base_qindex; + const int bit_depth = cm->seq_params.bit_depth; const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - int estimated_bits; - int mbs = cm->MBs; - int num4x4bl = mbs << 4; + const int mbs = cm->mi_params.MBs; + const 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 4x4 units. - double weight_segment1 = (double)cr->actual_num_seg1_blocks / num4x4bl; - double weight_segment2 = (double)cr->actual_num_seg2_blocks / num4x4bl; + const double weight_segment1 = (double)cr->actual_num_seg1_blocks / num4x4bl; + const double weight_segment2 = (double)cr->actual_num_seg2_blocks / num4x4bl; // Take segment weighted average for estimated bits. - estimated_bits = + const int estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) * - av1_estimate_bits_at_q(cm->current_frame.frame_type, - cm->base_qindex, mbs, correction_factor, - cm->seq_params.bit_depth) + + av1_estimate_bits_at_q(frame_type, base_qindex, mbs, + correction_factor, bit_depth) + weight_segment1 * av1_estimate_bits_at_q( - cm->current_frame.frame_type, - cm->base_qindex + cr->qindex_delta[1], mbs, - correction_factor, cm->seq_params.bit_depth) + + frame_type, base_qindex + cr->qindex_delta[1], + mbs, correction_factor, bit_depth) + weight_segment2 * av1_estimate_bits_at_q( - cm->current_frame.frame_type, - cm->base_qindex + cr->qindex_delta[2], mbs, - correction_factor, cm->seq_params.bit_depth)); + frame_type, base_qindex + cr->qindex_delta[2], + mbs, correction_factor, bit_depth)); return estimated_bits; } @@ -131,7 +130,7 @@ 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 num4x4bl = cm->MBs << 4; + int num4x4bl = cm->mi_params.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 = @@ -164,9 +163,9 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; - const int xmis = AOMMIN(cm->mi_cols - mi_col, bw); - const int ymis = AOMMIN(cm->mi_rows - mi_row, bh); - const int block_index = mi_row * cm->mi_cols + mi_col; + const int xmis = AOMMIN(cm->mi_params.mi_cols - mi_col, bw); + const int ymis = AOMMIN(cm->mi_params.mi_rows - mi_row, bh); + const int block_index = mi_row * cm->mi_params.mi_cols + mi_col; const int refresh_this_block = candidate_refresh_aq(cr, mbmi, rate, dist, bsize); // Default is to not update the refresh map. @@ -200,36 +199,42 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, // copy mbmi->segment_id into global segmentation map. for (int y = 0; y < ymis; y++) for (int x = 0; x < xmis; x++) { - int map_offset = block_index + y * cm->mi_cols + x; + int map_offset = block_index + y * cm->mi_params.mi_cols + x; cr->map[map_offset] = new_map_value; - cpi->segmentation_map[map_offset] = mbmi->segment_id; + cpi->enc_seg.map[map_offset] = mbmi->segment_id; } } // Update the some stats after encode frame is done. void av1_cyclic_refresh_postencode(AV1_COMP *const cpi) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - unsigned char *const seg_map = cpi->segmentation_map; + unsigned char *const seg_map = cpi->enc_seg.map; cr->cnt_zeromv = 0; cr->actual_num_seg1_blocks = 0; cr->actual_num_seg2_blocks = 0; - for (int mi_row = 0; mi_row < cm->mi_rows; mi_row++) { - for (int mi_col = 0; mi_col < cm->mi_cols; mi_col++) { - MB_MODE_INFO **mi = cm->mi_grid_base + mi_row * cm->mi_stride + mi_col; + for (int mi_row = 0; mi_row < mi_params->mi_rows; mi_row++) { + for (int mi_col = 0; mi_col < mi_params->mi_cols; mi_col++) { + MB_MODE_INFO **mi = + mi_params->mi_grid_base + mi_row * mi_params->mi_stride + mi_col; MV mv = mi[0]->mv[0].as_mv; - int map_index = mi_row * cm->mi_cols + mi_col; - if (cyclic_refresh_segment_id(seg_map[map_index]) == CR_SEGMENT_ID_BOOST1) - cr->actual_num_seg1_blocks++; - else if (cyclic_refresh_segment_id(seg_map[map_index]) == - CR_SEGMENT_ID_BOOST2) - cr->actual_num_seg2_blocks++; + if (cm->seg.enabled) { + int map_index = mi_row * mi_params->mi_cols + mi_col; + if (cyclic_refresh_segment_id(seg_map[map_index]) == + CR_SEGMENT_ID_BOOST1) + cr->actual_num_seg1_blocks++; + else if (cyclic_refresh_segment_id(seg_map[map_index]) == + CR_SEGMENT_ID_BOOST2) + cr->actual_num_seg2_blocks++; + } // Accumulate low_content_frame. if (is_inter_block(mi[0]) && abs(mv.row) < 16 && abs(mv.col) < 16) cr->cnt_zeromv++; } } - cr->cnt_zeromv = 100 * cr->cnt_zeromv / (cm->mi_rows * cm->mi_cols); + cr->cnt_zeromv = + 100 * cr->cnt_zeromv / (mi_params->mi_rows * mi_params->mi_cols); cr->avg_frame_low_motion = (3 * cr->avg_frame_low_motion + (double)cr->cnt_zeromv) / 4; } @@ -256,18 +261,20 @@ void av1_cyclic_refresh_set_golden_update(AV1_COMP *const cpi) { // encoding of the superblock). static void cyclic_refresh_update_map(AV1_COMP *const cpi) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - unsigned char *const seg_map = cpi->segmentation_map; + unsigned char *const seg_map = cpi->enc_seg.map; int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame; int xmis, ymis, x, y; - memset(seg_map, CR_SEGMENT_ID_BASE, cm->mi_rows * cm->mi_cols); - sb_cols = - (cm->mi_cols + cm->seq_params.mib_size - 1) / cm->seq_params.mib_size; - sb_rows = - (cm->mi_rows + cm->seq_params.mib_size - 1) / cm->seq_params.mib_size; + memset(seg_map, CR_SEGMENT_ID_BASE, mi_params->mi_rows * mi_params->mi_cols); + sb_cols = (mi_params->mi_cols + cm->seq_params.mib_size - 1) / + cm->seq_params.mib_size; + sb_rows = (mi_params->mi_rows + cm->seq_params.mib_size - 1) / + cm->seq_params.mib_size; sbs_in_frame = sb_cols * sb_rows; // Number of target blocks to get the q delta (segment 1). - block_count = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100; + block_count = + cr->percent_refresh * mi_params->mi_rows * mi_params->mi_cols / 100; // Set the segmentation map: cycle through the superblocks, starting at // cr->mb_index, and stopping when either block_count blocks have been found // to be refreshed, or we have passed through whole frame. @@ -283,21 +290,21 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { int mi_row = sb_row_index * cm->seq_params.mib_size; int mi_col = sb_col_index * cm->seq_params.mib_size; // TODO(any): Ensure the population of - // cpi->common.allow_screen_content_tools and use the same instead of - // cpi->oxcf.content == AOM_CONTENT_SCREEN - int qindex_thresh = - cpi->oxcf.content == AOM_CONTENT_SCREEN - ? av1_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST2, cm->base_qindex) - : 0; - assert(mi_row >= 0 && mi_row < cm->mi_rows); - assert(mi_col >= 0 && mi_col < cm->mi_cols); - bl_index = mi_row * cm->mi_cols + mi_col; + // cpi->common.features.allow_screen_content_tools and use the same instead + // of cpi->oxcf.content == AOM_CONTENT_SCREEN + int qindex_thresh = cpi->oxcf.content == AOM_CONTENT_SCREEN + ? av1_get_qindex(&cm->seg, CR_SEGMENT_ID_BOOST2, + cm->quant_params.base_qindex) + : 0; + assert(mi_row >= 0 && mi_row < mi_params->mi_rows); + assert(mi_col >= 0 && mi_col < mi_params->mi_cols); + bl_index = mi_row * mi_params->mi_cols + mi_col; // Loop through all MI blocks in superblock and update map. - xmis = AOMMIN(cm->mi_cols - mi_col, cm->seq_params.mib_size); - ymis = AOMMIN(cm->mi_rows - mi_row, cm->seq_params.mib_size); + xmis = AOMMIN(mi_params->mi_cols - mi_col, cm->seq_params.mib_size); + ymis = AOMMIN(mi_params->mi_rows - mi_row, cm->seq_params.mib_size); for (y = 0; y < ymis; y++) { for (x = 0; x < xmis; x++) { - const int bl_index2 = bl_index + y * cm->mi_cols + x; + const int bl_index2 = bl_index + y * mi_params->mi_cols + x; // If the block is as a candidate for clean up then mark it // for possible boost/refresh (segment 1). The segment id may get // reset to 0 later if block gets coded anything other than GLOBALMV. @@ -313,7 +320,7 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { if (sum_map >= xmis * ymis / 2) { for (y = 0; y < ymis; y++) for (x = 0; x < xmis; x++) { - seg_map[bl_index + y * cm->mi_cols + x] = CR_SEGMENT_ID_BOOST1; + seg_map[bl_index + y * mi_params->mi_cols + x] = CR_SEGMENT_ID_BOOST1; } cr->target_num_seg_blocks += xmis * ymis; } @@ -331,7 +338,7 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { 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 num4x4bl = cm->mi_params.MBs << 4; int target_refresh = 0; double weight_segment_target = 0; double weight_segment = 0; @@ -343,7 +350,7 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { rc->avg_frame_qindex[INTER_FRAME] < qp_thresh || (rc->frames_since_key > 20 && rc->avg_frame_qindex[INTER_FRAME] > qp_max_thresh) || - (cr->avg_frame_low_motion < 20 && rc->frames_since_key > 40)) { + (cr->avg_frame_low_motion < 45 && rc->frames_since_key > 40)) { cr->apply_cyclic_refresh = 0; return; } @@ -386,8 +393,9 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { // 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; + // frame in av1_rc_regulate_q. + target_refresh = + cr->percent_refresh * cm->mi_params.mi_rows * cm->mi_params.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) >> @@ -411,18 +419,19 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { if (cm->current_frame.frame_number == 0) cr->low_content_avg = 0.0; 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); + unsigned char *const seg_map = cpi->enc_seg.map; + memset(seg_map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); av1_disable_segmentation(&cm->seg); if (cm->current_frame.frame_type == KEY_FRAME) { memset(cr->last_coded_q_map, MAXQ, - cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map)); + cm->mi_params.mi_rows * cm->mi_params.mi_cols * + sizeof(*cr->last_coded_q_map)); cr->sb_index = 0; } return; } else { - const double q = - av1_convert_qindex_to_q(cm->base_qindex, cm->seq_params.bit_depth); + const double q = av1_convert_qindex_to_q(cm->quant_params.base_qindex, + cm->seq_params.bit_depth); aom_clear_system_state(); // Set rate threshold to some multiple (set to 2 for now) of the target // rate (target is given by sb64_target_rate and scaled by 256). @@ -453,20 +462,22 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { av1_enable_segfeature(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q); // Set the q delta for segment BOOST1. + const CommonQuantParams *const quant_params = &cm->quant_params; int qindex_delta = - compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta); + compute_deltaq(cpi, quant_params->base_qindex, cr->rate_ratio_qdelta); cr->qindex_delta[1] = qindex_delta; // Compute rd-mult for segment BOOST1. - const int qindex2 = - clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ); + const int qindex2 = clamp( + quant_params->base_qindex + quant_params->y_dc_delta_q + qindex_delta, + 0, MAXQ); cr->rdmult = av1_compute_rd_mult(cpi, qindex2); av1_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta); // Set a more aggressive (higher) q delta for segment BOOST2. qindex_delta = compute_deltaq( - cpi, cm->base_qindex, + cpi, quant_params->base_qindex, AOMMIN(CR_MAX_RATE_TARGET_RATIO, 0.1 * cr->rate_boost_fac * cr->rate_ratio_qdelta)); cr->qindex_delta[2] = qindex_delta; @@ -484,7 +495,7 @@ int av1_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr) { void av1_cyclic_refresh_reset_resize(AV1_COMP *const cpi) { const AV1_COMMON *const cm = &cpi->common; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - memset(cr->map, 0, cm->mi_rows * cm->mi_cols); + memset(cr->map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); cr->sb_index = 0; cpi->refresh_golden_frame = 1; } diff --git a/media/libaom/src/av1/encoder/aq_variance.c b/media/libaom/src/av1/encoder/aq_variance.c index 46b4971d58..4176da292c 100644 --- a/media/libaom/src/av1/encoder/aq_variance.c +++ b/media/libaom/src/av1/encoder/aq_variance.c @@ -44,6 +44,7 @@ static const int segment_id[ENERGY_SPAN] = { 0, 1, 1, 2, 3, 4 }; void av1_vaq_frame_setup(AV1_COMP *cpi) { AV1_COMMON *cm = &cpi->common; + const int base_qindex = cm->quant_params.base_qindex; struct segmentation *seg = &cm->seg; int i; @@ -57,13 +58,13 @@ void av1_vaq_frame_setup(AV1_COMP *cpi) { avg_ratio = rate_ratio[avg_energy]; if (resolution_change) { - memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); av1_clearall_segfeatures(seg); aom_clear_system_state(); av1_disable_segmentation(seg); return; } - if (frame_is_intra_only(cm) || cm->error_resilient_mode || + if (frame_is_intra_only(cm) || cm->features.error_resilient_mode || cpi->refresh_alt_ref_frame || (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { cpi->vaq_refresh = 1; @@ -77,15 +78,15 @@ void av1_vaq_frame_setup(AV1_COMP *cpi) { // Set up avg segment id to be 1.0 and adjust the other segments around // it. int qindex_delta = av1_compute_qdelta_by_rate( - &cpi->rc, cm->current_frame.frame_type, cm->base_qindex, + &cpi->rc, cm->current_frame.frame_type, base_qindex, rate_ratio[i] / avg_ratio, cm->seq_params.bit_depth); // We don't allow qindex 0 in a segment if the base value is not 0. // Q index 0 (lossless) implies 4x4 encoding only and in AQ mode a segment // Q delta is sometimes applied without going back around the rd loop. // This could lead to an illegal combination of partition size and q. - if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) { - qindex_delta = -cm->base_qindex + 1; + if ((base_qindex != 0) && ((base_qindex + qindex_delta) == 0)) { + qindex_delta = -base_qindex + 1; } av1_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta); @@ -174,8 +175,9 @@ int av1_block_wavelet_energy_level(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) { double energy, energy_midpoint; aom_clear_system_state(); - energy_midpoint = (cpi->oxcf.pass == 2) ? cpi->twopass.frame_avg_haar_energy - : DEFAULT_E_MIDPOINT; + energy_midpoint = (is_stat_consumption_stage_twopass(cpi)) + ? cpi->twopass.frame_avg_haar_energy + : DEFAULT_E_MIDPOINT; energy = av1_log_block_wavelet_energy(x, bs) - energy_midpoint; return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX); } @@ -191,12 +193,13 @@ int av1_compute_q_from_energy_level_deltaq_mode(const AV1_COMP *const cpi, } else { rate_level = block_var_level; } + const int base_qindex = cm->quant_params.base_qindex; int qindex_delta = av1_compute_qdelta_by_rate( - &cpi->rc, cm->current_frame.frame_type, cm->base_qindex, + &cpi->rc, cm->current_frame.frame_type, base_qindex, deltaq_rate_ratio[rate_level], cm->seq_params.bit_depth); - if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) { - qindex_delta = -cm->base_qindex + 1; + if ((base_qindex != 0) && ((base_qindex + qindex_delta) == 0)) { + qindex_delta = -base_qindex + 1; } - return cm->base_qindex + qindex_delta; + return base_qindex + qindex_delta; } diff --git a/media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c b/media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c index bc81692d93..22da1a8d66 100644 --- a/media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c +++ b/media/libaom/src/av1/encoder/arm/neon/av1_error_neon.c @@ -56,3 +56,30 @@ int64_t av1_block_error_neon(const tran_low_t *coeff, const tran_low_t *dqcoeff, return vgetq_lane_s64(error, 0) + vgetq_lane_s64(error, 1); #endif } + +int64_t av1_block_error_lp_neon(const int16_t *coeff, const int16_t *dqcoeff, + int block_size) { + int64x2_t error = vdupq_n_s64(0); + + assert(block_size >= 8); + assert((block_size % 8) == 0); + + do { + const int16x8_t c = vld1q_s16(coeff); + const int16x8_t d = vld1q_s16(dqcoeff); + const int16x8_t diff = vsubq_s16(c, d); + const int16x4_t diff_lo = vget_low_s16(diff); + const int16x4_t diff_hi = vget_high_s16(diff); + // diff is 15-bits, the squares 30, so we can store 2 in 31-bits before + // accumulating them in 64-bits. + const int32x4_t err0 = vmull_s16(diff_lo, diff_lo); + const int32x4_t err1 = vmlal_s16(err0, diff_hi, diff_hi); + const int64x2_t err2 = vaddl_s32(vget_low_s32(err1), vget_high_s32(err1)); + error = vaddq_s64(error, err2); + coeff += 8; + dqcoeff += 8; + block_size -= 8; + } while (block_size != 0); + + return vgetq_lane_s64(error, 0) + vgetq_lane_s64(error, 1); +} diff --git a/media/libaom/src/av1/encoder/arm/neon/quantize_neon.c b/media/libaom/src/av1/encoder/arm/neon/quantize_neon.c index 75ad3193d4..c2f50a2173 100644 --- a/media/libaom/src/av1/encoder/arm/neon/quantize_neon.c +++ b/media/libaom/src/av1/encoder/arm/neon/quantize_neon.c @@ -117,3 +117,99 @@ void av1_quantize_fp_neon(const tran_low_t *coeff_ptr, intptr_t count, } #endif // __aarch64__ } + +static INLINE void calculate_dqcoeff_lp_and_store(const int16x8_t qcoeff, + const int16x8_t dequant, + int16_t *dqcoeff) { + const int32x4_t dqcoeff_0 = + vmull_s16(vget_low_s16(qcoeff), vget_low_s16(dequant)); + const int32x4_t dqcoeff_1 = + vmull_s16(vget_high_s16(qcoeff), vget_high_s16(dequant)); + + vst1q_s16(dqcoeff, vcombine_s16(vmovn_s32(dqcoeff_0), vmovn_s32(dqcoeff_1))); +} + +void av1_quantize_lp_neon(const int16_t *coeff_ptr, intptr_t count, + const int16_t *round_ptr, const int16_t *quant_ptr, + int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr, + const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan) { + // Quantization pass: All coefficients with index >= zero_flag are + // skippable. Note: zero_flag can be zero. + const int16x8_t v_zero = vdupq_n_s16(0); + const int16x8_t v_one = vdupq_n_s16(1); + int16x8_t v_eobmax_76543210 = vdupq_n_s16(-1); + int16x8_t v_round = vmovq_n_s16(round_ptr[1]); + int16x8_t v_quant = vmovq_n_s16(quant_ptr[1]); + int16x8_t v_dequant = vmovq_n_s16(dequant_ptr[1]); + + // adjust for dc + v_round = vsetq_lane_s16(round_ptr[0], v_round, 0); + v_quant = vsetq_lane_s16(quant_ptr[0], v_quant, 0); + v_dequant = vsetq_lane_s16(dequant_ptr[0], v_dequant, 0); + // process dc and the first seven ac coeffs + { + const int16x8_t v_iscan = vld1q_s16(&scan[0]); + const int16x8_t v_coeff = vld1q_s16(coeff_ptr); + const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15); + const int16x8_t v_abs = vabsq_s16(v_coeff); + const int16x8_t v_tmp = vqaddq_s16(v_abs, v_round); + const int32x4_t v_tmp_lo = + vmull_s16(vget_low_s16(v_tmp), vget_low_s16(v_quant)); + const int32x4_t v_tmp_hi = + vmull_s16(vget_high_s16(v_tmp), vget_high_s16(v_quant)); + const int16x8_t v_tmp2 = + vcombine_s16(vshrn_n_s32(v_tmp_lo, 16), vshrn_n_s32(v_tmp_hi, 16)); + const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero); + const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one); + const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1); + const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign); + const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign); + calculate_dqcoeff_lp_and_store(v_qcoeff, v_dequant, dqcoeff_ptr); + v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan); + vst1q_s16(qcoeff_ptr, v_qcoeff); + v_round = vmovq_n_s16(round_ptr[1]); + v_quant = vmovq_n_s16(quant_ptr[1]); + v_dequant = vmovq_n_s16(dequant_ptr[1]); + } + // now process the rest of the ac coeffs + for (int i = 8; i < count; i += 8) { + const int16x8_t v_iscan = vld1q_s16(&scan[i]); + const int16x8_t v_coeff = vld1q_s16(coeff_ptr + i); + const int16x8_t v_coeff_sign = vshrq_n_s16(v_coeff, 15); + const int16x8_t v_abs = vabsq_s16(v_coeff); + const int16x8_t v_tmp = vqaddq_s16(v_abs, v_round); + const int32x4_t v_tmp_lo = + vmull_s16(vget_low_s16(v_tmp), vget_low_s16(v_quant)); + const int32x4_t v_tmp_hi = + vmull_s16(vget_high_s16(v_tmp), vget_high_s16(v_quant)); + const int16x8_t v_tmp2 = + vcombine_s16(vshrn_n_s32(v_tmp_lo, 16), vshrn_n_s32(v_tmp_hi, 16)); + const uint16x8_t v_nz_mask = vceqq_s16(v_tmp2, v_zero); + const int16x8_t v_iscan_plus1 = vaddq_s16(v_iscan, v_one); + const int16x8_t v_nz_iscan = vbslq_s16(v_nz_mask, v_zero, v_iscan_plus1); + const int16x8_t v_qcoeff_a = veorq_s16(v_tmp2, v_coeff_sign); + const int16x8_t v_qcoeff = vsubq_s16(v_qcoeff_a, v_coeff_sign); + calculate_dqcoeff_lp_and_store(v_qcoeff, v_dequant, dqcoeff_ptr + i); + v_eobmax_76543210 = vmaxq_s16(v_eobmax_76543210, v_nz_iscan); + vst1q_s16(qcoeff_ptr + i, v_qcoeff); + } +#ifdef __aarch64__ + *eob_ptr = vmaxvq_s16(v_eobmax_76543210); +#else + { + const int16x4_t v_eobmax_3210 = vmax_s16(vget_low_s16(v_eobmax_76543210), + vget_high_s16(v_eobmax_76543210)); + const int64x1_t v_eobmax_xx32 = + vshr_n_s64(vreinterpret_s64_s16(v_eobmax_3210), 32); + const int16x4_t v_eobmax_tmp = + vmax_s16(v_eobmax_3210, vreinterpret_s16_s64(v_eobmax_xx32)); + const int64x1_t v_eobmax_xxx3 = + vshr_n_s64(vreinterpret_s64_s16(v_eobmax_tmp), 16); + const int16x4_t v_eobmax_final = + vmax_s16(v_eobmax_tmp, vreinterpret_s16_s64(v_eobmax_xxx3)); + + *eob_ptr = (uint16_t)vget_lane_s16(v_eobmax_final, 0); + } +#endif // __aarch64__ +} diff --git a/media/libaom/src/av1/encoder/av1_fwd_txfm1d.c b/media/libaom/src/av1/encoder/av1_fwd_txfm1d.c index 98505e0b1a..6601c19ab3 100644 --- a/media/libaom/src/av1/encoder/av1_fwd_txfm1d.c +++ b/media/libaom/src/av1/encoder/av1_fwd_txfm1d.c @@ -13,8 +13,8 @@ #include "av1/encoder/av1_fwd_txfm1d.h" #include "av1/common/av1_txfm.h" -void av1_fdct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fdct4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 4; const int32_t *cospi; @@ -56,8 +56,8 @@ void av1_fdct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); } -void av1_fdct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fdct8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 8; const int32_t *cospi; @@ -141,8 +141,8 @@ void av1_fdct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); } -void av1_fdct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fdct16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 16; const int32_t *cospi; @@ -312,8 +312,8 @@ void av1_fdct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); } -void av1_fdct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fdct32(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 32; const int32_t *cospi; @@ -673,8 +673,8 @@ void av1_fdct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); } -void av1_fadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fadst4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { int bit = cos_bit; const int32_t *sinpi = sinpi_arr(bit); int32_t x0, x1, x2, x3; @@ -732,8 +732,8 @@ void av1_fadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(6, input, output, 4, stage_range[6]); } -void av1_fadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fadst8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 8; const int32_t *cospi; @@ -846,8 +846,8 @@ void av1_fadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(stage, input, bf1, size, stage_range[stage]); } -void av1_fadst16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fadst16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 16; const int32_t *cospi; @@ -1093,8 +1093,8 @@ void av1_fidentity32_c(const int32_t *input, int32_t *output, int8_t cos_bit, av1_range_check_buf(0, input, output, 32, stage_range[0]); } -void av1_fdct64_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range) { +void av1_fdct64(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range) { const int32_t size = 64; const int32_t *cospi; diff --git a/media/libaom/src/av1/encoder/av1_fwd_txfm1d.h b/media/libaom/src/av1/encoder/av1_fwd_txfm1d.h index 9dcf16552c..9ef54fe4de 100644 --- a/media/libaom/src/av1/encoder/av1_fwd_txfm1d.h +++ b/media/libaom/src/av1/encoder/av1_fwd_txfm1d.h @@ -18,22 +18,22 @@ extern "C" { #endif -void av1_fdct4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fdct8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fdct16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fdct32_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fdct64_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fadst4_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fadst8_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); -void av1_fadst16_new(const int32_t *input, int32_t *output, int8_t cos_bit, - const int8_t *stage_range); +void av1_fdct4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fdct8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fdct16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fdct32(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fdct64(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fadst4(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fadst8(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); +void av1_fadst16(const int32_t *input, int32_t *output, int8_t cos_bit, + const int8_t *stage_range); void av1_fidentity4_c(const int32_t *input, int32_t *output, int8_t cos_bit, const int8_t *stage_range); void av1_fidentity8_c(const int32_t *input, int32_t *output, int8_t cos_bit, diff --git a/media/libaom/src/av1/encoder/av1_fwd_txfm2d.c b/media/libaom/src/av1/encoder/av1_fwd_txfm2d.c index 642728a527..bcb829d79d 100644 --- a/media/libaom/src/av1/encoder/av1_fwd_txfm2d.c +++ b/media/libaom/src/av1/encoder/av1_fwd_txfm2d.c @@ -22,14 +22,14 @@ static INLINE TxfmFunc fwd_txfm_type_to_func(TXFM_TYPE txfm_type) { switch (txfm_type) { - case TXFM_TYPE_DCT4: return av1_fdct4_new; - case TXFM_TYPE_DCT8: return av1_fdct8_new; - case TXFM_TYPE_DCT16: return av1_fdct16_new; - case TXFM_TYPE_DCT32: return av1_fdct32_new; - case TXFM_TYPE_DCT64: return av1_fdct64_new; - case TXFM_TYPE_ADST4: return av1_fadst4_new; - case TXFM_TYPE_ADST8: return av1_fadst8_new; - case TXFM_TYPE_ADST16: return av1_fadst16_new; + case TXFM_TYPE_DCT4: return av1_fdct4; + case TXFM_TYPE_DCT8: return av1_fdct8; + case TXFM_TYPE_DCT16: return av1_fdct16; + case TXFM_TYPE_DCT32: return av1_fdct32; + case TXFM_TYPE_DCT64: return av1_fdct64; + case TXFM_TYPE_ADST4: return av1_fadst4; + case TXFM_TYPE_ADST8: return av1_fadst8; + case TXFM_TYPE_ADST16: return av1_fadst16; case TXFM_TYPE_IDENTITY4: return av1_fidentity4_c; case TXFM_TYPE_IDENTITY8: return av1_fidentity8_c; case TXFM_TYPE_IDENTITY16: return av1_fidentity16_c; @@ -416,8 +416,8 @@ void av1_get_fwd_txfm_cfg(TX_TYPE tx_type, TX_SIZE tx_size, set_flip_cfg(tx_type, cfg); const TX_TYPE_1D tx_type_1d_col = vtx_tab[tx_type]; const TX_TYPE_1D tx_type_1d_row = htx_tab[tx_type]; - const int txw_idx = tx_size_wide_log2[tx_size] - tx_size_wide_log2[0]; - const int txh_idx = tx_size_high_log2[tx_size] - tx_size_high_log2[0]; + const int txw_idx = get_txw_idx(tx_size); + const int txh_idx = get_txh_idx(tx_size); cfg->shift = av1_fwd_txfm_shift_ls[tx_size]; cfg->cos_bit_col = av1_fwd_cos_bit_col[txw_idx][txh_idx]; cfg->cos_bit_row = av1_fwd_cos_bit_row[txw_idx][txh_idx]; diff --git a/media/libaom/src/av1/encoder/av1_multi_thread.c b/media/libaom/src/av1/encoder/av1_multi_thread.c index 1260c7af7c..d170b0c282 100644 --- a/media/libaom/src/av1/encoder/av1_multi_thread.c +++ b/media/libaom/src/av1/encoder/av1_multi_thread.c @@ -19,8 +19,8 @@ void av1_row_mt_mem_alloc(AV1_COMP *cpi, int max_sb_rows) { struct AV1Common *cm = &cpi->common; MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt; int tile_row, tile_col; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; multi_thread_ctxt->allocated_tile_cols = tile_cols; multi_thread_ctxt->allocated_tile_rows = tile_rows; diff --git a/media/libaom/src/av1/encoder/av1_quantize.c b/media/libaom/src/av1/encoder/av1_quantize.c index 372bbdcd92..569784a2af 100644 --- a/media/libaom/src/av1/encoder/av1_quantize.c +++ b/media/libaom/src/av1/encoder/av1_quantize.c @@ -57,7 +57,7 @@ static void quantize_fp_helper_c( const int rc = scan[i]; const int32_t thresh = (int32_t)(dequant_ptr[rc != 0]); const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int tmp32 = 0; if ((abs_coeff << (1 + log_scale)) >= thresh) { @@ -84,7 +84,7 @@ static void quantize_fp_helper_c( const int dequant = (dequant_ptr[rc != 0] * iwt + (1 << (AOM_QM_BITS - 1))) >> AOM_QM_BITS; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int tmp32 = 0; if (abs_coeff * wt >= @@ -132,7 +132,7 @@ static void highbd_quantize_fp_helper_c( const int dequant = (dequant_ptr[rc != 0] * iwt + (1 << (AOM_QM_BITS - 1))) >> AOM_QM_BITS; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int abs_qcoeff = 0; if (abs_coeff * wt >= @@ -159,7 +159,7 @@ static void highbd_quantize_fp_helper_c( const int rc = scan[i]; const int coeff = coeff_ptr[rc]; const int rc01 = (rc != 0); - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int log_scaled_round = log_scaled_round_arr[rc01]; if ((abs_coeff << (1 + log_scale)) >= dequant_ptr[rc01]) { @@ -192,6 +192,35 @@ void av1_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, eob_ptr, scan, iscan, NULL, NULL, 0); } +void av1_quantize_lp_c(const int16_t *coeff_ptr, intptr_t n_coeffs, + const int16_t *round_ptr, const int16_t *quant_ptr, + int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr, + const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan) { + int eob = -1; + + memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr)); + memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr)); + + // Quantization pass: All coefficients with index >= zero_flag are + // skippable. Note: zero_flag can be zero. + for (int i = 0; i < n_coeffs; i++) { + const int rc = scan[i]; + const int coeff = coeff_ptr[rc]; + const int coeff_sign = AOMSIGN(coeff); + const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; + + int tmp = clamp(abs_coeff + round_ptr[rc != 0], INT16_MIN, INT16_MAX); + tmp = (tmp * quant_ptr[rc != 0]) >> 16; + + qcoeff_ptr[rc] = (tmp ^ coeff_sign) - coeff_sign; + dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0]; + + if (tmp) eob = i; + } + *eob_ptr = eob + 1; +} + void av1_quantize_fp_32x32_c(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, @@ -329,7 +358,7 @@ static void quantize_dc(const tran_low_t *coeff_ptr, int n_coeffs, const qm_val_t *iqm_ptr, const int log_scale) { const int rc = 0; const int coeff = coeff_ptr[rc]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; int64_t tmp; int eob = -1; @@ -474,7 +503,7 @@ static INLINE void highbd_quantize_dc( const qm_val_t wt = qm_ptr != NULL ? qm_ptr[0] : (1 << AOM_QM_BITS); const qm_val_t iwt = iqm_ptr != NULL ? iqm_ptr[0] : (1 << AOM_QM_BITS); const int coeff = coeff_ptr[0]; - const int coeff_sign = (coeff >> 31); + const int coeff_sign = AOMSIGN(coeff); const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign; const int64_t tmp = abs_coeff + ROUND_POWER_OF_TWO(round_ptr[0], log_scale); const int64_t tmpw = tmp * wt; @@ -619,78 +648,84 @@ void av1_build_quantizer(aom_bit_depth_t bit_depth, int y_dc_delta_q, } } -void av1_init_quantizer(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - QUANTS *const quants = &cpi->quants; - Dequants *const dequants = &cpi->dequants; - av1_build_quantizer(cm->seq_params.bit_depth, cm->y_dc_delta_q, - cm->u_dc_delta_q, cm->u_ac_delta_q, cm->v_dc_delta_q, - cm->v_ac_delta_q, quants, dequants); +void av1_init_quantizer(EncQuantDequantParams *const enc_quant_dequant_params, + const CommonQuantParams *quant_params, + aom_bit_depth_t bit_depth) { + QUANTS *const quants = &enc_quant_dequant_params->quants; + Dequants *const dequants = &enc_quant_dequant_params->dequants; + av1_build_quantizer(bit_depth, quant_params->y_dc_delta_q, + quant_params->u_dc_delta_q, quant_params->u_ac_delta_q, + quant_params->v_dc_delta_q, quant_params->v_ac_delta_q, + quants, dequants); } void av1_init_plane_quantizers(const AV1_COMP *cpi, MACROBLOCK *x, int segment_id) { const AV1_COMMON *const cm = &cpi->common; + const CommonQuantParams *const quant_params = &cm->quant_params; MACROBLOCKD *const xd = &x->e_mbd; - const QUANTS *const quants = &cpi->quants; + const QUANTS *const quants = &cpi->enc_quant_dequant_params.quants; + const Dequants *const dequants = &cpi->enc_quant_dequant_params.dequants; - int current_qindex = AOMMAX( - 0, AOMMIN(QINDEX_RANGE - 1, cm->delta_q_info.delta_q_present_flag - ? cm->base_qindex + xd->delta_qindex - : cm->base_qindex)); + const int current_qindex = + AOMMAX(0, AOMMIN(QINDEX_RANGE - 1, + cm->delta_q_info.delta_q_present_flag + ? quant_params->base_qindex + xd->delta_qindex + : quant_params->base_qindex)); const int qindex = av1_get_qindex(&cm->seg, segment_id, current_qindex); - const int rdmult = av1_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q); - int qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) - ? NUM_QM_LEVELS - 1 - : cm->qm_y; + const int rdmult = + av1_compute_rd_mult(cpi, qindex + quant_params->y_dc_delta_q); + const int use_qmatrix = av1_use_qmatrix(quant_params, xd, segment_id); // Y + const int qmlevel_y = + use_qmatrix ? quant_params->qmatrix_level_y : NUM_QM_LEVELS - 1; x->plane[0].quant_QTX = quants->y_quant[qindex]; x->plane[0].quant_fp_QTX = quants->y_quant_fp[qindex]; x->plane[0].round_fp_QTX = quants->y_round_fp[qindex]; x->plane[0].quant_shift_QTX = quants->y_quant_shift[qindex]; x->plane[0].zbin_QTX = quants->y_zbin[qindex]; x->plane[0].round_QTX = quants->y_round[qindex]; - x->plane[0].dequant_QTX = cpi->dequants.y_dequant_QTX[qindex]; - memcpy(&xd->plane[0].seg_qmatrix[segment_id], cm->gqmatrix[qmlevel][0], - sizeof(cm->gqmatrix[qmlevel][0])); - memcpy(&xd->plane[0].seg_iqmatrix[segment_id], cm->giqmatrix[qmlevel][0], - sizeof(cm->giqmatrix[qmlevel][0])); + x->plane[0].dequant_QTX = dequants->y_dequant_QTX[qindex]; + memcpy(&xd->plane[0].seg_qmatrix[segment_id], + quant_params->gqmatrix[qmlevel_y][0], + sizeof(quant_params->gqmatrix[qmlevel_y][0])); + memcpy(&xd->plane[0].seg_iqmatrix[segment_id], + quant_params->giqmatrix[qmlevel_y][0], + sizeof(quant_params->giqmatrix[qmlevel_y][0])); // U - qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) - ? NUM_QM_LEVELS - 1 - : cm->qm_u; - { - x->plane[1].quant_QTX = quants->u_quant[qindex]; - x->plane[1].quant_fp_QTX = quants->u_quant_fp[qindex]; - x->plane[1].round_fp_QTX = quants->u_round_fp[qindex]; - x->plane[1].quant_shift_QTX = quants->u_quant_shift[qindex]; - x->plane[1].zbin_QTX = quants->u_zbin[qindex]; - x->plane[1].round_QTX = quants->u_round[qindex]; - x->plane[1].dequant_QTX = cpi->dequants.u_dequant_QTX[qindex]; - memcpy(&xd->plane[1].seg_qmatrix[segment_id], cm->gqmatrix[qmlevel][1], - sizeof(cm->gqmatrix[qmlevel][1])); - memcpy(&xd->plane[1].seg_iqmatrix[segment_id], cm->giqmatrix[qmlevel][1], - sizeof(cm->giqmatrix[qmlevel][1])); - } + const int qmlevel_u = + use_qmatrix ? quant_params->qmatrix_level_u : NUM_QM_LEVELS - 1; + x->plane[1].quant_QTX = quants->u_quant[qindex]; + x->plane[1].quant_fp_QTX = quants->u_quant_fp[qindex]; + x->plane[1].round_fp_QTX = quants->u_round_fp[qindex]; + x->plane[1].quant_shift_QTX = quants->u_quant_shift[qindex]; + x->plane[1].zbin_QTX = quants->u_zbin[qindex]; + x->plane[1].round_QTX = quants->u_round[qindex]; + x->plane[1].dequant_QTX = dequants->u_dequant_QTX[qindex]; + memcpy(&xd->plane[1].seg_qmatrix[segment_id], + quant_params->gqmatrix[qmlevel_u][1], + sizeof(quant_params->gqmatrix[qmlevel_u][1])); + memcpy(&xd->plane[1].seg_iqmatrix[segment_id], + quant_params->giqmatrix[qmlevel_u][1], + sizeof(quant_params->giqmatrix[qmlevel_u][1])); // V - qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) - ? NUM_QM_LEVELS - 1 - : cm->qm_v; - { - x->plane[2].quant_QTX = quants->v_quant[qindex]; - x->plane[2].quant_fp_QTX = quants->v_quant_fp[qindex]; - x->plane[2].round_fp_QTX = quants->v_round_fp[qindex]; - x->plane[2].quant_shift_QTX = quants->v_quant_shift[qindex]; - x->plane[2].zbin_QTX = quants->v_zbin[qindex]; - x->plane[2].round_QTX = quants->v_round[qindex]; - x->plane[2].dequant_QTX = cpi->dequants.v_dequant_QTX[qindex]; - memcpy(&xd->plane[2].seg_qmatrix[segment_id], cm->gqmatrix[qmlevel][2], - sizeof(cm->gqmatrix[qmlevel][2])); - memcpy(&xd->plane[2].seg_iqmatrix[segment_id], cm->giqmatrix[qmlevel][2], - sizeof(cm->giqmatrix[qmlevel][2])); - } + const int qmlevel_v = + use_qmatrix ? quant_params->qmatrix_level_v : NUM_QM_LEVELS - 1; + x->plane[2].quant_QTX = quants->v_quant[qindex]; + x->plane[2].quant_fp_QTX = quants->v_quant_fp[qindex]; + x->plane[2].round_fp_QTX = quants->v_round_fp[qindex]; + x->plane[2].quant_shift_QTX = quants->v_quant_shift[qindex]; + x->plane[2].zbin_QTX = quants->v_zbin[qindex]; + x->plane[2].round_QTX = quants->v_round[qindex]; + x->plane[2].dequant_QTX = dequants->v_dequant_QTX[qindex]; + memcpy(&xd->plane[2].seg_qmatrix[segment_id], + quant_params->gqmatrix[qmlevel_v][2], + sizeof(quant_params->gqmatrix[qmlevel_v][2])); + memcpy(&xd->plane[2].seg_iqmatrix[segment_id], + quant_params->giqmatrix[qmlevel_v][2], + sizeof(quant_params->giqmatrix[qmlevel_v][2])); x->skip_block = segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP); x->qindex = qindex; @@ -705,24 +740,29 @@ void av1_frame_init_quantizer(AV1_COMP *cpi) { av1_init_plane_quantizers(cpi, x, xd->mi[0]->segment_id); } -void av1_set_quantizer(AV1_COMMON *cm, int q) { +void av1_set_quantizer(AV1_COMMON *const cm, int min_qmlevel, int max_qmlevel, + int q) { // quantizer has to be reinitialized with av1_init_quantizer() if any // delta_q changes. - cm->base_qindex = AOMMAX(cm->delta_q_info.delta_q_present_flag, q); - cm->y_dc_delta_q = 0; - cm->u_dc_delta_q = 0; - cm->u_ac_delta_q = 0; - cm->v_dc_delta_q = 0; - cm->v_ac_delta_q = 0; - cm->qm_y = aom_get_qmlevel(cm->base_qindex, cm->min_qmlevel, cm->max_qmlevel); - cm->qm_u = aom_get_qmlevel(cm->base_qindex + cm->u_ac_delta_q, - cm->min_qmlevel, cm->max_qmlevel); + CommonQuantParams *quant_params = &cm->quant_params; + quant_params->base_qindex = AOMMAX(cm->delta_q_info.delta_q_present_flag, q); + quant_params->y_dc_delta_q = 0; + quant_params->u_dc_delta_q = 0; + quant_params->u_ac_delta_q = 0; + quant_params->v_dc_delta_q = 0; + quant_params->v_ac_delta_q = 0; + quant_params->qmatrix_level_y = + aom_get_qmlevel(quant_params->base_qindex, min_qmlevel, max_qmlevel); + quant_params->qmatrix_level_u = + aom_get_qmlevel(quant_params->base_qindex + quant_params->u_ac_delta_q, + min_qmlevel, max_qmlevel); if (!cm->seq_params.separate_uv_delta_q) - cm->qm_v = cm->qm_u; + quant_params->qmatrix_level_v = quant_params->qmatrix_level_u; else - cm->qm_v = aom_get_qmlevel(cm->base_qindex + cm->v_ac_delta_q, - cm->min_qmlevel, cm->max_qmlevel); + quant_params->qmatrix_level_v = + aom_get_qmlevel(quant_params->base_qindex + quant_params->v_ac_delta_q, + min_qmlevel, max_qmlevel); } // Table that converts 0-63 Q-range values passed in outside to the Qindex diff --git a/media/libaom/src/av1/encoder/av1_quantize.h b/media/libaom/src/av1/encoder/av1_quantize.h index d4fa0b2601..40fb4bee89 100644 --- a/media/libaom/src/av1/encoder/av1_quantize.h +++ b/media/libaom/src/av1/encoder/av1_quantize.h @@ -31,6 +31,8 @@ typedef struct QUANT_PARAM { const qm_val_t *qmatrix; const qm_val_t *iqmatrix; int use_quant_b_adapt; + int use_optimize_b; + int xform_quant_idx; } QUANT_PARAM; typedef void (*AV1_QUANT_FACADE)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, @@ -82,6 +84,13 @@ typedef struct { v_dequant_QTX[QINDEX_RANGE][8]); // 8: SIMD width } Dequants; +typedef struct { + // Quantization parameters for internal quantizer setup. + QUANTS quants; + // Dequantization parameters for internal quantizer setup. + Dequants dequants; +} EncQuantDequantParams; + struct AV1_COMP; struct AV1Common; @@ -95,9 +104,12 @@ void av1_build_quantizer(aom_bit_depth_t bit_depth, int y_dc_delta_q, int v_ac_delta_q, QUANTS *const quants, Dequants *const deq); -void av1_init_quantizer(struct AV1_COMP *cpi); +void av1_init_quantizer(EncQuantDequantParams *const enc_quant_dequant_params, + const CommonQuantParams *quant_params, + aom_bit_depth_t bit_depth); -void av1_set_quantizer(struct AV1Common *cm, int q); +void av1_set_quantizer(struct AV1Common *const cm, int min_qmlevel, + int max_qmlevel, int q); int av1_quantizer_to_qindex(int quantizer); diff --git a/media/libaom/src/av1/encoder/bitstream.c b/media/libaom/src/av1/encoder/bitstream.c index f3f5a7680d..daa8ce1fc4 100644 --- a/media/libaom/src/av1/encoder/bitstream.c +++ b/media/libaom/src/av1/encoder/bitstream.c @@ -269,9 +269,9 @@ static AOM_INLINE void write_motion_mode(const AV1_COMMON *cm, MACROBLOCKD *xd, const MB_MODE_INFO *mbmi, aom_writer *w) { MOTION_MODE last_motion_mode_allowed = - cm->switchable_motion_mode + cm->features.switchable_motion_mode ? motion_mode_allowed(cm->global_motion, xd, mbmi, - cm->allow_warped_motion) + cm->features.allow_warped_motion) : SIMPLE_TRANSLATION; assert(mbmi->motion_mode <= last_motion_mode_allowed); switch (last_motion_mode_allowed) { @@ -399,20 +399,20 @@ static AOM_INLINE void pack_txb_tokens( } } -static INLINE void set_spatial_segment_id(const AV1_COMMON *const cm, - uint8_t *segment_ids, - BLOCK_SIZE bsize, int mi_row, - int mi_col, int segment_id) { - const int mi_offset = mi_row * cm->mi_cols + mi_col; +static INLINE void set_spatial_segment_id( + const CommonModeInfoParams *const mi_params, uint8_t *segment_ids, + BLOCK_SIZE bsize, int mi_row, int mi_col, int segment_id) { + const int mi_offset = mi_row * mi_params->mi_cols + mi_col; const int bw = mi_size_wide[bsize]; const int bh = mi_size_high[bsize]; - const int xmis = AOMMIN(cm->mi_cols - mi_col, bw); - const int ymis = AOMMIN(cm->mi_rows - mi_row, bh); - int x, y; + const int xmis = AOMMIN(mi_params->mi_cols - mi_col, bw); + const int ymis = AOMMIN(mi_params->mi_rows - mi_row, bh); - for (y = 0; y < ymis; ++y) - for (x = 0; x < xmis; ++x) - segment_ids[mi_offset + y * cm->mi_cols + x] = segment_id; + for (int y = 0; y < ymis; ++y) { + for (int x = 0; x < xmis; ++x) { + segment_ids[mi_offset + y * mi_params->mi_cols + x] = segment_id; + } + } } int av1_neg_interleave(int x, int ref, int max) { @@ -439,29 +439,28 @@ int av1_neg_interleave(int x, int ref, int max) { } } -static AOM_INLINE void write_segment_id(AV1_COMP *cpi, - const MB_MODE_INFO *const mbmi, - aom_writer *w, - const struct segmentation *seg, - struct segmentation_probs *segp, - int mi_row, int mi_col, int skip) { +static AOM_INLINE void write_segment_id( + AV1_COMP *cpi, const MB_MODE_INFO *const mbmi, aom_writer *w, + const struct segmentation *seg, struct segmentation_probs *segp, int skip) { if (!seg->enabled || !seg->update_map) return; AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; int cdf_num; - const int pred = av1_get_spatial_seg_pred(cm, xd, mi_row, mi_col, &cdf_num); + const int pred = av1_get_spatial_seg_pred(cm, xd, &cdf_num); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (skip) { // Still need to transmit tx size for intra blocks even if skip is // true. Changing segment_id may make the tx size become invalid, e.g // changing from lossless to lossy. - assert(is_inter_block(mbmi) || !cpi->has_lossless_segment); + assert(is_inter_block(mbmi) || !cpi->enc_seg.has_lossless_segment); - set_spatial_segment_id(cm, cm->cur_frame->seg_map, mbmi->sb_type, mi_row, - mi_col, pred); - set_spatial_segment_id(cm, cpi->segmentation_map, mbmi->sb_type, mi_row, - mi_col, pred); + set_spatial_segment_id(&cm->mi_params, cm->cur_frame->seg_map, + mbmi->sb_type, mi_row, mi_col, pred); + set_spatial_segment_id(&cm->mi_params, cpi->enc_seg.map, mbmi->sb_type, + mi_row, mi_col, pred); /* mbmi is read only but we need to update segment_id */ ((MB_MODE_INFO *)mbmi)->segment_id = pred; return; @@ -471,8 +470,8 @@ static AOM_INLINE void write_segment_id(AV1_COMP *cpi, av1_neg_interleave(mbmi->segment_id, pred, seg->last_active_segid + 1); aom_cdf_prob *pred_cdf = segp->spatial_pred_seg_cdf[cdf_num]; aom_write_symbol(w, coded_id, pred_cdf, MAX_SEGMENTS); - set_spatial_segment_id(cm, cm->cur_frame->seg_map, mbmi->sb_type, mi_row, - mi_col, mbmi->segment_id); + set_spatial_segment_id(&cm->mi_params, cm->cur_frame->seg_map, mbmi->sb_type, + mi_row, mi_col, mbmi->segment_id); } #define WRITE_REF_BIT(bname, pname) \ @@ -604,21 +603,20 @@ static AOM_INLINE void write_angle_delta(aom_writer *w, int angle_delta, 2 * MAX_ANGLE_DELTA + 1); } -static AOM_INLINE void write_mb_interp_filter(AV1_COMP *cpi, +static AOM_INLINE void write_mb_interp_filter(AV1_COMMON *const cm, const MACROBLOCKD *xd, aom_writer *w) { - AV1_COMMON *const cm = &cpi->common; const MB_MODE_INFO *const mbmi = xd->mi[0]; FRAME_CONTEXT *ec_ctx = xd->tile_ctx; if (!av1_is_interp_needed(xd)) { - int_interpfilters filters = - av1_broadcast_interp_filter(av1_unswitchable_filter(cm->interp_filter)); + int_interpfilters filters = av1_broadcast_interp_filter( + av1_unswitchable_filter(cm->features.interp_filter)); assert(mbmi->interp_filters.as_int == filters.as_int); (void)filters; return; } - if (cm->interp_filter == SWITCHABLE) { + if (cm->features.interp_filter == SWITCHABLE) { int dir; for (dir = 0; dir < 2; ++dir) { const int ctx = av1_get_pred_context_switchable_interp(xd, dir); @@ -753,11 +751,10 @@ static AOM_INLINE void write_palette_colors_uv( static AOM_INLINE void write_palette_mode_info(const AV1_COMMON *cm, const MACROBLOCKD *xd, const MB_MODE_INFO *const mbmi, - int mi_row, int mi_col, aom_writer *w) { const int num_planes = av1_num_planes(cm); const BLOCK_SIZE bsize = mbmi->sb_type; - assert(av1_allow_palette(cm->allow_screen_content_tools, bsize)); + assert(av1_allow_palette(cm->features.allow_screen_content_tools, bsize)); const PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); @@ -776,9 +773,7 @@ static AOM_INLINE void write_palette_mode_info(const AV1_COMMON *cm, } const int uv_dc_pred = - num_planes > 1 && mbmi->uv_mode == UV_DC_PRED && - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y); + num_planes > 1 && mbmi->uv_mode == UV_DC_PRED && xd->is_chroma_ref; if (uv_dc_pred) { const int n = pmi->palette_size[1]; const int palette_uv_mode_ctx = (pmi->palette_size[0] > 0); @@ -796,17 +791,19 @@ static AOM_INLINE void write_palette_mode_info(const AV1_COMMON *cm, void av1_write_tx_type(const AV1_COMMON *const cm, const MACROBLOCKD *xd, TX_TYPE tx_type, TX_SIZE tx_size, aom_writer *w) { MB_MODE_INFO *mbmi = xd->mi[0]; + const FeatureFlags *const features = &cm->features; const int is_inter = is_inter_block(mbmi); - if (get_ext_tx_types(tx_size, is_inter, cm->reduced_tx_set_used) > 1 && - ((!cm->seg.enabled && cm->base_qindex > 0) || + if (get_ext_tx_types(tx_size, is_inter, features->reduced_tx_set_used) > 1 && + ((!cm->seg.enabled && cm->quant_params.base_qindex > 0) || (cm->seg.enabled && xd->qindex[mbmi->segment_id] > 0)) && !mbmi->skip && !segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { FRAME_CONTEXT *ec_ctx = xd->tile_ctx; const TX_SIZE square_tx_size = txsize_sqr_map[tx_size]; - const TxSetType tx_set_type = - av1_get_ext_tx_set_type(tx_size, is_inter, cm->reduced_tx_set_used); - const int eset = get_ext_tx_set(tx_size, is_inter, cm->reduced_tx_set_used); + const TxSetType tx_set_type = av1_get_ext_tx_set_type( + tx_size, is_inter, features->reduced_tx_set_used); + const int eset = + get_ext_tx_set(tx_size, is_inter, features->reduced_tx_set_used); // eset == 0 should correspond to a set with only DCT_DCT and there // is no need to send the tx_type assert(eset > 0); @@ -863,38 +860,53 @@ static AOM_INLINE void write_cfl_alphas(FRAME_CONTEXT *const ec_ctx, } static AOM_INLINE void write_cdef(AV1_COMMON *cm, MACROBLOCKD *const xd, - aom_writer *w, int skip, int mi_col, - int mi_row) { - if (cm->coded_lossless || cm->allow_intrabc) return; + aom_writer *w, int skip) { + if (cm->features.coded_lossless || cm->features.allow_intrabc) return; - const int m = ~((1 << (6 - MI_SIZE_LOG2)) - 1); - const MB_MODE_INFO *mbmi = - cm->mi_grid_base[(mi_row & m) * cm->mi_stride + (mi_col & m)]; - // Initialise when at top left part of the superblock - if (!(mi_row & (cm->seq_params.mib_size - 1)) && - !(mi_col & (cm->seq_params.mib_size - 1))) { // Top left? - xd->cdef_preset[0] = xd->cdef_preset[1] = xd->cdef_preset[2] = - xd->cdef_preset[3] = -1; + // At the start of a superblock, mark that we haven't yet written CDEF + // strengths for any of the CDEF units contained in this superblock. + const int sb_mask = (cm->seq_params.mib_size - 1); + const int mi_row_in_sb = (xd->mi_row & sb_mask); + const int mi_col_in_sb = (xd->mi_col & sb_mask); + if (mi_row_in_sb == 0 && mi_col_in_sb == 0) { + xd->cdef_transmitted[0] = xd->cdef_transmitted[1] = + xd->cdef_transmitted[2] = xd->cdef_transmitted[3] = false; } - // Emit CDEF param at first non-skip coding block - const int mask = 1 << (6 - MI_SIZE_LOG2); - const int index = cm->seq_params.sb_size == BLOCK_128X128 - ? !!(mi_col & mask) + 2 * !!(mi_row & mask) + // CDEF unit size is 64x64 irrespective of the superblock size. + const int cdef_size = 1 << (6 - MI_SIZE_LOG2); + + // Find index of this CDEF unit in this superblock. + const int index_mask = cdef_size; + const int cdef_unit_row_in_sb = ((xd->mi_row & index_mask) != 0); + const int cdef_unit_col_in_sb = ((xd->mi_col & index_mask) != 0); + const int index = (cm->seq_params.sb_size == BLOCK_128X128) + ? cdef_unit_col_in_sb + 2 * cdef_unit_row_in_sb : 0; - if (xd->cdef_preset[index] == -1 && !skip) { + + // Write CDEF strength to the first non-skip coding block in this CDEF unit. + if (!xd->cdef_transmitted[index] && !skip) { + // CDEF strength for this CDEF unit needs to be stored in the MB_MODE_INFO + // of the 1st block in this CDEF unit. + const int first_block_mask = ~(cdef_size - 1); + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const int grid_idx = + get_mi_grid_idx(mi_params, xd->mi_row & first_block_mask, + xd->mi_col & first_block_mask); + const MB_MODE_INFO *const mbmi = mi_params->mi_grid_base[grid_idx]; aom_write_literal(w, mbmi->cdef_strength, cm->cdef_info.cdef_bits); - xd->cdef_preset[index] = mbmi->cdef_strength; + xd->cdef_transmitted[index] = true; } } static AOM_INLINE void write_inter_segment_id( AV1_COMP *cpi, aom_writer *w, const struct segmentation *const seg, - struct segmentation_probs *const segp, int mi_row, int mi_col, int skip, - int preskip) { + struct segmentation_probs *const segp, int skip, int preskip) { MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; AV1_COMMON *const cm = &cpi->common; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (seg->update_map) { if (preskip) { @@ -902,7 +914,7 @@ static AOM_INLINE void write_inter_segment_id( } else { if (seg->segid_preskip) return; if (skip) { - write_segment_id(cpi, mbmi, w, seg, segp, mi_row, mi_col, 1); + write_segment_id(cpi, mbmi, w, seg, segp, 1); if (seg->temporal_update) mbmi->seg_id_predicted = 0; return; } @@ -912,22 +924,21 @@ static AOM_INLINE void write_inter_segment_id( aom_cdf_prob *pred_cdf = av1_get_pred_cdf_seg_id(segp, xd); aom_write_symbol(w, pred_flag, pred_cdf, 2); if (!pred_flag) { - write_segment_id(cpi, mbmi, w, seg, segp, mi_row, mi_col, 0); + write_segment_id(cpi, mbmi, w, seg, segp, 0); } if (pred_flag) { - set_spatial_segment_id(cm, cm->cur_frame->seg_map, mbmi->sb_type, - mi_row, mi_col, mbmi->segment_id); + set_spatial_segment_id(&cm->mi_params, cm->cur_frame->seg_map, + mbmi->sb_type, mi_row, mi_col, mbmi->segment_id); } } else { - write_segment_id(cpi, mbmi, w, seg, segp, mi_row, mi_col, 0); + write_segment_id(cpi, mbmi, w, seg, segp, 0); } } } // If delta q is present, writes delta_q index. // Also writes delta_q loop filter levels, if present. -static AOM_INLINE void write_delta_q_params(AV1_COMP *cpi, const int mi_row, - const int mi_col, int skip, +static AOM_INLINE void write_delta_q_params(AV1_COMP *cpi, int skip, aom_writer *w) { AV1_COMMON *const cm = &cpi->common; const DeltaQInfo *const delta_q_info = &cm->delta_q_info; @@ -938,8 +949,8 @@ static AOM_INLINE void write_delta_q_params(AV1_COMP *cpi, const int mi_row, const MB_MODE_INFO *const mbmi = xd->mi[0]; const BLOCK_SIZE bsize = mbmi->sb_type; const int super_block_upper_left = - ((mi_row & (cm->seq_params.mib_size - 1)) == 0) && - ((mi_col & (cm->seq_params.mib_size - 1)) == 0); + ((xd->mi_row & (cm->seq_params.mib_size - 1)) == 0) && + ((xd->mi_col & (cm->seq_params.mib_size - 1)) == 0); if ((bsize != cm->seq_params.sb_size || skip == 0) && super_block_upper_left) { @@ -973,8 +984,6 @@ static AOM_INLINE void write_delta_q_params(AV1_COMP *cpi, const int mi_row, } static AOM_INLINE void write_intra_prediction_modes(AV1_COMP *cpi, - const int mi_row, - const int mi_col, int is_keyframe, aom_writer *w) { const AV1_COMMON *const cm = &cpi->common; @@ -1002,9 +1011,7 @@ static AOM_INLINE void write_intra_prediction_modes(AV1_COMP *cpi, } // UV mode and UV angle delta. - if (!cm->seq_params.monochrome && - is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y)) { + if (!cm->seq_params.monochrome && xd->is_chroma_ref) { const UV_PREDICTION_MODE uv_mode = mbmi->uv_mode; write_intra_uv_mode(ec_ctx, uv_mode, mode, is_cfl_allowed(xd), w); if (uv_mode == UV_CFL_PRED) @@ -1016,8 +1023,8 @@ static AOM_INLINE void write_intra_prediction_modes(AV1_COMP *cpi, } // Palette. - if (av1_allow_palette(cm->allow_screen_content_tools, bsize)) { - write_palette_mode_info(cm, xd, mbmi, mi_row, mi_col, w); + if (av1_allow_palette(cm->features.allow_screen_content_tools, bsize)) { + write_palette_mode_info(cm, xd, mbmi, w); } // Filter intra. @@ -1066,8 +1073,7 @@ static INLINE int_mv get_ref_mv(const MACROBLOCK *x, int ref_idx) { x->mbmi_ext_frame); } -static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, - const int mi_col, aom_writer *w) { +static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, aom_writer *w) { AV1_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->td.mb; MACROBLOCKD *const xd = &x->e_mbd; @@ -1079,12 +1085,12 @@ static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, const PREDICTION_MODE mode = mbmi->mode; const int segment_id = mbmi->segment_id; const BLOCK_SIZE bsize = mbmi->sb_type; - const int allow_hp = cm->allow_high_precision_mv; + const int allow_hp = cm->features.allow_high_precision_mv; const int is_inter = is_inter_block(mbmi); const int is_compound = has_second_ref(mbmi); int ref; - write_inter_segment_id(cpi, w, seg, segp, mi_row, mi_col, 0, 1); + write_inter_segment_id(cpi, w, seg, segp, 0, 1); write_skip_mode(cm, xd, segment_id, mbmi, w); @@ -1092,18 +1098,18 @@ static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, const int skip = mbmi->skip_mode ? 1 : write_skip(cm, xd, segment_id, mbmi, w); - write_inter_segment_id(cpi, w, seg, segp, mi_row, mi_col, skip, 0); + write_inter_segment_id(cpi, w, seg, segp, skip, 0); - write_cdef(cm, xd, w, skip, mi_col, mi_row); + write_cdef(cm, xd, w, skip); - write_delta_q_params(cpi, mi_row, mi_col, skip, w); + write_delta_q_params(cpi, skip, w); if (!mbmi->skip_mode) write_is_inter(cm, xd, mbmi->segment_id, w, is_inter); if (mbmi->skip_mode) return; if (!is_inter) { - write_intra_prediction_modes(cpi, mi_row, mi_col, 0, w); + write_intra_prediction_modes(cpi, 0, w); } else { int16_t mode_ctx; @@ -1154,12 +1160,12 @@ static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, aom_write_symbol(w, mbmi->interintra_mode, ec_ctx->interintra_mode_cdf[bsize_group], INTERINTRA_MODES); - if (is_interintra_wedge_used(bsize)) { + if (av1_is_wedge_used(bsize)) { aom_write_symbol(w, mbmi->use_wedge_interintra, ec_ctx->wedge_interintra_cdf[bsize], 2); if (mbmi->use_wedge_interintra) { aom_write_symbol(w, mbmi->interintra_wedge_index, - ec_ctx->wedge_idx_cdf[bsize], 16); + ec_ctx->wedge_idx_cdf[bsize], MAX_WEDGE_TYPES); } } } @@ -1210,7 +1216,7 @@ static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, if (mbmi->interinter_comp.type == COMPOUND_WEDGE) { assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize)); aom_write_symbol(w, mbmi->interinter_comp.wedge_index, - ec_ctx->wedge_idx_cdf[bsize], 16); + ec_ctx->wedge_idx_cdf[bsize], MAX_WEDGE_TYPES); aom_write_bit(w, mbmi->interinter_comp.wedge_sign); } else { assert(mbmi->interinter_comp.type == COMPOUND_DIFFWTD); @@ -1219,7 +1225,7 @@ static AOM_INLINE void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, } } } - write_mb_interp_filter(cpi, xd, w); + write_mb_interp_filter(cm, xd, w); } } @@ -1241,8 +1247,7 @@ static AOM_INLINE void write_intrabc_info( static AOM_INLINE void write_mb_modes_kf( AV1_COMP *cpi, MACROBLOCKD *xd, - const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame, const int mi_row, - const int mi_col, aom_writer *w) { + const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame, aom_writer *w) { AV1_COMMON *const cm = &cpi->common; FRAME_CONTEXT *ec_ctx = xd->tile_ctx; const struct segmentation *const seg = &cm->seg; @@ -1250,23 +1255,23 @@ static AOM_INLINE void write_mb_modes_kf( const MB_MODE_INFO *const mbmi = xd->mi[0]; if (seg->segid_preskip && seg->update_map) - write_segment_id(cpi, mbmi, w, seg, segp, mi_row, mi_col, 0); + write_segment_id(cpi, mbmi, w, seg, segp, 0); const int skip = write_skip(cm, xd, mbmi->segment_id, mbmi, w); if (!seg->segid_preskip && seg->update_map) - write_segment_id(cpi, mbmi, w, seg, segp, mi_row, mi_col, skip); + write_segment_id(cpi, mbmi, w, seg, segp, skip); - write_cdef(cm, xd, w, skip, mi_col, mi_row); + write_cdef(cm, xd, w, skip); - write_delta_q_params(cpi, mi_row, mi_col, skip, w); + write_delta_q_params(cpi, skip, w); if (av1_allow_intrabc(cm)) { write_intrabc_info(xd, mbmi_ext_frame, w); if (is_intrabc_block(mbmi)) return; } - write_intra_prediction_modes(cpi, mi_row, mi_col, 1, w); + write_intra_prediction_modes(cpi, 1, w); } #if CONFIG_RD_DEBUG @@ -1306,12 +1311,15 @@ static int rd_token_stats_mismatch(RD_STATS *rd_stats, TOKEN_STATS *token_stats, #endif #if ENC_MISMATCH_DEBUG -static AOM_INLINE void enc_dump_logs(AV1_COMP *cpi, int mi_row, int mi_col) { - AV1_COMMON *const cm = &cpi->common; - const MB_MODE_INFO *const mbmi = - *(cm->mi_grid_base + (mi_row * cm->mi_stride + mi_col)); - const MB_MODE_INFO_EXT_FRAME *const mbmi_ext_frame_base = - cpi->mbmi_ext_frame_base + get_mi_ext_idx(cm, mi_row, mi_col); +static AOM_INLINE void enc_dump_logs( + const AV1_COMMON *const cm, + const MBMIExtFrameBufferInfo *const mbmi_ext_info, int mi_row, int mi_col) { + const MB_MODE_INFO *const mbmi = *( + cm->mi_params.mi_grid_base + (mi_row * cm->mi_params.mi_stride + mi_col)); + const MB_MODE_INFO_EXT_FRAME *const mbmi_ext_frame = + mbmi_ext_info->frame_base + get_mi_ext_idx(mi_row, mi_col, + cm->mi_params.mi_alloc_bsize, + mbmi_ext_info->stride); if (is_inter_block(mbmi)) { #define FRAME_TO_CHECK 11 if (cm->current_frame.frame_number == FRAME_TO_CHECK && @@ -1359,14 +1367,13 @@ static AOM_INLINE void enc_dump_logs(AV1_COMP *cpi, int mi_row, int mi_col) { } #endif // ENC_MISMATCH_DEBUG -static AOM_INLINE void write_mbmi_b(AV1_COMP *cpi, aom_writer *w, int mi_row, - int mi_col) { +static AOM_INLINE void write_mbmi_b(AV1_COMP *cpi, aom_writer *w) { AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; MB_MODE_INFO *m = xd->mi[0]; if (frame_is_intra_only(cm)) { - write_mb_modes_kf(cpi, xd, cpi->td.mb.mbmi_ext_frame, mi_row, mi_col, w); + write_mb_modes_kf(cpi, xd, cpi->td.mb.mbmi_ext_frame, w); } else { // has_subpel_mv_component needs the ref frame buffers set up to look // up if they are scaled. has_subpel_mv_component is in turn needed by @@ -1374,10 +1381,10 @@ static AOM_INLINE void write_mbmi_b(AV1_COMP *cpi, aom_writer *w, int mi_row, set_ref_ptrs(cm, xd, m->ref_frame[0], m->ref_frame[1]); #if ENC_MISMATCH_DEBUG - enc_dump_logs(cpi, mi_row, mi_col); + enc_dump_logs(cm, &cpi->mbmi_ext_info, xd->mi_row, xd->mi_col); #endif // ENC_MISMATCH_DEBUG - pack_inter_mode_mvs(cpi, mi_row, mi_col, w); + pack_inter_mode_mvs(cpi, w); } } @@ -1390,37 +1397,25 @@ static AOM_INLINE void write_inter_txb_coeff( const struct macroblockd_plane *const pd = &xd->plane[plane]; const BLOCK_SIZE bsize = mbmi->sb_type; assert(bsize < BLOCK_SIZES_ALL); - const BLOCK_SIZE bsizec = - scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); - - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsizec, pd->subsampling_x, pd->subsampling_y); - + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, ss_x, ss_y); + assert(plane_bsize < BLOCK_SIZES_ALL); const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, plane); const int step = tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; const int bkw = tx_size_wide_unit[max_tx_size]; const int bkh = tx_size_high_unit[max_tx_size]; - const BLOCK_SIZE max_unit_bsize = - get_plane_block_size(BLOCK_64X64, pd->subsampling_x, pd->subsampling_y); - int mu_blocks_wide = block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; - - int blk_row, blk_col; - - assert(plane_bsize < BLOCK_SIZES_ALL); - const int num_4x4_w = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int num_4x4_h = block_size_high[plane_bsize] >> tx_size_high_log2[0]; - - const int unit_height = - AOMMIN(mu_blocks_high + (row >> pd->subsampling_y), num_4x4_h); - const int unit_width = - AOMMIN(mu_blocks_wide + (col >> pd->subsampling_x), num_4x4_w); - for (blk_row = row >> pd->subsampling_y; blk_row < unit_height; - blk_row += bkh) { - for (blk_col = col >> pd->subsampling_x; blk_col < unit_width; - blk_col += bkw) { + get_plane_block_size(BLOCK_64X64, ss_x, ss_y); + const int num_4x4_w = mi_size_wide[plane_bsize]; + const int num_4x4_h = mi_size_high[plane_bsize]; + const int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + const int mu_blocks_high = mi_size_high[max_unit_bsize]; + const int unit_height = AOMMIN(mu_blocks_high + (row >> ss_y), num_4x4_h); + const int unit_width = AOMMIN(mu_blocks_wide + (col >> ss_x), num_4x4_w); + for (int blk_row = row >> ss_y; blk_row < unit_height; blk_row += bkh) { + for (int blk_col = col >> ss_x; blk_col < unit_width; blk_col += bkw) { pack_txb_tokens(w, cm, x, tok, tok_end, xd, mbmi, plane, plane_bsize, cm->seq_params.bit_depth, *block, blk_row, blk_col, max_tx_size, token_stats); @@ -1431,8 +1426,7 @@ static AOM_INLINE void write_inter_txb_coeff( static AOM_INLINE void write_tokens_b(AV1_COMP *cpi, aom_writer *w, const TOKENEXTRA **tok, - const TOKENEXTRA *const tok_end, - int mi_row, int mi_col) { + const TOKENEXTRA *const tok_end) { AV1_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &cpi->td.mb; MACROBLOCKD *const xd = &x->e_mbd; @@ -1443,13 +1437,13 @@ static AOM_INLINE void write_tokens_b(AV1_COMP *cpi, aom_writer *w, const int is_inter = is_inter_block(mbmi); if (!is_inter) { - av1_write_coeffs_mb(cm, x, mi_row, mi_col, w, bsize); + av1_write_coeffs_mb(cm, x, w, bsize); } else { int block[MAX_MB_PLANE] = { 0 }; assert(bsize == get_plane_block_size(bsize, xd->plane[0].subsampling_x, xd->plane[0].subsampling_y)); - const int num_4x4_w = block_size_wide[bsize] >> tx_size_wide_log2[0]; - const int num_4x4_h = block_size_high[bsize] >> tx_size_high_log2[0]; + const int num_4x4_w = mi_size_wide[bsize]; + const int num_4x4_h = mi_size_high[bsize]; TOKEN_STATS token_stats; init_token_stats(&token_stats); @@ -1457,11 +1451,8 @@ static AOM_INLINE void write_tokens_b(AV1_COMP *cpi, aom_writer *w, assert(max_unit_bsize == get_plane_block_size(BLOCK_64X64, xd->plane[0].subsampling_x, xd->plane[0].subsampling_y)); - int mu_blocks_wide = - block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = - block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; - + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(num_4x4_w, mu_blocks_wide); mu_blocks_high = AOMMIN(num_4x4_h, mu_blocks_high); @@ -1469,11 +1460,7 @@ static AOM_INLINE void write_tokens_b(AV1_COMP *cpi, aom_writer *w, for (int row = 0; row < num_4x4_h; row += mu_blocks_high) { for (int col = 0; col < num_4x4_w; col += mu_blocks_wide) { for (int plane = 0; plane < num_planes; ++plane) { - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) { - continue; - } + if (plane && !xd->is_chroma_ref) break; write_inter_txb_coeff(cm, x, mbmi, w, tok, tok_end, &token_stats, row, col, &block[plane], plane); } @@ -1496,13 +1483,16 @@ static AOM_INLINE void write_modes_b(AV1_COMP *cpi, const TileInfo *const tile, const TOKENEXTRA *const tok_end, int mi_row, int mi_col) { const AV1_COMMON *cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; MACROBLOCKD *xd = &cpi->td.mb.e_mbd; - const int grid_idx = mi_row * cm->mi_stride + mi_col; - xd->mi = cm->mi_grid_base + grid_idx; + const int grid_idx = mi_row * mi_params->mi_stride + mi_col; + xd->mi = mi_params->mi_grid_base + grid_idx; cpi->td.mb.mbmi_ext_frame = - cpi->mbmi_ext_frame_base + get_mi_ext_idx(cm, mi_row, mi_col); - xd->tx_type_map = cm->tx_type_map + grid_idx; - xd->tx_type_map_stride = cm->mi_stride; + cpi->mbmi_ext_info.frame_base + + get_mi_ext_idx(mi_row, mi_col, cm->mi_params.mi_alloc_bsize, + cpi->mbmi_ext_info.stride); + xd->tx_type_map = mi_params->tx_type_map + grid_idx; + xd->tx_type_map_stride = mi_params->mi_stride; const MB_MODE_INFO *mbmi = xd->mi[0]; const BLOCK_SIZE bsize = mbmi->sb_type; @@ -1511,13 +1501,14 @@ static AOM_INLINE void write_modes_b(AV1_COMP *cpi, const TileInfo *const tile, const int bh = mi_size_high[bsize]; const int bw = mi_size_wide[bsize]; - set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols); + set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, mi_params->mi_rows, + mi_params->mi_cols); - xd->above_txfm_context = cm->above_txfm_context[tile->tile_row] + mi_col; + xd->above_txfm_context = cm->above_contexts.txfm[tile->tile_row] + mi_col; xd->left_txfm_context = xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); - write_mbmi_b(cpi, w, mi_row, mi_col); + write_mbmi_b(cpi, w); for (int plane = 0; plane < AOMMIN(2, av1_num_planes(cm)); ++plane) { const uint8_t palette_size_plane = @@ -1525,7 +1516,9 @@ static AOM_INLINE void write_modes_b(AV1_COMP *cpi, const TileInfo *const tile, assert(!mbmi->skip_mode || !palette_size_plane); if (palette_size_plane > 0) { assert(mbmi->use_intrabc == 0); - assert(av1_allow_palette(cm->allow_screen_content_tools, mbmi->sb_type)); + assert(av1_allow_palette(cm->features.allow_screen_content_tools, + mbmi->sb_type)); + assert(!plane || xd->is_chroma_ref); int rows, cols; av1_get_block_dimensions(mbmi->sb_type, plane, xd, NULL, NULL, &rows, &cols); @@ -1537,14 +1530,14 @@ static AOM_INLINE void write_modes_b(AV1_COMP *cpi, const TileInfo *const tile, const int is_inter_tx = is_inter_block(mbmi); const int skip = mbmi->skip; const int segment_id = mbmi->segment_id; - if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) && + if (cm->features.tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) && !(is_inter_tx && skip) && !xd->lossless[segment_id]) { if (is_inter_tx) { // This implies skip flag is 0. const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, bsize, 0); const int txbh = tx_size_high_unit[max_tx_size]; const int txbw = tx_size_wide_unit[max_tx_size]; - const int width = block_size_wide[bsize] >> tx_size_wide_log2[0]; - const int height = block_size_high[bsize] >> tx_size_high_log2[0]; + const int width = mi_size_wide[bsize]; + const int height = mi_size_high[bsize]; for (int idy = 0; idy < height; idy += txbh) { for (int idx = 0; idx < width; idx += txbw) { write_tx_size_vartx(xd, mbmi, max_tx_size, 0, idy, idx, w); @@ -1552,14 +1545,15 @@ static AOM_INLINE void write_modes_b(AV1_COMP *cpi, const TileInfo *const tile, } } else { write_selected_tx_size(xd, w); - set_txfm_ctxs(mbmi->tx_size, xd->n4_w, xd->n4_h, 0, xd); + set_txfm_ctxs(mbmi->tx_size, xd->width, xd->height, 0, xd); } } else { - set_txfm_ctxs(mbmi->tx_size, xd->n4_w, xd->n4_h, skip && is_inter_tx, xd); + set_txfm_ctxs(mbmi->tx_size, xd->width, xd->height, skip && is_inter_tx, + xd); } if (!mbmi->skip) { - write_tokens_b(cpi, w, tok, tok_end, mi_row, mi_col); + write_tokens_b(cpi, w, tok, tok_end); } } @@ -1571,8 +1565,8 @@ static AOM_INLINE void write_partition(const AV1_COMMON *const cm, if (!is_partition_point) return; - const int has_rows = (mi_row + hbs) < cm->mi_rows; - const int has_cols = (mi_col + hbs) < cm->mi_cols; + const int has_rows = (mi_row + hbs) < cm->mi_params.mi_rows; + const int has_cols = (mi_col + hbs) < cm->mi_params.mi_cols; const int ctx = partition_plane_context(xd, mi_row, mi_col, bsize); FRAME_CONTEXT *ec_ctx = xd->tile_ctx; @@ -1605,6 +1599,7 @@ static AOM_INLINE void write_modes_sb( const TOKENEXTRA **tok, const TOKENEXTRA *const tok_end, int mi_row, int mi_col, BLOCK_SIZE bsize) { const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; assert(bsize < BLOCK_SIZES_ALL); const int hbs = mi_size_wide[bsize] / 2; @@ -1613,7 +1608,7 @@ static AOM_INLINE void write_modes_sb( const PARTITION_TYPE partition = get_partition(cm, mi_row, mi_col, bsize); const BLOCK_SIZE subsize = get_partition_subsize(bsize, partition); - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; const int num_planes = av1_num_planes(cm); for (int plane = 0; plane < num_planes; ++plane) { @@ -1640,12 +1635,12 @@ static AOM_INLINE void write_modes_sb( break; case PARTITION_HORZ: write_modes_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); - if (mi_row + hbs < cm->mi_rows) + if (mi_row + hbs < mi_params->mi_rows) write_modes_b(cpi, tile, w, tok, tok_end, mi_row + hbs, mi_col); break; case PARTITION_VERT: write_modes_b(cpi, tile, w, tok, tok_end, mi_row, mi_col); - if (mi_col + hbs < cm->mi_cols) + if (mi_col + hbs < mi_params->mi_cols) write_modes_b(cpi, tile, w, tok, tok_end, mi_row, mi_col + hbs); break; case PARTITION_SPLIT: @@ -1678,7 +1673,7 @@ static AOM_INLINE void write_modes_sb( case PARTITION_HORZ_4: for (i = 0; i < 4; ++i) { int this_mi_row = mi_row + i * quarter_step; - if (i > 0 && this_mi_row >= cm->mi_rows) break; + if (i > 0 && this_mi_row >= mi_params->mi_rows) break; write_modes_b(cpi, tile, w, tok, tok_end, this_mi_row, mi_col); } @@ -1686,7 +1681,7 @@ static AOM_INLINE void write_modes_sb( case PARTITION_VERT_4: for (i = 0; i < 4; ++i) { int this_mi_col = mi_col + i * quarter_step; - if (i > 0 && this_mi_col >= cm->mi_cols) break; + if (i > 0 && this_mi_col >= mi_params->mi_cols) break; write_modes_b(cpi, tile, w, tok, tok_end, mi_row, this_mi_col); } @@ -1708,21 +1703,21 @@ static AOM_INLINE void write_modes(AV1_COMP *const cpi, const int mi_row_end = tile->mi_row_end; const int mi_col_start = tile->mi_col_start; const int mi_col_end = tile->mi_col_end; - int mi_row, mi_col, sb_row_in_tile; + const int num_planes = av1_num_planes(cm); av1_zero_above_context(cm, xd, mi_col_start, mi_col_end, tile->tile_row); - av1_init_above_context(cm, xd, tile->tile_row); + av1_init_above_context(&cm->above_contexts, num_planes, tile->tile_row, xd); if (cpi->common.delta_q_info.delta_q_present_flag) { - xd->current_qindex = cpi->common.base_qindex; + xd->current_qindex = cpi->common.quant_params.base_qindex; if (cpi->common.delta_q_info.delta_lf_present_flag) { - av1_reset_loop_filter_delta(xd, av1_num_planes(cm)); + av1_reset_loop_filter_delta(xd, num_planes); } } - for (mi_row = mi_row_start; mi_row < mi_row_end; + for (int mi_row = mi_row_start; mi_row < mi_row_end; mi_row += cm->seq_params.mib_size) { - sb_row_in_tile = + const int sb_row_in_tile = (mi_row - tile->mi_row_start) >> cm->seq_params.mib_size_log2; const TOKENEXTRA *tok = cpi->tplist[tile_row][tile_col][sb_row_in_tile].start; @@ -1731,7 +1726,7 @@ static AOM_INLINE void write_modes(AV1_COMP *const cpi, av1_zero_left_context(xd); - for (mi_col = mi_col_start; mi_col < mi_col_end; + for (int mi_col = mi_col_start; mi_col < mi_col_end; mi_col += cm->seq_params.mib_size) { cpi->td.mb.cb_coef_buff = av1_get_cb_coeff_buffer(cpi, mi_row, mi_col); write_modes_sb(cpi, tile, w, &tok, tok_end, mi_row, mi_col, @@ -1743,9 +1738,9 @@ static AOM_INLINE void write_modes(AV1_COMP *const cpi, static AOM_INLINE void encode_restoration_mode( AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); if (!cm->seq_params.enable_restoration) return; - if (cm->allow_intrabc) return; + if (cm->features.allow_intrabc) return; const int num_planes = av1_num_planes(cm); int all_none = 1, chroma_none = 1; for (int p = 0; p < num_planes; ++p) { @@ -1896,7 +1891,7 @@ static AOM_INLINE void loop_restoration_write_sb_coeffs( if (frame_rtype == RESTORE_NONE) return; (void)counts; - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); const int wiener_win = (plane > 0) ? WIENER_WIN_CHROMA : WIENER_WIN; WienerInfo *ref_wiener_info = &xd->wiener_info[plane]; @@ -1939,12 +1934,41 @@ static AOM_INLINE void loop_restoration_write_sb_coeffs( } } +// Only write out the ref delta section if any of the elements +// will signal a delta. +static bool is_mode_ref_delta_meaningful(AV1_COMMON *cm) { + struct loopfilter *lf = &cm->lf; + if (!lf->mode_ref_delta_update) { + return 0; + } + const RefCntBuffer *buf = get_primary_ref_frame_buf(cm); + int8_t last_ref_deltas[REF_FRAMES]; + int8_t last_mode_deltas[MAX_MODE_LF_DELTAS]; + if (buf == NULL) { + av1_set_default_ref_deltas(last_ref_deltas); + av1_set_default_mode_deltas(last_mode_deltas); + } else { + memcpy(last_ref_deltas, buf->ref_deltas, REF_FRAMES); + memcpy(last_mode_deltas, buf->mode_deltas, MAX_MODE_LF_DELTAS); + } + for (int i = 0; i < REF_FRAMES; i++) { + if (lf->ref_deltas[i] != last_ref_deltas[i]) { + return true; + } + } + for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) { + if (lf->mode_deltas[i] != last_mode_deltas[i]) { + return true; + } + } + return false; +} + static AOM_INLINE void encode_loopfilter(AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { - assert(!cm->coded_lossless); - if (cm->allow_intrabc) return; + assert(!cm->features.coded_lossless); + if (cm->features.allow_intrabc) return; const int num_planes = av1_num_planes(cm); - int i; struct loopfilter *lf = &cm->lf; // Encode the loop filter level and type @@ -1958,49 +1982,45 @@ static AOM_INLINE void encode_loopfilter(AV1_COMMON *cm, } aom_wb_write_literal(wb, lf->sharpness_level, 3); - // Write out loop filter deltas applied at the MB level based on mode or - // ref frame (if they are enabled). aom_wb_write_bit(wb, lf->mode_ref_delta_enabled); - if (lf->mode_ref_delta_enabled) { - aom_wb_write_bit(wb, lf->mode_ref_delta_update); + // Write out loop filter deltas applied at the MB level based on mode or + // ref frame (if they are enabled), only if there is information to write. + int meaningful = is_mode_ref_delta_meaningful(cm); + aom_wb_write_bit(wb, meaningful); + if (!meaningful) { + return; + } - if (lf->mode_ref_delta_update) { - const RefCntBuffer *buf = get_primary_ref_frame_buf(cm); - int8_t last_ref_deltas[REF_FRAMES]; - if (buf == NULL) { - av1_set_default_ref_deltas(last_ref_deltas); - } else { - memcpy(last_ref_deltas, buf->ref_deltas, REF_FRAMES); - } - for (i = 0; i < REF_FRAMES; i++) { - const int delta = lf->ref_deltas[i]; - const int changed = delta != last_ref_deltas[i]; - aom_wb_write_bit(wb, changed); - if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6); - } - - int8_t last_mode_deltas[MAX_MODE_LF_DELTAS]; - if (buf == NULL) { - av1_set_default_mode_deltas(last_mode_deltas); - } else { - memcpy(last_mode_deltas, buf->mode_deltas, MAX_MODE_LF_DELTAS); - } - for (i = 0; i < MAX_MODE_LF_DELTAS; i++) { - const int delta = lf->mode_deltas[i]; - const int changed = delta != last_mode_deltas[i]; - aom_wb_write_bit(wb, changed); - if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6); - } - } + const RefCntBuffer *buf = get_primary_ref_frame_buf(cm); + int8_t last_ref_deltas[REF_FRAMES]; + int8_t last_mode_deltas[MAX_MODE_LF_DELTAS]; + if (buf == NULL) { + av1_set_default_ref_deltas(last_ref_deltas); + av1_set_default_mode_deltas(last_mode_deltas); + } else { + memcpy(last_ref_deltas, buf->ref_deltas, REF_FRAMES); + memcpy(last_mode_deltas, buf->mode_deltas, MAX_MODE_LF_DELTAS); + } + for (int i = 0; i < REF_FRAMES; i++) { + const int delta = lf->ref_deltas[i]; + const int changed = delta != last_ref_deltas[i]; + aom_wb_write_bit(wb, changed); + if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6); + } + for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) { + const int delta = lf->mode_deltas[i]; + const int changed = delta != last_mode_deltas[i]; + aom_wb_write_bit(wb, changed); + if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6); } } static AOM_INLINE void encode_cdef(const AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { - assert(!cm->coded_lossless); + assert(!cm->features.coded_lossless); if (!cm->seq_params.enable_cdef) return; - if (cm->allow_intrabc) return; + if (cm->features.allow_intrabc) return; const int num_planes = av1_num_planes(cm); int i; aom_wb_write_literal(wb, cm->cdef_info.cdef_damping - 3, 2); @@ -2024,31 +2044,31 @@ static AOM_INLINE void write_delta_q(struct aom_write_bit_buffer *wb, } } -static AOM_INLINE void encode_quantization(const AV1_COMMON *const cm, - struct aom_write_bit_buffer *wb) { - const int num_planes = av1_num_planes(cm); - - aom_wb_write_literal(wb, cm->base_qindex, QINDEX_BITS); - write_delta_q(wb, cm->y_dc_delta_q); +static AOM_INLINE void encode_quantization( + const CommonQuantParams *const quant_params, int num_planes, + bool separate_uv_delta_q, struct aom_write_bit_buffer *wb) { + aom_wb_write_literal(wb, quant_params->base_qindex, QINDEX_BITS); + write_delta_q(wb, quant_params->y_dc_delta_q); if (num_planes > 1) { - int diff_uv_delta = (cm->u_dc_delta_q != cm->v_dc_delta_q) || - (cm->u_ac_delta_q != cm->v_ac_delta_q); - if (cm->seq_params.separate_uv_delta_q) aom_wb_write_bit(wb, diff_uv_delta); - write_delta_q(wb, cm->u_dc_delta_q); - write_delta_q(wb, cm->u_ac_delta_q); + int diff_uv_delta = + (quant_params->u_dc_delta_q != quant_params->v_dc_delta_q) || + (quant_params->u_ac_delta_q != quant_params->v_ac_delta_q); + if (separate_uv_delta_q) aom_wb_write_bit(wb, diff_uv_delta); + write_delta_q(wb, quant_params->u_dc_delta_q); + write_delta_q(wb, quant_params->u_ac_delta_q); if (diff_uv_delta) { - write_delta_q(wb, cm->v_dc_delta_q); - write_delta_q(wb, cm->v_ac_delta_q); + write_delta_q(wb, quant_params->v_dc_delta_q); + write_delta_q(wb, quant_params->v_ac_delta_q); } } - aom_wb_write_bit(wb, cm->using_qmatrix); - if (cm->using_qmatrix) { - aom_wb_write_literal(wb, cm->qm_y, QM_LEVEL_BITS); - aom_wb_write_literal(wb, cm->qm_u, QM_LEVEL_BITS); - if (!cm->seq_params.separate_uv_delta_q) - assert(cm->qm_u == cm->qm_v); + aom_wb_write_bit(wb, quant_params->using_qmatrix); + if (quant_params->using_qmatrix) { + aom_wb_write_literal(wb, quant_params->qmatrix_level_y, QM_LEVEL_BITS); + aom_wb_write_literal(wb, quant_params->qmatrix_level_u, QM_LEVEL_BITS); + if (!separate_uv_delta_q) + assert(quant_params->qmatrix_level_u == quant_params->qmatrix_level_v); else - aom_wb_write_literal(wb, cm->qm_v, QM_LEVEL_BITS); + aom_wb_write_literal(wb, quant_params->qmatrix_level_v, QM_LEVEL_BITS); } } @@ -2061,7 +2081,7 @@ static AOM_INLINE void encode_segmentation(AV1_COMMON *cm, MACROBLOCKD *xd, if (!seg->enabled) return; // Write update flags - if (cm->primary_ref_frame == PRIMARY_REF_NONE) { + if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) { assert(seg->update_map == 1); seg->temporal_update = 0; assert(seg->update_data == 1); @@ -2121,48 +2141,48 @@ static AOM_INLINE void wb_write_uniform(struct aom_write_bit_buffer *wb, int n, static AOM_INLINE void write_tile_info_max_tile( const AV1_COMMON *const cm, struct aom_write_bit_buffer *wb) { - int width_mi = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2); - int height_mi = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); + int width_mi = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_cols, cm->seq_params.mib_size_log2); + int height_mi = + ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, cm->seq_params.mib_size_log2); int width_sb = width_mi >> cm->seq_params.mib_size_log2; int height_sb = height_mi >> cm->seq_params.mib_size_log2; int size_sb, i; + const CommonTileParams *const tiles = &cm->tiles; - aom_wb_write_bit(wb, cm->uniform_tile_spacing_flag); + aom_wb_write_bit(wb, tiles->uniform_spacing); - if (cm->uniform_tile_spacing_flag) { - // Uniform spaced tiles with power-of-two number of rows and columns - // tile columns - int ones = cm->log2_tile_cols - cm->min_log2_tile_cols; + if (tiles->uniform_spacing) { + int ones = tiles->log2_cols - tiles->min_log2_cols; while (ones--) { aom_wb_write_bit(wb, 1); } - if (cm->log2_tile_cols < cm->max_log2_tile_cols) { + if (tiles->log2_cols < tiles->max_log2_cols) { aom_wb_write_bit(wb, 0); } // rows - ones = cm->log2_tile_rows - cm->min_log2_tile_rows; + ones = tiles->log2_rows - tiles->min_log2_rows; while (ones--) { aom_wb_write_bit(wb, 1); } - if (cm->log2_tile_rows < cm->max_log2_tile_rows) { + if (tiles->log2_rows < tiles->max_log2_rows) { aom_wb_write_bit(wb, 0); } } else { // Explicit tiles with configurable tile widths and heights // columns - for (i = 0; i < cm->tile_cols; i++) { - size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i]; - wb_write_uniform(wb, AOMMIN(width_sb, cm->max_tile_width_sb), - size_sb - 1); + for (i = 0; i < tiles->cols; i++) { + size_sb = tiles->col_start_sb[i + 1] - tiles->col_start_sb[i]; + wb_write_uniform(wb, AOMMIN(width_sb, tiles->max_width_sb), size_sb - 1); width_sb -= size_sb; } assert(width_sb == 0); // rows - for (i = 0; i < cm->tile_rows; i++) { - size_sb = cm->tile_row_start_sb[i + 1] - cm->tile_row_start_sb[i]; - wb_write_uniform(wb, AOMMIN(height_sb, cm->max_tile_height_sb), + for (i = 0; i < tiles->rows; i++) { + size_sb = tiles->row_start_sb[i + 1] - tiles->row_start_sb[i]; + wb_write_uniform(wb, AOMMIN(height_sb, tiles->max_height_sb), size_sb - 1); height_sb -= size_sb; } @@ -2176,9 +2196,9 @@ static AOM_INLINE void write_tile_info(const AV1_COMMON *const cm, write_tile_info_max_tile(cm, wb); *saved_wb = *wb; - if (cm->tile_rows * cm->tile_cols > 1) { + if (cm->tiles.rows * cm->tiles.cols > 1) { // tile id used for cdf update - aom_wb_write_literal(wb, 0, cm->log2_tile_cols + cm->log2_tile_rows); + aom_wb_write_literal(wb, 0, cm->tiles.log2_cols + cm->tiles.log2_rows); // Number of bytes in tile size - 1 aom_wb_write_literal(wb, 3, 2); } @@ -2193,7 +2213,7 @@ static AOM_INLINE void write_ext_tile_info( assert(aom_wb_is_byte_aligned(wb)); *saved_wb = *wb; - if (cm->tile_rows * cm->tile_cols > 1) { + if (cm->tiles.rows * cm->tiles.cols > 1) { // Note that the last item in the uncompressed header is the data // describing tile configuration. // Number of bytes in tile column size - 1 @@ -2421,61 +2441,44 @@ static AOM_INLINE void write_color_config( } static AOM_INLINE void write_timing_info_header( - AV1_COMMON *const cm, struct aom_write_bit_buffer *wb) { - aom_wb_write_unsigned_literal(wb, cm->timing_info.num_units_in_display_tick, - 32); // Number of units in tick - aom_wb_write_unsigned_literal(wb, cm->timing_info.time_scale, - 32); // Time scale - aom_wb_write_bit( - wb, - cm->timing_info.equal_picture_interval); // Equal picture interval bit - if (cm->timing_info.equal_picture_interval) { - aom_wb_write_uvlc( - wb, - cm->timing_info.num_ticks_per_picture - 1); // ticks per picture + const aom_timing_info_t *const timing_info, + struct aom_write_bit_buffer *wb) { + aom_wb_write_unsigned_literal(wb, timing_info->num_units_in_display_tick, 32); + aom_wb_write_unsigned_literal(wb, timing_info->time_scale, 32); + aom_wb_write_bit(wb, timing_info->equal_picture_interval); + if (timing_info->equal_picture_interval) { + aom_wb_write_uvlc(wb, timing_info->num_ticks_per_picture - 1); } } static AOM_INLINE void write_decoder_model_info( - AV1_COMMON *const cm, struct aom_write_bit_buffer *wb) { + const aom_dec_model_info_t *const decoder_model_info, + struct aom_write_bit_buffer *wb) { aom_wb_write_literal( - wb, cm->buffer_model.encoder_decoder_buffer_delay_length - 1, 5); - aom_wb_write_unsigned_literal(wb, cm->buffer_model.num_units_in_decoding_tick, - 32); // Number of units in decoding tick - aom_wb_write_literal(wb, cm->buffer_model.buffer_removal_time_length - 1, 5); - aom_wb_write_literal(wb, cm->buffer_model.frame_presentation_time_length - 1, + wb, decoder_model_info->encoder_decoder_buffer_delay_length - 1, 5); + aom_wb_write_unsigned_literal( + wb, decoder_model_info->num_units_in_decoding_tick, 32); + aom_wb_write_literal(wb, decoder_model_info->buffer_removal_time_length - 1, 5); + aom_wb_write_literal( + wb, decoder_model_info->frame_presentation_time_length - 1, 5); } static AOM_INLINE void write_dec_model_op_parameters( - AV1_COMMON *const cm, struct aom_write_bit_buffer *wb, int op_num) { - if (op_num > MAX_NUM_OPERATING_POINTS) - aom_internal_error( - &cm->error, AOM_CODEC_UNSUP_BITSTREAM, - "Encoder does not support %d decoder model operating points", op_num); - - // aom_wb_write_bit(wb, cm->op_params[op_num].has_parameters); - // if (!cm->op_params[op_num].has_parameters) return; - - aom_wb_write_unsigned_literal( - wb, cm->op_params[op_num].decoder_buffer_delay, - cm->buffer_model.encoder_decoder_buffer_delay_length); - - aom_wb_write_unsigned_literal( - wb, cm->op_params[op_num].encoder_buffer_delay, - cm->buffer_model.encoder_decoder_buffer_delay_length); - - aom_wb_write_bit(wb, cm->op_params[op_num].low_delay_mode_flag); - - cm->op_frame_timing[op_num].buffer_removal_time = - 0; // reset the decoded frame counter + const aom_dec_model_op_parameters_t *op_params, int buffer_delay_length, + struct aom_write_bit_buffer *wb) { + aom_wb_write_unsigned_literal(wb, op_params->decoder_buffer_delay, + buffer_delay_length); + aom_wb_write_unsigned_literal(wb, op_params->encoder_buffer_delay, + buffer_delay_length); + aom_wb_write_bit(wb, op_params->low_delay_mode_flag); } static AOM_INLINE void write_tu_pts_info(AV1_COMMON *const cm, struct aom_write_bit_buffer *wb) { aom_wb_write_unsigned_literal( wb, cm->frame_presentation_time, - cm->buffer_model.frame_presentation_time_length); + cm->seq_params.decoder_model_info.frame_presentation_time_length); } static AOM_INLINE void write_film_grain_params( @@ -2722,7 +2725,7 @@ static AOM_INLINE void write_global_motion(AV1_COMP *cpi, cm->prev_frame ? &cm->prev_frame->global_motion[frame] : &default_warp_params; write_global_motion_params(&cm->global_motion[frame], ref_params, wb, - cm->allow_high_precision_mv); + cm->features.allow_high_precision_mv); // TODO(sarahparker, debargha): The logic in the commented out code below // does not work currently and causes mismatches when resize is on. // Fix it before turning the optimization back on. @@ -2732,7 +2735,7 @@ static AOM_INLINE void write_global_motion(AV1_COMP *cpi, cpi->source->y_crop_height == ref_buf->y_crop_height) { write_global_motion_params(&cm->global_motion[frame], &cm->prev_frame->global_motion[frame], wb, - cm->allow_high_precision_mv); + cm->features.allow_high_precision_mv); } else { assert(cm->global_motion[frame].wmtype == IDENTITY && "Invalid warp type for frames of different resolutions"); @@ -2822,8 +2825,10 @@ static AOM_INLINE void write_uncompressed_header_obu( struct aom_write_bit_buffer *wb) { AV1_COMMON *const cm = &cpi->common; const SequenceHeader *const seq_params = &cm->seq_params; + const CommonQuantParams *quant_params = &cm->quant_params; MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; CurrentFrame *const current_frame = &cm->current_frame; + FeatureFlags *const features = &cm->features; current_frame->frame_refs_short_signaling = 0; @@ -2838,7 +2843,7 @@ static AOM_INLINE void write_uncompressed_header_obu( aom_wb_write_literal(wb, cpi->existing_fb_idx_to_show, 3); if (seq_params->decoder_model_info_present_flag && - cm->timing_info.equal_picture_interval == 0) { + seq_params->timing_info.equal_picture_interval == 0) { write_tu_pts_info(cm, wb); } if (seq_params->frame_id_numbers_present_flag) { @@ -2856,34 +2861,35 @@ static AOM_INLINE void write_uncompressed_header_obu( aom_wb_write_bit(wb, cm->show_frame); if (cm->show_frame) { if (seq_params->decoder_model_info_present_flag && - cm->timing_info.equal_picture_interval == 0) + seq_params->timing_info.equal_picture_interval == 0) write_tu_pts_info(cm, wb); } else { aom_wb_write_bit(wb, cm->showable_frame); } if (frame_is_sframe(cm)) { - assert(cm->error_resilient_mode); + assert(features->error_resilient_mode); } else if (!(current_frame->frame_type == KEY_FRAME && cm->show_frame)) { - aom_wb_write_bit(wb, cm->error_resilient_mode); + aom_wb_write_bit(wb, features->error_resilient_mode); } } - aom_wb_write_bit(wb, cm->disable_cdf_update); + aom_wb_write_bit(wb, features->disable_cdf_update); if (seq_params->force_screen_content_tools == 2) { - aom_wb_write_bit(wb, cm->allow_screen_content_tools); + aom_wb_write_bit(wb, features->allow_screen_content_tools); } else { - assert(cm->allow_screen_content_tools == + assert(features->allow_screen_content_tools == seq_params->force_screen_content_tools); } - if (cm->allow_screen_content_tools) { + if (features->allow_screen_content_tools) { if (seq_params->force_integer_mv == 2) { - aom_wb_write_bit(wb, cm->cur_frame_force_integer_mv); + aom_wb_write_bit(wb, features->cur_frame_force_integer_mv); } else { - assert(cm->cur_frame_force_integer_mv == seq_params->force_integer_mv); + assert(features->cur_frame_force_integer_mv == + seq_params->force_integer_mv); } } else { - assert(cm->cur_frame_force_integer_mv == 0); + assert(features->cur_frame_force_integer_mv == 0); } int frame_size_override_flag = 0; @@ -2915,8 +2921,8 @@ static AOM_INLINE void write_uncompressed_header_obu( wb, current_frame->order_hint, seq_params->order_hint_info.order_hint_bits_minus_1 + 1); - if (!cm->error_resilient_mode && !frame_is_intra_only(cm)) { - aom_wb_write_literal(wb, cm->primary_ref_frame, PRIMARY_REF_BITS); + if (!features->error_resilient_mode && !frame_is_intra_only(cm)) { + aom_wb_write_literal(wb, features->primary_ref_frame, PRIMARY_REF_BITS); } } @@ -2925,7 +2931,7 @@ static AOM_INLINE void write_uncompressed_header_obu( if (cm->buffer_removal_time_present) { for (int op_num = 0; op_num < seq_params->operating_points_cnt_minus_1 + 1; op_num++) { - if (cm->op_params[op_num].decoder_model_param_present_flag) { + if (seq_params->op_params[op_num].decoder_model_param_present_flag) { if (((seq_params->operating_point_idc[op_num] >> cm->temporal_layer_id) & 0x1 && @@ -2934,10 +2940,10 @@ static AOM_INLINE void write_uncompressed_header_obu( 0x1) || seq_params->operating_point_idc[op_num] == 0) { aom_wb_write_unsigned_literal( - wb, cm->op_frame_timing[op_num].buffer_removal_time, - cm->buffer_model.buffer_removal_time_length); - cm->op_frame_timing[op_num].buffer_removal_time++; - if (cm->op_frame_timing[op_num].buffer_removal_time == 0) { + wb, cm->buffer_removal_times[op_num], + seq_params->decoder_model_info.buffer_removal_time_length); + cm->buffer_removal_times[op_num]++; + if (cm->buffer_removal_times[op_num] == 0) { aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, "buffer_removal_time overflowed"); } @@ -2956,7 +2962,7 @@ static AOM_INLINE void write_uncompressed_header_obu( if (!frame_is_intra_only(cm) || current_frame->refresh_frame_flags != 0xff) { // Write all ref frame order hints if error_resilient_mode == 1 - if (cm->error_resilient_mode && + if (features->error_resilient_mode && seq_params->order_hint_info.enable_order_hint) { for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) { aom_wb_write_literal( @@ -2968,15 +2974,15 @@ static AOM_INLINE void write_uncompressed_header_obu( if (current_frame->frame_type == KEY_FRAME) { write_frame_size(cm, frame_size_override_flag, wb); - assert(!av1_superres_scaled(cm) || !cm->allow_intrabc); - if (cm->allow_screen_content_tools && !av1_superres_scaled(cm)) - aom_wb_write_bit(wb, cm->allow_intrabc); + assert(!av1_superres_scaled(cm) || !features->allow_intrabc); + if (features->allow_screen_content_tools && !av1_superres_scaled(cm)) + aom_wb_write_bit(wb, features->allow_intrabc); } else { if (current_frame->frame_type == INTRA_ONLY_FRAME) { write_frame_size(cm, frame_size_override_flag, wb); - assert(!av1_superres_scaled(cm) || !cm->allow_intrabc); - if (cm->allow_screen_content_tools && !av1_superres_scaled(cm)) - aom_wb_write_bit(wb, cm->allow_intrabc); + assert(!av1_superres_scaled(cm) || !features->allow_intrabc); + if (features->allow_screen_content_tools && !av1_superres_scaled(cm)) + aom_wb_write_bit(wb, features->allow_intrabc); } else if (current_frame->frame_type == INTER_FRAME || frame_is_sframe(cm)) { MV_REFERENCE_FRAME ref_frame; @@ -3032,46 +3038,47 @@ static AOM_INLINE void write_uncompressed_header_obu( } } - if (!cm->error_resilient_mode && frame_size_override_flag) { + if (!features->error_resilient_mode && frame_size_override_flag) { write_frame_size_with_refs(cm, wb); } else { write_frame_size(cm, frame_size_override_flag, wb); } - if (!cm->cur_frame_force_integer_mv) - aom_wb_write_bit(wb, cm->allow_high_precision_mv); - write_frame_interp_filter(cm->interp_filter, wb); - aom_wb_write_bit(wb, cm->switchable_motion_mode); + if (!features->cur_frame_force_integer_mv) + aom_wb_write_bit(wb, features->allow_high_precision_mv); + write_frame_interp_filter(features->interp_filter, wb); + aom_wb_write_bit(wb, features->switchable_motion_mode); if (frame_might_allow_ref_frame_mvs(cm)) { - aom_wb_write_bit(wb, cm->allow_ref_frame_mvs); + aom_wb_write_bit(wb, features->allow_ref_frame_mvs); } else { - assert(cm->allow_ref_frame_mvs == 0); + assert(features->allow_ref_frame_mvs == 0); } } } - const int might_bwd_adapt = - !(seq_params->reduced_still_picture_hdr) && !(cm->disable_cdf_update); - if (cm->large_scale_tile) - assert(cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED); + const int might_bwd_adapt = !(seq_params->reduced_still_picture_hdr) && + !(features->disable_cdf_update); + if (cm->tiles.large_scale) + assert(features->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED); if (might_bwd_adapt) { aom_wb_write_bit( - wb, cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED); + wb, features->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED); } write_tile_info(cm, saved_wb, wb); - encode_quantization(cm, wb); + encode_quantization(quant_params, av1_num_planes(cm), + cm->seq_params.separate_uv_delta_q, wb); encode_segmentation(cm, xd, wb); const DeltaQInfo *const delta_q_info = &cm->delta_q_info; - if (delta_q_info->delta_q_present_flag) assert(cm->base_qindex > 0); - if (cm->base_qindex > 0) { + if (delta_q_info->delta_q_present_flag) assert(quant_params->base_qindex > 0); + if (quant_params->base_qindex > 0) { aom_wb_write_bit(wb, delta_q_info->delta_q_present_flag); if (delta_q_info->delta_q_present_flag) { aom_wb_write_literal(wb, get_msb(delta_q_info->delta_q_res), 2); - xd->current_qindex = cm->base_qindex; - if (cm->allow_intrabc) + xd->current_qindex = quant_params->base_qindex; + if (features->allow_intrabc) assert(delta_q_info->delta_lf_present_flag == 0); else aom_wb_write_bit(wb, delta_q_info->delta_lf_present_flag); @@ -3083,10 +3090,10 @@ static AOM_INLINE void write_uncompressed_header_obu( } } - if (cm->all_lossless) { + if (features->all_lossless) { assert(!av1_superres_scaled(cm)); } else { - if (!cm->coded_lossless) { + if (!features->coded_lossless) { encode_loopfilter(cm, wb); encode_cdef(cm, wb); } @@ -3094,10 +3101,10 @@ static AOM_INLINE void write_uncompressed_header_obu( } // Write TX mode - if (cm->coded_lossless) - assert(cm->tx_mode == ONLY_4X4); + if (features->coded_lossless) + assert(features->tx_mode == ONLY_4X4); else - aom_wb_write_bit(wb, cm->tx_mode == TX_MODE_SELECT); + aom_wb_write_bit(wb, features->tx_mode == TX_MODE_SELECT); if (!frame_is_intra_only(cm)) { const int use_hybrid_pred = @@ -3110,11 +3117,11 @@ static AOM_INLINE void write_uncompressed_header_obu( aom_wb_write_bit(wb, current_frame->skip_mode_info.skip_mode_flag); if (frame_might_allow_warped_motion(cm)) - aom_wb_write_bit(wb, cm->allow_warped_motion); + aom_wb_write_bit(wb, features->allow_warped_motion); else - assert(!cm->allow_warped_motion); + assert(!features->allow_warped_motion); - aom_wb_write_bit(wb, cm->reduced_tx_set_used); + aom_wb_write_bit(wb, features->reduced_tx_set_used); if (!frame_is_intra_only(cm)) write_global_motion(cpi, wb); @@ -3122,7 +3129,7 @@ static AOM_INLINE void write_uncompressed_header_obu( (cm->show_frame || cm->showable_frame)) write_film_grain_params(cpi, wb); - if (cm->large_scale_tile) write_ext_tile_info(cm, saved_wb, wb); + if (cm->tiles.large_scale) write_ext_tile_info(cm, saved_wb, wb); } static int choose_size_bytes(uint32_t size, int spare_msbs) { @@ -3156,7 +3163,7 @@ static AOM_INLINE void mem_put_varsize(uint8_t *const dst, const int sz, } } -static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, +static int remux_tiles(const CommonTileParams *const tiles, uint8_t *dst, const uint32_t data_size, const uint32_t max_tile_size, const uint32_t max_tile_col_size, int *const tile_size_bytes, @@ -3165,7 +3172,7 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, int tsb; int tcsb; - if (cm->large_scale_tile) { + if (tiles->large_scale) { // The top bit in the tile size field indicates tile copy mode, so we // have 1 less bit to code the tile size tsb = choose_size_bytes(max_tile_size, 1); @@ -3186,25 +3193,25 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, uint32_t wpos = 0; uint32_t rpos = 0; - if (cm->large_scale_tile) { + if (tiles->large_scale) { int tile_row; int tile_col; - for (tile_col = 0; tile_col < cm->tile_cols; tile_col++) { + for (tile_col = 0; tile_col < tiles->cols; tile_col++) { // All but the last column has a column header - if (tile_col < cm->tile_cols - 1) { + if (tile_col < tiles->cols - 1) { uint32_t tile_col_size = mem_get_le32(dst + rpos); rpos += 4; // Adjust the tile column size by the number of bytes removed // from the tile size fields. - tile_col_size -= (4 - tsb) * cm->tile_rows; + tile_col_size -= (4 - tsb) * tiles->rows; mem_put_varsize(dst + wpos, tcsb, tile_col_size); wpos += tcsb; } - for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) { + for (tile_row = 0; tile_row < tiles->rows; tile_row++) { // All, including the last row has a header uint32_t tile_header = mem_get_le32(dst + rpos); rpos += 4; @@ -3232,7 +3239,7 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, return wpos; } - const int n_tiles = cm->tile_cols * cm->tile_rows; + const int n_tiles = tiles->cols * tiles->rows; int n; for (n = 0; n < n_tiles; n++) { @@ -3260,11 +3267,12 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst, return wpos; } -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 && +uint32_t av1_write_obu_header(AV1LevelParams *const level_params, + OBU_TYPE obu_type, int obu_extension, + uint8_t *const dst) { + if (level_params->keep_level_stats && (obu_type == OBU_FRAME || obu_type == OBU_FRAME_HEADER)) - ++cpi->frame_header_count; + ++level_params->frame_header_count; struct aom_write_bit_buffer wb = { dst, 0 }; uint32_t size = 0; @@ -3283,11 +3291,12 @@ uint32_t av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type, return size; } -int av1_write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size, +int av1_write_uleb_obu_size(size_t obu_header_size, size_t obu_payload_size, uint8_t *dest) { - const uint32_t obu_size = obu_payload_size; - const uint32_t offset = obu_header_size; + const size_t offset = obu_header_size; size_t coded_obu_size = 0; + const uint32_t obu_size = (uint32_t)obu_payload_size; + assert(obu_size == obu_payload_size); if (aom_uleb_encode(obu_size, sizeof(obu_size), dest + offset, &coded_obu_size) != 0) { @@ -3297,13 +3306,12 @@ int av1_write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size, return AOM_CODEC_OK; } -static size_t obu_memmove(uint32_t obu_header_size, uint32_t obu_payload_size, +static size_t obu_memmove(size_t obu_header_size, size_t obu_payload_size, uint8_t *data) { const size_t length_field_size = aom_uleb_size_in_bytes(obu_payload_size); - const uint32_t move_dst_offset = - (uint32_t)length_field_size + obu_header_size; - const uint32_t move_src_offset = obu_header_size; - const uint32_t move_size = obu_payload_size; + const size_t move_dst_offset = length_field_size + obu_header_size; + const size_t move_src_offset = obu_header_size; + const size_t move_size = obu_payload_size; memmove(data + move_dst_offset, data + move_src_offset, move_size); return length_field_size; } @@ -3323,68 +3331,74 @@ static AOM_INLINE void write_bitstream_level(AV1_LEVEL seq_level_idx, aom_wb_write_literal(wb, seq_level_idx, LEVEL_BITS); } -uint32_t av1_write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst) { - AV1_COMMON *const cm = &cpi->common; +uint32_t av1_write_sequence_header_obu(const SequenceHeader *seq_params, + uint8_t *const dst) { struct aom_write_bit_buffer wb = { dst, 0 }; uint32_t size = 0; - write_profile(cm->seq_params.profile, &wb); + write_profile(seq_params->profile, &wb); // Still picture or not - aom_wb_write_bit(&wb, cm->seq_params.still_picture); - assert(IMPLIES(!cm->seq_params.still_picture, - !cm->seq_params.reduced_still_picture_hdr)); + aom_wb_write_bit(&wb, seq_params->still_picture); + assert(IMPLIES(!seq_params->still_picture, + !seq_params->reduced_still_picture_hdr)); // whether to use reduced still picture header - aom_wb_write_bit(&wb, cm->seq_params.reduced_still_picture_hdr); + aom_wb_write_bit(&wb, seq_params->reduced_still_picture_hdr); - if (cm->seq_params.reduced_still_picture_hdr) { - 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.seq_level_idx[0], &wb); + if (seq_params->reduced_still_picture_hdr) { + assert(seq_params->timing_info_present == 0); + assert(seq_params->decoder_model_info_present_flag == 0); + assert(seq_params->display_model_info_present_flag == 0); + write_bitstream_level(seq_params->seq_level_idx[0], &wb); } else { - aom_wb_write_bit(&wb, cm->timing_info_present); // timing info present flag + aom_wb_write_bit( + &wb, seq_params->timing_info_present); // timing info present flag - if (cm->timing_info_present) { + if (seq_params->timing_info_present) { // timing_info - write_timing_info_header(cm, &wb); - aom_wb_write_bit(&wb, cm->seq_params.decoder_model_info_present_flag); - if (cm->seq_params.decoder_model_info_present_flag) { - write_decoder_model_info(cm, &wb); + write_timing_info_header(&seq_params->timing_info, &wb); + aom_wb_write_bit(&wb, seq_params->decoder_model_info_present_flag); + if (seq_params->decoder_model_info_present_flag) { + write_decoder_model_info(&seq_params->decoder_model_info, &wb); } } - aom_wb_write_bit(&wb, cm->seq_params.display_model_info_present_flag); - aom_wb_write_literal(&wb, cm->seq_params.operating_points_cnt_minus_1, + aom_wb_write_bit(&wb, seq_params->display_model_info_present_flag); + aom_wb_write_literal(&wb, seq_params->operating_points_cnt_minus_1, OP_POINTS_CNT_MINUS_1_BITS); int i; - 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], + for (i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; i++) { + aom_wb_write_literal(&wb, seq_params->operating_point_idc[i], OP_POINTS_IDC_BITS); - 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, - cm->op_params[i].decoder_model_param_present_flag); - if (cm->op_params[i].decoder_model_param_present_flag) - write_dec_model_op_parameters(cm, &wb, i); + write_bitstream_level(seq_params->seq_level_idx[i], &wb); + if (seq_params->seq_level_idx[i] >= SEQ_LEVEL_4_0) + aom_wb_write_bit(&wb, seq_params->tier[i]); + if (seq_params->decoder_model_info_present_flag) { + aom_wb_write_bit( + &wb, seq_params->op_params[i].decoder_model_param_present_flag); + if (seq_params->op_params[i].decoder_model_param_present_flag) { + write_dec_model_op_parameters( + &seq_params->op_params[i], + seq_params->decoder_model_info + .encoder_decoder_buffer_delay_length, + &wb); + } } - if (cm->seq_params.display_model_info_present_flag) { - aom_wb_write_bit(&wb, - cm->op_params[i].display_model_param_present_flag); - if (cm->op_params[i].display_model_param_present_flag) { - assert(cm->op_params[i].initial_display_delay <= 10); - aom_wb_write_literal(&wb, cm->op_params[i].initial_display_delay - 1, - 4); + if (seq_params->display_model_info_present_flag) { + aom_wb_write_bit( + &wb, seq_params->op_params[i].display_model_param_present_flag); + if (seq_params->op_params[i].display_model_param_present_flag) { + assert(seq_params->op_params[i].initial_display_delay <= 10); + aom_wb_write_literal( + &wb, seq_params->op_params[i].initial_display_delay - 1, 4); } } } } - write_sequence_header(&cm->seq_params, &wb); + write_sequence_header(seq_params, &wb); - write_color_config(&cm->seq_params, &wb); + write_color_config(seq_params, &wb); - aom_wb_write_bit(&wb, cm->seq_params.film_grain_params_present); + aom_wb_write_bit(&wb, seq_params->film_grain_params_present); add_trailing_bits(&wb); @@ -3427,27 +3441,32 @@ typedef struct { size_t total_length; } FrameHeaderInfo; +extern void av1_print_uncompressed_frame_header(const uint8_t *data, int size, + const char *filename); + static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, struct aom_write_bit_buffer *saved_wb, uint8_t obu_extension_header, const FrameHeaderInfo *fh_info, int *const largest_tile_id) { AV1_COMMON *const cm = &cpi->common; + const CommonTileParams *const tiles = &cm->tiles; + AV1LevelParams *const level_params = &cpi->level_params; aom_writer mode_bc; int tile_row, tile_col; // Store the location and size of each tile's data in the bitstream: TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS]; uint32_t total_size = 0; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = tiles->cols; + const int tile_rows = tiles->rows; unsigned int tile_size = 0; unsigned int max_tile_size = 0; unsigned int max_tile_col_size = 0; - const int n_log2_tiles = cm->log2_tile_rows + cm->log2_tile_cols; + const int n_log2_tiles = tiles->log2_rows + tiles->log2_cols; // Fixed size tile groups for the moment - const int num_tg_hdrs = cm->num_tg; + const int num_tg_hdrs = cpi->num_tg; const int tg_size = - (cm->large_scale_tile) + (tiles->large_scale) ? 1 : (tile_rows * tile_cols + num_tg_hdrs - 1) / num_tg_hdrs; int tile_count = 0; @@ -3459,11 +3478,12 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, *largest_tile_id = 0; - if (cm->large_scale_tile) { + if (tiles->large_scale) { // 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 = av1_write_obu_header(cpi, obu_type, 0, data); + const uint32_t tg_hdr_size = + av1_write_obu_header(level_params, obu_type, 0, data); data += tg_hdr_size; const uint32_t frame_header_size = @@ -3471,9 +3491,8 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, data += frame_header_size; total_size += frame_header_size; -#define EXT_TILE_DEBUG 0 -#if EXT_TILE_DEBUG - { + // (yunqing) This test ensures the correctness of large scale tile coding. + if (cpi->oxcf.ext_tile_debug) { char fn[20] = "./fh"; fn[4] = cm->current_frame.frame_number / 100 + '0'; fn[5] = (cm->current_frame.frame_number % 100) / 10 + '0'; @@ -3482,8 +3501,6 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, av1_print_uncompressed_frame_header(data - frame_header_size, frame_header_size, fn); } -#endif // EXT_TILE_DEBUG -#undef EXT_TILE_DEBUG int tile_size_bytes = 0; int tile_col_size_bytes = 0; @@ -3511,9 +3528,9 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // even for the last one, unless no tiling is used at all. total_size += data_offset; cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx; - mode_bc.allow_update_cdf = !cm->large_scale_tile; + mode_bc.allow_update_cdf = !tiles->large_scale; mode_bc.allow_update_cdf = - mode_bc.allow_update_cdf && !cm->disable_cdf_update; + mode_bc.allow_update_cdf && !cm->features.disable_cdf_update; aom_start_encode(&mode_bc, buf->data + data_offset); write_modes(cpi, &tile_info, &mode_bc, tile_row, tile_col); aom_stop_encode(&mode_bc); @@ -3530,7 +3547,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // tile header: size of this tile, or copy offset uint32_t tile_header = tile_size - AV1_MIN_TILE_SIZE_BYTES; const int tile_copy_mode = - ((AOMMAX(cm->tile_width, cm->tile_height) << MI_SIZE_LOG2) <= 256) + ((AOMMAX(tiles->width, tiles->height) << MI_SIZE_LOG2) <= 256) ? 1 : 0; @@ -3567,7 +3584,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, } if (have_tiles) { - total_size = remux_tiles(cm, data, total_size - frame_header_size, + total_size = remux_tiles(tiles, data, total_size - frame_header_size, max_tile_size, max_tile_col_size, &tile_size_bytes, &tile_col_size_bytes); total_size += frame_header_size; @@ -3617,8 +3634,8 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // tile group header const OBU_TYPE obu_type = (num_tg_hdrs == 1) ? OBU_FRAME : OBU_TILE_GROUP; - curr_tg_data_size = - av1_write_obu_header(cpi, obu_type, obu_extension_header, data); + curr_tg_data_size = av1_write_obu_header(level_params, obu_type, + obu_extension_header, data); obu_header_size = curr_tg_data_size; if (num_tg_hdrs == 1) { @@ -3628,7 +3645,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, curr_tg_data_size += write_tile_group_header( data + curr_tg_data_size, tile_idx, AOMMIN(tile_idx + tg_size - 1, tile_cols * tile_rows - 1), - n_log2_tiles, cm->num_tg > 1); + n_log2_tiles, cpi->num_tg > 1); total_size += curr_tg_data_size; tile_data_start += curr_tg_data_size; new_tg = 0; @@ -3652,7 +3669,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx; mode_bc.allow_update_cdf = 1; mode_bc.allow_update_cdf = - mode_bc.allow_update_cdf && !cm->disable_cdf_update; + mode_bc.allow_update_cdf && !cm->features.disable_cdf_update; const int num_planes = av1_num_planes(cm); av1_reset_loop_restoration(&cpi->td.mb.e_mbd, num_planes); @@ -3690,7 +3707,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, saved_wb->bit_buffer += length_field_size; } - if (!first_tg && cm->error_resilient_mode) { + if (!first_tg && cm->features.error_resilient_mode) { // Make room for a duplicate Frame Header OBU. memmove(data + fh_info->total_length, data, curr_tg_data_size); @@ -3704,7 +3721,7 @@ 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. - av1_write_obu_header(cpi, OBU_REDUNDANT_FRAME_HEADER, + av1_write_obu_header(level_params, OBU_REDUNDANT_FRAME_HEADER, obu_extension_header, &data[fh_info->obu_header_byte_offset]); @@ -3725,7 +3742,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, // cdf update. The encoder currently sets it to the largest tile // (but is up to the encoder) aom_wb_overwrite_literal(saved_wb, *largest_tile_id, - cm->log2_tile_cols + cm->log2_tile_rows); + tiles->log2_cols + tiles->log2_rows); // If more than one tile group. tile_size_bytes takes the default value 4 // and does not need to be set. For a single tile group it is set in the // section below. @@ -3735,7 +3752,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, const uint32_t tile_data_size = total_size - tile_data_offset; total_size = - remux_tiles(cm, tile_data_start, tile_data_size, max_tile_size, + remux_tiles(tiles, tile_data_start, tile_data_size, max_tile_size, max_tile_col_size, &tile_size_bytes, &unused); total_size += tile_data_offset; assert(tile_size_bytes >= 1 && tile_size_bytes <= 4); @@ -3770,11 +3787,63 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst, return total_size; } +static size_t av1_write_metadata_obu(const aom_metadata_t *metadata, + uint8_t *const dst) { + size_t coded_metadata_size = 0; + const uint64_t metadata_type = (uint64_t)metadata->type; + if (aom_uleb_encode(metadata_type, sizeof(metadata_type), dst, + &coded_metadata_size) != 0) { + return 0; + } + memcpy(dst + coded_metadata_size, metadata->payload, metadata->sz); + // Add trailing bits. + dst[coded_metadata_size + metadata->sz] = 0x80; + return (uint32_t)(coded_metadata_size + metadata->sz + 1); +} + +static size_t av1_write_metadata_array(AV1_COMP *const cpi, uint8_t *dst) { + if (!cpi->source) return 0; + AV1_COMMON *const cm = &cpi->common; + aom_metadata_array_t *arr = cpi->source->metadata; + if (!arr) return 0; + size_t obu_header_size = 0; + size_t obu_payload_size = 0; + size_t total_bytes_written = 0; + size_t length_field_size = 0; + for (size_t i = 0; i < arr->sz; i++) { + aom_metadata_t *current_metadata = arr->metadata_array[i]; + if (current_metadata && current_metadata->payload) { + if ((cm->current_frame.frame_type == KEY_FRAME && + current_metadata->insert_flag == AOM_MIF_KEY_FRAME) || + (cm->current_frame.frame_type != KEY_FRAME && + current_metadata->insert_flag == AOM_MIF_NON_KEY_FRAME) || + current_metadata->insert_flag == AOM_MIF_ANY_FRAME) { + obu_header_size = + av1_write_obu_header(&cpi->level_params, OBU_METADATA, 0, dst); + obu_payload_size = + av1_write_metadata_obu(current_metadata, dst + obu_header_size); + length_field_size = obu_memmove(obu_header_size, obu_payload_size, dst); + if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, dst) == + AOM_CODEC_OK) { + const size_t obu_size = obu_header_size + obu_payload_size; + dst += obu_size + length_field_size; + total_bytes_written += obu_size + length_field_size; + } else { + aom_internal_error(&cpi->common.error, AOM_CODEC_ERROR, + "Error writing metadata OBU size"); + } + } + } + } + return total_bytes_written; +} + int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, int *const largest_tile_id) { uint8_t *data = dst; uint32_t data_size; AV1_COMMON *const cm = &cpi->common; + AV1LevelParams *const level_params = &cpi->level_params; uint32_t obu_header_size = 0; uint32_t obu_payload_size = 0; FrameHeaderInfo fh_info = { NULL, 0, 0 }; @@ -3790,16 +3859,17 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, bitstream_queue_reset_write(); #endif - cpi->frame_header_count = 0; + level_params->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 = av1_write_obu_header(cpi, OBU_SEQUENCE_HEADER, 0, data); + obu_header_size = + av1_write_obu_header(level_params, OBU_SEQUENCE_HEADER, 0, data); obu_payload_size = - av1_write_sequence_header_obu(cpi, data + obu_header_size); + av1_write_sequence_header_obu(&cm->seq_params, data + obu_header_size); const size_t length_field_size = obu_memmove(obu_header_size, obu_payload_size, data); if (av1_write_uleb_obu_size(obu_header_size, obu_payload_size, data) != @@ -3810,14 +3880,17 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, data += obu_header_size + obu_payload_size + length_field_size; } + // write metadata obus before the frame obu that has the show_frame flag set + if (cm->show_frame) data += av1_write_metadata_array(cpi, data); + const int write_frame_header = - (cm->num_tg > 1 || encode_show_existing_frame(cm)); + (cpi->num_tg > 1 || encode_show_existing_frame(cm)); struct aom_write_bit_buffer saved_wb; if (write_frame_header) { // Write Frame Header OBU. fh_info.frame_header = data; - obu_header_size = - av1_write_obu_header(cpi, OBU_FRAME_HEADER, obu_extension_header, data); + obu_header_size = av1_write_obu_header(level_params, 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/media/libaom/src/av1/encoder/bitstream.h b/media/libaom/src/av1/encoder/bitstream.h index b3b5c12d8e..45151e25e4 100644 --- a/media/libaom/src/av1/encoder/bitstream.h +++ b/media/libaom/src/av1/encoder/bitstream.h @@ -23,14 +23,16 @@ struct aom_write_bit_buffer; // Writes only the OBU Sequence Header payload, and returns the size of the // payload written to 'dst'. This function does not write the OBU header, the // optional extension, or the OBU size to 'dst'. -uint32_t av1_write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst); +uint32_t av1_write_sequence_header_obu(const SequenceHeader *seq_params, + 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 av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type, - int obu_extension, uint8_t *const dst); +uint32_t av1_write_obu_header(AV1LevelParams *const level_params, + OBU_TYPE obu_type, int obu_extension, + uint8_t *const dst); -int av1_write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size, +int av1_write_uleb_obu_size(size_t obu_header_size, size_t obu_payload_size, uint8_t *dest); int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size, diff --git a/media/libaom/src/av1/encoder/block.h b/media/libaom/src/av1/encoder/block.h index 595f32e166..5a74567a46 100644 --- a/media/libaom/src/av1/encoder/block.h +++ b/media/libaom/src/av1/encoder/block.h @@ -22,24 +22,24 @@ #endif #include "av1/encoder/hash.h" -#if CONFIG_DIST_8X8 -#include "aom/aomcx.h" -#endif #ifdef __cplusplus extern "C" { #endif -// 1: use classic model 0: use count or saving stats -#define USE_TPL_CLASSIC_MODEL 0 #define MC_FLOW_BSIZE_1D 16 #define MC_FLOW_NUM_PELS (MC_FLOW_BSIZE_1D * MC_FLOW_BSIZE_1D) #define MAX_MC_FLOW_BLK_IN_SB (MAX_SB_SIZE / MC_FLOW_BSIZE_1D) -#define MAX_WINNER_MODE_COUNT 3 +#define MAX_WINNER_MODE_COUNT_INTRA 3 +#define MAX_WINNER_MODE_COUNT_INTER 1 typedef struct { MB_MODE_INFO mbmi; + RD_STATS rd_cost; int64_t rd; + int rate_y; + int rate_uv; uint8_t color_index_map[64 * 64]; + THR_MODES mode_index; } WinnerModeStats; typedef struct { @@ -48,6 +48,13 @@ typedef struct { unsigned int var; } DIFF; +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_ESTIMATE_YRD_TRELLIS_OPT // Disable trellis in estimate_yrd_for_sb +} UENUM1BYTE(TRELLIS_OPT_TYPE); + typedef struct macroblock_plane { DECLARE_ALIGNED(32, int16_t, src_diff[MAX_SB_SQUARE]); tran_low_t *qcoeff; @@ -100,7 +107,7 @@ typedef struct { uint8_t ref_mv_count[MODE_CTX_REF_FRAMES]; } MB_MODE_INFO_EXT; -// Structure to store winner reference mode information at frame level. This +// Structure to store best mode information at frame level. This // frame level information will be used during bitstream preparation stage. typedef struct { CANDIDATE_MV ref_mv_stack[USABLE_REF_MV_STACK_SIZE]; @@ -112,13 +119,6 @@ typedef struct { uint8_t ref_mv_count; } MB_MODE_INFO_EXT_FRAME; -typedef struct { - int col_min; - int col_max; - int row_min; - int row_max; -} MvLimits; - typedef struct { uint8_t best_palette_color_map[MAX_PALETTE_SQUARE]; int kmeans_data_buf[2 * MAX_PALETTE_SQUARE]; @@ -182,30 +182,23 @@ typedef struct { // 4: NEAREST, NEW, NEAR, GLOBAL #define SINGLE_REF_MODES ((REF_FRAMES - 1) * 4) -#define MAX_INTERP_FILTER_STATS 64 -typedef struct { - int_interpfilters filters; - int_mv mv[2]; - int8_t ref_frames[2]; - COMPOUND_TYPE comp_type; - int64_t rd; - 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]; + int32_t model_rate[COMPOUND_TYPES]; + int64_t model_dist[COMPOUND_TYPES]; + int comp_rs2[COMPOUND_TYPES]; int_mv mv[2]; MV_REFERENCE_FRAME ref_frames[2]; PREDICTION_MODE mode; int_interpfilters filter; int ref_mv_idx; int is_global[2]; + INTERINTER_COMPOUND_DATA interinter_comp; } COMP_RD_STATS; -// Struct for buffers used by compound_type_rd() function. +// Struct for buffers used by av1_compound_type_rd() function. // For sizes and alignment of these arrays, refer to // alloc_compound_type_rd_buffers() function. typedef struct { @@ -216,6 +209,14 @@ typedef struct { uint8_t *tmp_best_mask_buf; // backup of the best segmentation mask } CompoundTypeRdBuffers; +enum { + MV_COST_ENTROPY, // Use the entropy rate of the mv as the cost + MV_COST_L1_LOWRES, // Use the l1 norm of the mv as the cost (<480p) + MV_COST_L1_MIDRES, // Use the l1 norm of the mv as the cost (>=480p) + MV_COST_L1_HDRES, // Use the l1 norm of the mv as the cost (>=720p) + MV_COST_NONE // Use 0 as as cost irrespective of the current mv +} UENUM1BYTE(MV_COST_TYPE); + struct inter_modes_info; typedef struct macroblock MACROBLOCK; struct macroblock { @@ -226,10 +227,6 @@ struct macroblock { // to select transform kernel. int rd_model; - // [comp_idx][saved stat_idx] - INTERPOLATION_FILTER_STATS interp_filter_stats[2][MAX_INTERP_FILTER_STATS]; - int interp_filter_stats_idx[2]; - // prune_comp_search_by_single_result (3:MAX_REF_MV_SEARCH) SimpleRDState simple_rd_state[SINGLE_REF_MODES][3]; @@ -249,7 +246,8 @@ struct macroblock { MB_MODE_INFO_EXT *mbmi_ext; MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame; // Array of mode stats for winner mode processing - WinnerModeStats winner_mode_stats[MAX_WINNER_MODE_COUNT]; + WinnerModeStats winner_mode_stats[AOMMAX(MAX_WINNER_MODE_COUNT_INTRA, + MAX_WINNER_MODE_COUNT_INTER)]; int winner_mode_count; int skip_block; int qindex; @@ -259,15 +257,10 @@ struct macroblock { int errorperbit; // The equivalend SAD error of one (whole) bit at the current quantizer // for large blocks. - int sadperbit16; - // The equivalend SAD error of one (whole) bit at the current quantizer - // for sub-8x8 blocks. - int sadperbit4; + int sadperbit; int rdmult; int mb_energy; int sb_energy_level; - int *m_search_count_ptr; - int *ex_search_count_ptr; unsigned int txb_split_count; #if CONFIG_SPEED_STATS @@ -314,25 +307,18 @@ struct macroblock { struct inter_modes_info *inter_modes_info; - // buffer for hash value calculation of a block - // used only in av1_get_block_hash_value() - // [first hash/second hash] - // [two buffers used ping-pong] - uint32_t *hash_value_buffer[2][2]; - - CRC_CALCULATOR crc_calculator1; - CRC_CALCULATOR crc_calculator2; - int g_crc_initialized; + // Contains the hash table, hash function, and buffer used for intrabc + IntraBCHashInfo intrabc_hash_info; // These define limits to motion vector components to prevent them // from extending outside the UMV borders - MvLimits mv_limits; + FullMvLimits mv_limits; uint8_t blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; uint8_t tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - int skip; - int skip_chroma_rd; + // Force the coding block to skip transform and quantization. + int force_skip; int skip_cost[SKIP_CONTEXTS][2]; int skip_mode; // 0: off; 1: on @@ -401,14 +387,6 @@ struct macroblock { // Used to store sub partition's choices. MV pred_mv[REF_FRAMES]; - // Store the best motion vector during motion search - int_mv best_mv; - // Store the second best motion vector during full-pixel motion search - int_mv second_best_mv; - - // 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. @@ -418,15 +396,12 @@ struct macroblock { int use_default_intra_tx_type; // use default transform and skip transform type search for inter modes int use_default_inter_tx_type; -#if CONFIG_DIST_8X8 - int using_dist_8x8; - aom_tune_metric tune_metric; -#endif // CONFIG_DIST_8X8 int comp_idx_cost[COMP_INDEX_CONTEXTS][2]; int comp_group_idx_cost[COMP_GROUP_IDX_CONTEXTS][2]; int must_find_valid_partition; int recalc_luma_mc_data; // Flag to indicate recalculation of MC data during // interpolation filter search + int prune_mode; uint32_t tx_domain_dist_threshold; int use_transform_domain_distortion; // The likelihood of an edge existing in the block (using partial Canny edge @@ -455,21 +430,56 @@ struct macroblock { float log_q; #endif int thresh_freq_fact[BLOCK_SIZES_ALL][MAX_MODES]; + // 0 - 128x128 + // 1-2 - 128x64 + // 3-4 - 64x128 + // 5-8 - 64x64 + // 9-16 - 64x32 + // 17-24 - 32x64 + // 25-40 - 32x32 + // 41-104 - 16x16 uint8_t variance_low[105]; + uint8_t content_state_sb; // Strong color activity detection. Used in REALTIME coding mode to enhance // the visual quality at the boundary of moving color objects. uint8_t color_sensitivity[2]; + int nonrd_prune_ref_frame_search; // Used to control the tx size search evaluation for mode processing // (normal/winner mode) int tx_size_search_method; - TX_MODE tx_mode; + // This tx_mode_search_type is used internally by the encoder, and is not + // written to the bitstream. It determines what kind of tx_mode should be + // searched. For example, we might set it to TX_MODE_LARGEST to find a good + // candidate, then use TX_MODE_SELECT on it + TX_MODE tx_mode_search_type; + + // Used to control aggressiveness of skip flag prediction for mode processing + // (normal/winner mode) + unsigned int predict_skip_level; // Copy out this SB's TPL block stats. int valid_cost_b; int64_t inter_cost_b[MAX_MC_FLOW_BLK_IN_SB * MAX_MC_FLOW_BLK_IN_SB]; int64_t intra_cost_b[MAX_MC_FLOW_BLK_IN_SB * MAX_MC_FLOW_BLK_IN_SB]; + int_mv mv_b[MAX_MC_FLOW_BLK_IN_SB * MAX_MC_FLOW_BLK_IN_SB] + [INTER_REFS_PER_FRAME]; int cost_stride; + + // The type of mv cost used during motion search + MV_COST_TYPE mv_cost_type; + + uint8_t search_ref_frame[REF_FRAMES]; + +#if CONFIG_AV1_HIGHBITDEPTH + void (*fwd_txfm4x4)(const int16_t *input, tran_low_t *output, int stride); + void (*inv_txfm_add)(const tran_low_t *input, uint8_t *dest, int stride, + int eob); +#else + void (*fwd_txfm4x4)(const int16_t *input, int16_t *output, int stride); + void (*inv_txfm_add)(const int16_t *input, uint8_t *dest, int stride, + int eob); +#endif }; // Only consider full SB, MC_FLOW_BSIZE_1D = 16. diff --git a/media/libaom/src/av1/encoder/cnn.c b/media/libaom/src/av1/encoder/cnn.c index d4f2e7de64..5d8a236a06 100644 --- a/media/libaom/src/av1/encoder/cnn.c +++ b/media/libaom/src/av1/encoder/cnn.c @@ -14,7 +14,7 @@ #include "aom_dsp/aom_dsp_common.h" #include "av1/encoder/cnn.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #define CLAMPINDEX(a, hi) ((a) < 0 ? 0 : ((a) >= (hi) ? ((hi)-1) : (a))) diff --git a/media/libaom/src/av1/encoder/compound_type.c b/media/libaom/src/av1/encoder/compound_type.c new file mode 100644 index 0000000000..42095b79e3 --- /dev/null +++ b/media/libaom/src/av1/encoder/compound_type.c @@ -0,0 +1,1508 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "av1/common/pred_common.h" +#include "av1/encoder/compound_type.h" +#include "av1/encoder/model_rd.h" +#include "av1/encoder/motion_search_facade.h" +#include "av1/encoder/rdopt_utils.h" +#include "av1/encoder/reconinter_enc.h" +#include "av1/encoder/tx_search.h" + +typedef int64_t (*pick_interinter_mask_type)( + const AV1_COMP *const cpi, MACROBLOCK *x, const BLOCK_SIZE bsize, + const uint8_t *const p0, const uint8_t *const p1, + const int16_t *const residual1, const int16_t *const diff10, + uint64_t *best_sse); + +// Checks if characteristics of search match +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_model_rate, + int64_t *comp_model_dist, int *comp_rs2) { + // 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 + if (st->filter.as_int != mi->interp_filters.as_int) return 0; + + const MACROBLOCKD *const xd = &x->e_mbd; + // Match MV and reference indices + for (int i = 0; i < 2; ++i) { + if ((st->ref_frames[i] != mi->ref_frame[i]) || + (st->mv[i].as_int != mi->mv[i].as_int)) { + return 0; + } + const WarpedMotionParams *const wm = &xd->global_motion[mi->ref_frame[i]]; + if (is_global_mv_block(mi, wm->wmtype) != st->is_global[i]) return 0; + } + + // Store the stats for COMPOUND_AVERAGE and COMPOUND_DISTWTD + for (int comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; + comp_type++) { + comp_rate[comp_type] = st->rate[comp_type]; + comp_dist[comp_type] = st->dist[comp_type]; + comp_model_rate[comp_type] = st->model_rate[comp_type]; + comp_model_dist[comp_type] = st->model_dist[comp_type]; + comp_rs2[comp_type] = st->comp_rs2[comp_type]; + } + + // 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)) || + (cpi->sf.inter_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_rate[COMPOUND_WEDGE], &st->model_rate[COMPOUND_WEDGE], + sizeof(comp_model_rate[COMPOUND_WEDGE]) * 2); + memcpy(&comp_model_dist[COMPOUND_WEDGE], &st->model_dist[COMPOUND_WEDGE], + sizeof(comp_model_dist[COMPOUND_WEDGE]) * 2); + memcpy(&comp_rs2[COMPOUND_WEDGE], &st->comp_rs2[COMPOUND_WEDGE], + sizeof(comp_rs2[COMPOUND_WEDGE]) * 2); + } + return 1; +} + +// 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 AV1_COMP *const cpi, + const MACROBLOCK *x, + const MB_MODE_INFO *const mbmi, + int32_t *comp_rate, int64_t *comp_dist, + int32_t *comp_model_rate, + int64_t *comp_model_dist, int *comp_rs2, + int *match_index) { + for (int j = 0; j < x->comp_rd_stats_idx; ++j) { + if (is_comp_rd_match(cpi, x, &x->comp_rd_stats[j], mbmi, comp_rate, + comp_dist, comp_model_rate, comp_model_dist, + comp_rs2)) { + *match_index = j; + return 1; + } + } + return 0; // no match result found +} + +static INLINE bool enable_wedge_search(MACROBLOCK *const x, + const AV1_COMP *const cpi) { + // Enable wedge search if source variance and edge strength are above + // the thresholds. + return x->source_variance > + cpi->sf.inter_sf.disable_wedge_search_var_thresh && + x->edge_strength > cpi->sf.inter_sf.disable_wedge_search_edge_thresh; +} + +static INLINE bool enable_wedge_interinter_search(MACROBLOCK *const x, + const AV1_COMP *const cpi) { + return enable_wedge_search(x, cpi) && cpi->oxcf.enable_interinter_wedge && + !cpi->sf.inter_sf.disable_interinter_wedge; +} + +static INLINE bool enable_wedge_interintra_search(MACROBLOCK *const x, + const AV1_COMP *const cpi) { + return enable_wedge_search(x, cpi) && cpi->oxcf.enable_interintra_wedge && + !cpi->sf.inter_sf.disable_wedge_interintra_search; +} + +static int8_t estimate_wedge_sign(const AV1_COMP *cpi, const MACROBLOCK *x, + const BLOCK_SIZE bsize, const uint8_t *pred0, + int stride0, const uint8_t *pred1, + int stride1) { + static const BLOCK_SIZE split_qtr[BLOCK_SIZES_ALL] = { + // 4X4 + BLOCK_INVALID, + // 4X8, 8X4, 8X8 + BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X4, + // 8X16, 16X8, 16X16 + BLOCK_4X8, BLOCK_8X4, BLOCK_8X8, + // 16X32, 32X16, 32X32 + BLOCK_8X16, BLOCK_16X8, BLOCK_16X16, + // 32X64, 64X32, 64X64 + BLOCK_16X32, BLOCK_32X16, BLOCK_32X32, + // 64x128, 128x64, 128x128 + BLOCK_32X64, BLOCK_64X32, BLOCK_64X64, + // 4X16, 16X4, 8X32 + BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X16, + // 32X8, 16X64, 64X16 + BLOCK_16X4, BLOCK_8X32, BLOCK_32X8 + }; + const struct macroblock_plane *const p = &x->plane[0]; + const uint8_t *src = p->src.buf; + int src_stride = p->src.stride; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const int bw_by2 = bw >> 1; + const int bh_by2 = bh >> 1; + uint32_t esq[2][2]; + int64_t tl, br; + + const BLOCK_SIZE f_index = split_qtr[bsize]; + assert(f_index != BLOCK_INVALID); + + if (is_cur_buf_hbd(&x->e_mbd)) { + pred0 = CONVERT_TO_BYTEPTR(pred0); + pred1 = CONVERT_TO_BYTEPTR(pred1); + } + + // Residual variance computation over relevant quandrants in order to + // find TL + BR, TL = sum(1st,2nd,3rd) quadrants of (pred0 - pred1), + // BR = sum(2nd,3rd,4th) quadrants of (pred1 - pred0) + // The 2nd and 3rd quadrants cancel out in TL + BR + // Hence TL + BR = 1st quadrant of (pred0-pred1) + 4th of (pred1-pred0) + // TODO(nithya): Sign estimation assumes 45 degrees (1st and 4th quadrants) + // for all codebooks; experiment with other quadrant combinations for + // 0, 90 and 135 degrees also. + cpi->fn_ptr[f_index].vf(src, src_stride, pred0, stride0, &esq[0][0]); + cpi->fn_ptr[f_index].vf(src + bh_by2 * src_stride + bw_by2, src_stride, + pred0 + bh_by2 * stride0 + bw_by2, stride0, + &esq[0][1]); + cpi->fn_ptr[f_index].vf(src, src_stride, pred1, stride1, &esq[1][0]); + cpi->fn_ptr[f_index].vf(src + bh_by2 * src_stride + bw_by2, src_stride, + pred1 + bh_by2 * stride1 + bw_by2, stride0, + &esq[1][1]); + + tl = ((int64_t)esq[0][0]) - ((int64_t)esq[1][0]); + br = ((int64_t)esq[1][1]) - ((int64_t)esq[0][1]); + return (tl + br > 0); +} + +// Choose the best wedge index and sign +static int64_t pick_wedge(const AV1_COMP *const cpi, const MACROBLOCK *const x, + const BLOCK_SIZE bsize, const uint8_t *const p0, + const int16_t *const residual1, + const int16_t *const diff10, + int8_t *const best_wedge_sign, + int8_t *const best_wedge_index, uint64_t *best_sse) { + const MACROBLOCKD *const xd = &x->e_mbd; + const struct buf_2d *const src = &x->plane[0].src; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const int N = bw * bh; + assert(N >= 64); + int rate; + int64_t dist; + int64_t rd, best_rd = INT64_MAX; + int8_t wedge_index; + int8_t wedge_sign; + const int8_t wedge_types = get_wedge_types_lookup(bsize); + const uint8_t *mask; + uint64_t sse; + const int hbd = is_cur_buf_hbd(xd); + const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; + + DECLARE_ALIGNED(32, int16_t, residual0[MAX_SB_SQUARE]); // src - pred0 +#if CONFIG_AV1_HIGHBITDEPTH + if (hbd) { + aom_highbd_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, + CONVERT_TO_BYTEPTR(p0), bw, xd->bd); + } else { + aom_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, p0, bw); + } +#else + (void)hbd; + aom_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, p0, bw); +#endif + + int64_t sign_limit = ((int64_t)aom_sum_squares_i16(residual0, N) - + (int64_t)aom_sum_squares_i16(residual1, N)) * + (1 << WEDGE_WEIGHT_BITS) / 2; + int16_t *ds = residual0; + + av1_wedge_compute_delta_squares(ds, residual0, residual1, N); + + for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) { + mask = av1_get_contiguous_soft_mask(wedge_index, 0, bsize); + + wedge_sign = av1_wedge_sign_from_residuals(ds, mask, N, sign_limit); + + mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); + sse = av1_wedge_sse_from_residuals(residual1, diff10, mask, N); + sse = ROUND_POWER_OF_TWO(sse, bd_round); + + model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, + &rate, &dist); + // int rate2; + // int64_t dist2; + // model_rd_with_curvfit(cpi, x, bsize, 0, sse, N, &rate2, &dist2); + // printf("sse %"PRId64": leagacy: %d %"PRId64", curvfit %d %"PRId64"\n", + // sse, rate, dist, rate2, dist2); dist = dist2; + // rate = rate2; + + rate += x->wedge_idx_cost[bsize][wedge_index]; + rd = RDCOST(x->rdmult, rate, dist); + + if (rd < best_rd) { + *best_wedge_index = wedge_index; + *best_wedge_sign = wedge_sign; + best_rd = rd; + *best_sse = sse; + } + } + + return best_rd - + RDCOST(x->rdmult, x->wedge_idx_cost[bsize][*best_wedge_index], 0); +} + +// Choose the best wedge index the specified sign +static int64_t pick_wedge_fixed_sign( + const AV1_COMP *const cpi, const MACROBLOCK *const x, + const BLOCK_SIZE bsize, const int16_t *const residual1, + const int16_t *const diff10, const int8_t wedge_sign, + int8_t *const best_wedge_index, uint64_t *best_sse) { + const MACROBLOCKD *const xd = &x->e_mbd; + + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const int N = bw * bh; + assert(N >= 64); + int rate; + int64_t dist; + int64_t rd, best_rd = INT64_MAX; + int8_t wedge_index; + const int8_t wedge_types = get_wedge_types_lookup(bsize); + const uint8_t *mask; + uint64_t sse; + const int hbd = is_cur_buf_hbd(xd); + const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; + for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) { + mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); + sse = av1_wedge_sse_from_residuals(residual1, diff10, mask, N); + sse = ROUND_POWER_OF_TWO(sse, bd_round); + + model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, + &rate, &dist); + rate += x->wedge_idx_cost[bsize][wedge_index]; + rd = RDCOST(x->rdmult, rate, dist); + + if (rd < best_rd) { + *best_wedge_index = wedge_index; + best_rd = rd; + *best_sse = sse; + } + } + return best_rd - + RDCOST(x->rdmult, x->wedge_idx_cost[bsize][*best_wedge_index], 0); +} + +static int64_t pick_interinter_wedge( + const AV1_COMP *const cpi, MACROBLOCK *const x, const BLOCK_SIZE bsize, + const uint8_t *const p0, const uint8_t *const p1, + const int16_t *const residual1, const int16_t *const diff10, + uint64_t *best_sse) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int bw = block_size_wide[bsize]; + + int64_t rd; + int8_t wedge_index = -1; + int8_t wedge_sign = 0; + + assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize)); + assert(cpi->common.seq_params.enable_masked_compound); + + if (cpi->sf.inter_sf.fast_wedge_sign_estimate) { + wedge_sign = estimate_wedge_sign(cpi, x, bsize, p0, bw, p1, bw); + rd = pick_wedge_fixed_sign(cpi, x, bsize, residual1, diff10, wedge_sign, + &wedge_index, best_sse); + } else { + rd = pick_wedge(cpi, x, bsize, p0, residual1, diff10, &wedge_sign, + &wedge_index, best_sse); + } + + mbmi->interinter_comp.wedge_sign = wedge_sign; + mbmi->interinter_comp.wedge_index = wedge_index; + return rd; +} + +static int64_t pick_interinter_seg(const AV1_COMP *const cpi, + MACROBLOCK *const x, const BLOCK_SIZE bsize, + const uint8_t *const p0, + const uint8_t *const p1, + const int16_t *const residual1, + const int16_t *const diff10, + uint64_t *best_sse) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + const int N = 1 << num_pels_log2_lookup[bsize]; + int rate; + int64_t dist; + DIFFWTD_MASK_TYPE cur_mask_type; + int64_t best_rd = INT64_MAX; + DIFFWTD_MASK_TYPE best_mask_type = 0; + const int hbd = is_cur_buf_hbd(xd); + const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; + DECLARE_ALIGNED(16, uint8_t, seg_mask[2 * MAX_SB_SQUARE]); + uint8_t *tmp_mask[2] = { xd->seg_mask, seg_mask }; + // try each mask type and its inverse + for (cur_mask_type = 0; cur_mask_type < DIFFWTD_MASK_TYPES; cur_mask_type++) { + // build mask and inverse + if (hbd) + av1_build_compound_diffwtd_mask_highbd( + tmp_mask[cur_mask_type], cur_mask_type, CONVERT_TO_BYTEPTR(p0), bw, + CONVERT_TO_BYTEPTR(p1), bw, bh, bw, xd->bd); + else + av1_build_compound_diffwtd_mask(tmp_mask[cur_mask_type], cur_mask_type, + p0, bw, p1, bw, bh, bw); + + // compute rd for mask + uint64_t sse = av1_wedge_sse_from_residuals(residual1, diff10, + tmp_mask[cur_mask_type], N); + sse = ROUND_POWER_OF_TWO(sse, bd_round); + + model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, + &rate, &dist); + const int64_t rd0 = RDCOST(x->rdmult, rate, dist); + + if (rd0 < best_rd) { + best_mask_type = cur_mask_type; + best_rd = rd0; + *best_sse = sse; + } + } + mbmi->interinter_comp.mask_type = best_mask_type; + if (best_mask_type == DIFFWTD_38_INV) { + memcpy(xd->seg_mask, seg_mask, N * 2); + } + return best_rd; +} + +static int64_t pick_interintra_wedge(const AV1_COMP *const cpi, + const MACROBLOCK *const x, + const BLOCK_SIZE bsize, + const uint8_t *const p0, + const uint8_t *const p1) { + const MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(av1_is_wedge_used(bsize)); + assert(cpi->common.seq_params.enable_interintra_compound); + + const struct buf_2d *const src = &x->plane[0].src; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + DECLARE_ALIGNED(32, int16_t, residual1[MAX_SB_SQUARE]); // src - pred1 + DECLARE_ALIGNED(32, int16_t, diff10[MAX_SB_SQUARE]); // pred1 - pred0 +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + aom_highbd_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, + CONVERT_TO_BYTEPTR(p1), bw, xd->bd); + aom_highbd_subtract_block(bh, bw, diff10, bw, CONVERT_TO_BYTEPTR(p1), bw, + CONVERT_TO_BYTEPTR(p0), bw, xd->bd); + } else { + aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, p1, bw); + aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw); + } +#else + aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, p1, bw); + aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw); +#endif + int8_t wedge_index = -1; + uint64_t sse; + int64_t rd = pick_wedge_fixed_sign(cpi, x, bsize, residual1, diff10, 0, + &wedge_index, &sse); + + mbmi->interintra_wedge_index = wedge_index; + return rd; +} + +static AOM_INLINE void get_inter_predictors_masked_compound( + MACROBLOCK *x, const BLOCK_SIZE bsize, uint8_t **preds0, uint8_t **preds1, + int16_t *residual1, int16_t *diff10, int *strides) { + MACROBLOCKD *xd = &x->e_mbd; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + // get inter predictors to use for masked compound modes + av1_build_inter_predictors_for_planes_single_buf(xd, bsize, 0, 0, 0, preds0, + strides); + av1_build_inter_predictors_for_planes_single_buf(xd, bsize, 0, 0, 1, preds1, + strides); + const struct buf_2d *const src = &x->plane[0].src; +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + aom_highbd_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, + CONVERT_TO_BYTEPTR(*preds1), bw, xd->bd); + aom_highbd_subtract_block(bh, bw, diff10, bw, CONVERT_TO_BYTEPTR(*preds1), + bw, CONVERT_TO_BYTEPTR(*preds0), bw, xd->bd); + } else { + aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, *preds1, + bw); + aom_subtract_block(bh, bw, diff10, bw, *preds1, bw, *preds0, bw); + } +#else + aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, *preds1, bw); + aom_subtract_block(bh, bw, diff10, bw, *preds1, bw, *preds0, bw); +#endif +} + +// Computes the rd cost for the given interintra mode and updates the best +static INLINE void compute_best_interintra_mode( + const AV1_COMP *const cpi, MB_MODE_INFO *mbmi, MACROBLOCKD *xd, + MACROBLOCK *const x, const int *const interintra_mode_cost, + const BUFFER_SET *orig_dst, uint8_t *intrapred, const uint8_t *tmp_buf, + INTERINTRA_MODE *best_interintra_mode, int64_t *best_interintra_rd, + INTERINTRA_MODE interintra_mode, BLOCK_SIZE bsize) { + const AV1_COMMON *const cm = &cpi->common; + int rate, skip_txfm_sb; + int64_t dist, skip_sse_sb; + const int bw = block_size_wide[bsize]; + mbmi->interintra_mode = interintra_mode; + int rmode = interintra_mode_cost[interintra_mode]; + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); + model_rd_sb_fn[MODELRD_TYPE_INTERINTRA](cpi, bsize, x, xd, 0, 0, &rate, &dist, + &skip_txfm_sb, &skip_sse_sb, NULL, + NULL, NULL); + int64_t rd = RDCOST(x->rdmult, rate + rmode, dist); + if (rd < *best_interintra_rd) { + *best_interintra_rd = rd; + *best_interintra_mode = mbmi->interintra_mode; + } +} + +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; + if (ref_best_rd < 0) return INT64_MAX; + av1_subtract_plane(x, bs, 0); + x->rd_model = LOW_TXFM_RD; + const int skip_trellis = (cpi->optimize_seg_arr[xd->mi[0]->segment_id] == + NO_ESTIMATE_YRD_TRELLIS_OPT); + const int64_t rd = + av1_uniform_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) { + const int skip_ctx = av1_get_skip_context(xd); + if (rd_stats->skip) { + const int s1 = x->skip_cost[skip_ctx][1]; + rd_stats->rate = s1; + } else { + const int s0 = x->skip_cost[skip_ctx][0]; + rd_stats->rate += s0; + } + } + return rd; +} + +// Computes the rd_threshold for smooth interintra rd search. +static AOM_INLINE int64_t compute_rd_thresh(MACROBLOCK *const x, + int total_mode_rate, + int64_t ref_best_rd) { + const int64_t rd_thresh = get_rd_thresh_from_best_rd( + ref_best_rd, (1 << INTER_INTRA_RD_THRESH_SHIFT), + INTER_INTRA_RD_THRESH_SCALE); + const int64_t mode_rd = RDCOST(x->rdmult, total_mode_rate, 0); + return (rd_thresh - mode_rd); +} + +// Computes the best wedge interintra mode +static AOM_INLINE int64_t compute_best_wedge_interintra( + const AV1_COMP *const cpi, MB_MODE_INFO *mbmi, MACROBLOCKD *xd, + MACROBLOCK *const x, const int *const interintra_mode_cost, + const BUFFER_SET *orig_dst, uint8_t *intrapred_, uint8_t *tmp_buf_, + int *best_mode, int *best_wedge_index, BLOCK_SIZE bsize) { + const AV1_COMMON *const cm = &cpi->common; + const int bw = block_size_wide[bsize]; + int64_t best_interintra_rd_wedge = INT64_MAX; + int64_t best_total_rd = INT64_MAX; + uint8_t *intrapred = get_buf_by_bd(xd, intrapred_); + for (INTERINTRA_MODE mode = 0; mode < INTERINTRA_MODES; ++mode) { + mbmi->interintra_mode = mode; + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + int64_t rd = pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); + const int rate_overhead = + interintra_mode_cost[mode] + + x->wedge_idx_cost[bsize][mbmi->interintra_wedge_index]; + const int64_t total_rd = rd + RDCOST(x->rdmult, rate_overhead, 0); + if (total_rd < best_total_rd) { + best_total_rd = total_rd; + best_interintra_rd_wedge = rd; + *best_mode = mbmi->interintra_mode; + *best_wedge_index = mbmi->interintra_wedge_index; + } + } + return best_interintra_rd_wedge; +} + +int av1_handle_inter_intra_mode(const AV1_COMP *const cpi, MACROBLOCK *const x, + BLOCK_SIZE bsize, MB_MODE_INFO *mbmi, + HandleInterModeArgs *args, int64_t ref_best_rd, + int *rate_mv, int *tmp_rate2, + const BUFFER_SET *orig_dst) { + const int try_smooth_interintra = cpi->oxcf.enable_smooth_interintra && + !cpi->sf.inter_sf.disable_smooth_interintra; + const int is_wedge_used = av1_is_wedge_used(bsize); + const int try_wedge_interintra = + is_wedge_used && enable_wedge_interintra_search(x, cpi); + if (!try_smooth_interintra && !try_wedge_interintra) return -1; + + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + int64_t rd = INT64_MAX; + const int bw = block_size_wide[bsize]; + DECLARE_ALIGNED(16, uint8_t, tmp_buf_[2 * MAX_INTERINTRA_SB_SQUARE]); + DECLARE_ALIGNED(16, uint8_t, intrapred_[2 * MAX_INTERINTRA_SB_SQUARE]); + uint8_t *tmp_buf = get_buf_by_bd(xd, tmp_buf_); + uint8_t *intrapred = get_buf_by_bd(xd, intrapred_); + const int *const interintra_mode_cost = + x->interintra_mode_cost[size_group_lookup[bsize]]; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + // Single reference inter prediction + mbmi->ref_frame[1] = NONE_FRAME; + xd->plane[0].dst.buf = tmp_buf; + xd->plane[0].dst.stride = bw; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + const int num_planes = av1_num_planes(cm); + + // Restore the buffers for intra prediction + restore_dst_buf(xd, *orig_dst, num_planes); + mbmi->ref_frame[1] = INTRA_FRAME; + INTERINTRA_MODE best_interintra_mode = + args->inter_intra_mode[mbmi->ref_frame[0]]; + + // Compute smooth_interintra + int64_t best_interintra_rd_nowedge = INT64_MAX; + int best_mode_rate = INT_MAX; + if (try_smooth_interintra) { + mbmi->use_wedge_interintra = 0; + int interintra_mode_reuse = 1; + if (cpi->sf.inter_sf.reuse_inter_intra_mode == 0 || + best_interintra_mode == INTERINTRA_MODES) { + interintra_mode_reuse = 0; + int64_t best_interintra_rd = INT64_MAX; + for (INTERINTRA_MODE cur_mode = 0; cur_mode < INTERINTRA_MODES; + ++cur_mode) { + if ((!cpi->oxcf.enable_smooth_intra || + cpi->sf.intra_sf.disable_smooth_intra) && + cur_mode == II_SMOOTH_PRED) + continue; + compute_best_interintra_mode(cpi, mbmi, xd, x, interintra_mode_cost, + orig_dst, intrapred, tmp_buf, + &best_interintra_mode, &best_interintra_rd, + cur_mode, bsize); + } + args->inter_intra_mode[mbmi->ref_frame[0]] = best_interintra_mode; + } + assert(IMPLIES(!cpi->oxcf.enable_smooth_interintra || + cpi->sf.inter_sf.disable_smooth_interintra, + best_interintra_mode != II_SMOOTH_PRED)); + // Recompute prediction if required + if (interintra_mode_reuse || best_interintra_mode != INTERINTRA_MODES - 1) { + mbmi->interintra_mode = best_interintra_mode; + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); + } + + // Compute rd cost for best smooth_interintra + RD_STATS rd_stats; + const int rmode = interintra_mode_cost[best_interintra_mode] + + (is_wedge_used ? x->wedge_interintra_cost[bsize][0] : 0); + const int total_mode_rate = rmode + *rate_mv; + const int64_t rd_thresh = + compute_rd_thresh(x, total_mode_rate, ref_best_rd); + rd = estimate_yrd_for_sb(cpi, bsize, x, rd_thresh, &rd_stats); + if (rd != INT64_MAX) { + rd = RDCOST(x->rdmult, total_mode_rate + rd_stats.rate, rd_stats.dist); + } else { + return -1; + } + best_interintra_rd_nowedge = rd; + best_mode_rate = rmode; + // Return early if best_interintra_rd_nowedge not good enough + if (ref_best_rd < INT64_MAX && + (best_interintra_rd_nowedge >> INTER_INTRA_RD_THRESH_SHIFT) * + INTER_INTRA_RD_THRESH_SCALE > + ref_best_rd) { + return -1; + } + } + + // Compute wedge interintra + int64_t best_interintra_rd_wedge = INT64_MAX; + if (try_wedge_interintra) { + mbmi->use_wedge_interintra = 1; + if (!cpi->sf.inter_sf.fast_interintra_wedge_search) { + // Exhaustive search of all wedge and mode combinations. + int best_mode = 0; + int best_wedge_index = 0; + best_interintra_rd_wedge = compute_best_wedge_interintra( + cpi, mbmi, xd, x, interintra_mode_cost, orig_dst, intrapred_, + tmp_buf_, &best_mode, &best_wedge_index, bsize); + mbmi->interintra_mode = best_mode; + mbmi->interintra_wedge_index = best_wedge_index; + if (best_mode != INTERINTRA_MODES - 1) { + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + } + } else if (!try_smooth_interintra) { + if (best_interintra_mode == INTERINTRA_MODES) { + mbmi->interintra_mode = INTERINTRA_MODES - 1; + best_interintra_mode = INTERINTRA_MODES - 1; + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + // Pick wedge mask based on INTERINTRA_MODES - 1 + best_interintra_rd_wedge = + pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); + // Find the best interintra mode for the chosen wedge mask + for (INTERINTRA_MODE cur_mode = 0; cur_mode < INTERINTRA_MODES; + ++cur_mode) { + compute_best_interintra_mode( + cpi, mbmi, xd, x, interintra_mode_cost, orig_dst, intrapred, + tmp_buf, &best_interintra_mode, &best_interintra_rd_wedge, + cur_mode, bsize); + } + args->inter_intra_mode[mbmi->ref_frame[0]] = best_interintra_mode; + mbmi->interintra_mode = best_interintra_mode; + + // Recompute prediction if required + if (best_interintra_mode != INTERINTRA_MODES - 1) { + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + } + } else { + // Pick wedge mask for the best interintra mode (reused) + mbmi->interintra_mode = best_interintra_mode; + av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, + intrapred, bw); + best_interintra_rd_wedge = + pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); + } + } else { + // Pick wedge mask for the best interintra mode from smooth_interintra + best_interintra_rd_wedge = + pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); + } + + const int rate_overhead = + interintra_mode_cost[mbmi->interintra_mode] + + x->wedge_idx_cost[bsize][mbmi->interintra_wedge_index] + + x->wedge_interintra_cost[bsize][1]; + best_interintra_rd_wedge += RDCOST(x->rdmult, rate_overhead + *rate_mv, 0); + + const int_mv mv0 = mbmi->mv[0]; + int_mv tmp_mv = mv0; + rd = INT64_MAX; + int tmp_rate_mv = 0; + // Refine motion vector for NEWMV case. + if (have_newmv_in_inter_mode(mbmi->mode)) { + int rate_sum, skip_txfm_sb; + int64_t dist_sum, skip_sse_sb; + // get negative of mask + const uint8_t *mask = + av1_get_contiguous_soft_mask(mbmi->interintra_wedge_index, 1, bsize); + av1_compound_single_motion_search(cpi, x, bsize, &tmp_mv.as_mv, intrapred, + mask, bw, &tmp_rate_mv, 0); + if (mbmi->mv[0].as_int != tmp_mv.as_int) { + mbmi->mv[0].as_int = tmp_mv.as_int; + // Set ref_frame[1] to NONE_FRAME temporarily so that the intra + // predictor is not calculated again in av1_enc_build_inter_predictor(). + mbmi->ref_frame[1] = NONE_FRAME; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + mbmi->ref_frame[1] = INTRA_FRAME; + av1_combine_interintra(xd, bsize, 0, xd->plane[AOM_PLANE_Y].dst.buf, + xd->plane[AOM_PLANE_Y].dst.stride, intrapred, + bw); + model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND]( + cpi, bsize, x, xd, 0, 0, &rate_sum, &dist_sum, &skip_txfm_sb, + &skip_sse_sb, NULL, NULL, NULL); + rd = + RDCOST(x->rdmult, tmp_rate_mv + rate_overhead + rate_sum, dist_sum); + } + } + if (rd >= best_interintra_rd_wedge) { + tmp_mv.as_int = mv0.as_int; + tmp_rate_mv = *rate_mv; + av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); + } + // Evaluate closer to true rd + RD_STATS rd_stats; + const int64_t mode_rd = RDCOST(x->rdmult, rate_overhead + tmp_rate_mv, 0); + const int64_t tmp_rd_thresh = best_interintra_rd_nowedge - mode_rd; + rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &rd_stats); + if (rd != INT64_MAX) { + rd = RDCOST(x->rdmult, rate_overhead + tmp_rate_mv + rd_stats.rate, + rd_stats.dist); + } else { + if (best_interintra_rd_nowedge == INT64_MAX) return -1; + } + best_interintra_rd_wedge = rd; + if (best_interintra_rd_wedge < best_interintra_rd_nowedge) { + mbmi->mv[0].as_int = tmp_mv.as_int; + *tmp_rate2 += tmp_rate_mv - *rate_mv; + *rate_mv = tmp_rate_mv; + best_mode_rate = rate_overhead; + } else { + mbmi->use_wedge_interintra = 0; + mbmi->interintra_mode = best_interintra_mode; + mbmi->mv[0].as_int = mv0.as_int; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + } + } + + if (best_interintra_rd_nowedge == INT64_MAX && + best_interintra_rd_wedge == INT64_MAX) { + return -1; + } + + *tmp_rate2 += best_mode_rate; + + if (num_planes > 1) { + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_U, num_planes - 1); + } + return 0; +} + +static void alloc_compound_type_rd_buffers_no_check( + CompoundTypeRdBuffers *const bufs) { + bufs->pred0 = + (uint8_t *)aom_memalign(16, 2 * MAX_SB_SQUARE * sizeof(*bufs->pred0)); + bufs->pred1 = + (uint8_t *)aom_memalign(16, 2 * MAX_SB_SQUARE * sizeof(*bufs->pred1)); + bufs->residual1 = + (int16_t *)aom_memalign(32, MAX_SB_SQUARE * sizeof(*bufs->residual1)); + bufs->diff10 = + (int16_t *)aom_memalign(32, MAX_SB_SQUARE * sizeof(*bufs->diff10)); + bufs->tmp_best_mask_buf = (uint8_t *)aom_malloc( + 2 * MAX_SB_SQUARE * sizeof(*bufs->tmp_best_mask_buf)); +} + +// Computes the valid compound_types to be evaluated +static INLINE int compute_valid_comp_types( + MACROBLOCK *x, const AV1_COMP *const cpi, int *try_average_and_distwtd_comp, + BLOCK_SIZE bsize, int masked_compound_used, int mode_search_mask, + COMPOUND_TYPE *valid_comp_types) { + const AV1_COMMON *cm = &cpi->common; + int valid_type_count = 0; + int comp_type, valid_check; + int8_t enable_masked_type[MASKED_COMPOUND_TYPES] = { 0, 0 }; + + 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.inter_sf.use_dist_wtd_comp_flag != DIST_WTD_COMP_DISABLED); + *try_average_and_distwtd_comp = try_average_comp && try_distwtd_comp; + + // Check if COMPOUND_AVERAGE and COMPOUND_DISTWTD are valid cases + for (comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; + comp_type++) { + valid_check = + (comp_type == COMPOUND_AVERAGE) ? try_average_comp : try_distwtd_comp; + if (!*try_average_and_distwtd_comp && valid_check && + is_interinter_compound_used(comp_type, bsize)) + valid_comp_types[valid_type_count++] = comp_type; + } + // Check if COMPOUND_WEDGE and COMPOUND_DIFFWTD are valid cases + if (masked_compound_used) { + // enable_masked_type[0] corresponds to COMPOUND_WEDGE + // enable_masked_type[1] corresponds to COMPOUND_DIFFWTD + enable_masked_type[0] = enable_wedge_interinter_search(x, cpi); + enable_masked_type[1] = cpi->oxcf.enable_diff_wtd_comp; + for (comp_type = COMPOUND_WEDGE; comp_type <= COMPOUND_DIFFWTD; + comp_type++) { + if ((mode_search_mask & (1 << comp_type)) && + is_interinter_compound_used(comp_type, bsize) && + enable_masked_type[comp_type - COMPOUND_WEDGE]) + valid_comp_types[valid_type_count++] = comp_type; + } + } + return valid_type_count; +} + +// Calculates the cost for compound type mask +static INLINE void calc_masked_type_cost(MACROBLOCK *x, BLOCK_SIZE bsize, + int comp_group_idx_ctx, + int comp_index_ctx, + int masked_compound_used, + int *masked_type_cost) { + av1_zero_array(masked_type_cost, COMPOUND_TYPES); + // Account for group index cost when wedge and/or diffwtd prediction are + // enabled + if (masked_compound_used) { + // Compound group index of average and distwtd is 0 + // Compound group index of wedge and diffwtd is 1 + masked_type_cost[COMPOUND_AVERAGE] += + x->comp_group_idx_cost[comp_group_idx_ctx][0]; + masked_type_cost[COMPOUND_DISTWTD] += masked_type_cost[COMPOUND_AVERAGE]; + masked_type_cost[COMPOUND_WEDGE] += + x->comp_group_idx_cost[comp_group_idx_ctx][1]; + masked_type_cost[COMPOUND_DIFFWTD] += masked_type_cost[COMPOUND_WEDGE]; + } + + // Compute the cost to signal compound index/type + masked_type_cost[COMPOUND_AVERAGE] += x->comp_idx_cost[comp_index_ctx][1]; + masked_type_cost[COMPOUND_DISTWTD] += x->comp_idx_cost[comp_index_ctx][0]; + masked_type_cost[COMPOUND_WEDGE] += x->compound_type_cost[bsize][0]; + masked_type_cost[COMPOUND_DIFFWTD] += x->compound_type_cost[bsize][1]; +} + +// Updates mbmi structure with the relevant compound type info +static INLINE void update_mbmi_for_compound_type(MB_MODE_INFO *mbmi, + COMPOUND_TYPE cur_type) { + mbmi->interinter_comp.type = cur_type; + mbmi->comp_group_idx = (cur_type >= COMPOUND_WEDGE); + mbmi->compound_idx = (cur_type != COMPOUND_DISTWTD); +} + +// When match is found, populate the compound type data +// and calculate the rd cost using the stored stats and +// update the mbmi appropriately. +static INLINE int populate_reuse_comp_type_data( + const MACROBLOCK *x, MB_MODE_INFO *mbmi, + BEST_COMP_TYPE_STATS *best_type_stats, int_mv *cur_mv, int32_t *comp_rate, + int64_t *comp_dist, int *comp_rs2, int *rate_mv, int64_t *rd, + int match_index) { + const int winner_comp_type = + x->comp_rd_stats[match_index].interinter_comp.type; + if (comp_rate[winner_comp_type] == INT_MAX) + return best_type_stats->best_compmode_interinter_cost; + update_mbmi_for_compound_type(mbmi, winner_comp_type); + mbmi->interinter_comp = x->comp_rd_stats[match_index].interinter_comp; + *rd = RDCOST( + x->rdmult, + comp_rs2[winner_comp_type] + *rate_mv + comp_rate[winner_comp_type], + comp_dist[winner_comp_type]); + mbmi->mv[0].as_int = cur_mv[0].as_int; + mbmi->mv[1].as_int = cur_mv[1].as_int; + return comp_rs2[winner_comp_type]; +} + +// Updates rd cost and relevant compound type data for the best compound type +static INLINE void update_best_info(const MB_MODE_INFO *const mbmi, int64_t *rd, + BEST_COMP_TYPE_STATS *best_type_stats, + int64_t best_rd_cur, + int64_t comp_model_rd_cur, int rs2) { + *rd = best_rd_cur; + best_type_stats->comp_best_model_rd = comp_model_rd_cur; + best_type_stats->best_compound_data = mbmi->interinter_comp; + best_type_stats->best_compmode_interinter_cost = rs2; +} + +// Updates best_mv for masked compound types +static INLINE void update_mask_best_mv(const MB_MODE_INFO *const mbmi, + int_mv *best_mv, int_mv *cur_mv, + const COMPOUND_TYPE cur_type, + int *best_tmp_rate_mv, int tmp_rate_mv, + const SPEED_FEATURES *const sf) { + if (cur_type == COMPOUND_WEDGE || + (sf->inter_sf.enable_interinter_diffwtd_newmv_search && + cur_type == COMPOUND_DIFFWTD)) { + *best_tmp_rate_mv = tmp_rate_mv; + best_mv[0].as_int = mbmi->mv[0].as_int; + best_mv[1].as_int = mbmi->mv[1].as_int; + } else { + best_mv[0].as_int = cur_mv[0].as_int; + best_mv[1].as_int = cur_mv[1].as_int; + } +} + +// Choose the better of the two COMPOUND_AVERAGE, +// COMPOUND_DISTWTD based on modeled cost +static int find_best_avg_distwtd_comp_type(MACROBLOCK *x, int *comp_model_rate, + int64_t *comp_model_dist, + int rate_mv, int64_t *best_rd) { + int64_t est_rd[2]; + est_rd[COMPOUND_AVERAGE] = + RDCOST(x->rdmult, comp_model_rate[COMPOUND_AVERAGE] + rate_mv, + comp_model_dist[COMPOUND_AVERAGE]); + est_rd[COMPOUND_DISTWTD] = + RDCOST(x->rdmult, comp_model_rate[COMPOUND_DISTWTD] + rate_mv, + comp_model_dist[COMPOUND_DISTWTD]); + int best_type = (est_rd[COMPOUND_AVERAGE] <= est_rd[COMPOUND_DISTWTD]) + ? COMPOUND_AVERAGE + : COMPOUND_DISTWTD; + *best_rd = est_rd[best_type]; + return best_type; +} + +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 int32_t *comp_model_rate, + const int64_t *comp_model_dist, const int_mv *cur_mv, const int *comp_rs2) { + 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->model_rate, comp_model_rate, sizeof(rd_stats->model_rate)); + memcpy(rd_stats->model_dist, comp_model_dist, sizeof(rd_stats->model_dist)); + memcpy(rd_stats->comp_rs2, comp_rs2, sizeof(rd_stats->comp_rs2)); + 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; + rd_stats->filter = mbmi->interp_filters; + rd_stats->ref_mv_idx = mbmi->ref_mv_idx; + const MACROBLOCKD *const xd = &x->e_mbd; + for (int i = 0; i < 2; ++i) { + const WarpedMotionParams *const wm = + &xd->global_motion[mbmi->ref_frame[i]]; + rd_stats->is_global[i] = is_global_mv_block(mbmi, wm->wmtype); + } + memcpy(&rd_stats->interinter_comp, &mbmi->interinter_comp, + sizeof(rd_stats->interinter_comp)); + ++x->comp_rd_stats_idx; + } +} + +static INLINE int get_interinter_compound_mask_rate( + const MACROBLOCK *const x, const MB_MODE_INFO *const mbmi) { + const COMPOUND_TYPE compound_type = mbmi->interinter_comp.type; + // This function will be called only for COMPOUND_WEDGE and COMPOUND_DIFFWTD + if (compound_type == COMPOUND_WEDGE) { + return av1_is_wedge_used(mbmi->sb_type) + ? av1_cost_literal(1) + + x->wedge_idx_cost[mbmi->sb_type] + [mbmi->interinter_comp.wedge_index] + : 0; + } else { + assert(compound_type == COMPOUND_DIFFWTD); + return av1_cost_literal(1); + } +} + +// Takes a backup of rate, distortion and model_rd for future reuse +static INLINE void backup_stats(COMPOUND_TYPE cur_type, int32_t *comp_rate, + int64_t *comp_dist, int32_t *comp_model_rate, + int64_t *comp_model_dist, int rate_sum, + int64_t dist_sum, RD_STATS *rd_stats, + int *comp_rs2, int rs2) { + comp_rate[cur_type] = rd_stats->rate; + comp_dist[cur_type] = rd_stats->dist; + comp_model_rate[cur_type] = rate_sum; + comp_model_dist[cur_type] = dist_sum; + comp_rs2[cur_type] = rs2; +} + +static int64_t masked_compound_type_rd( + const AV1_COMP *const cpi, MACROBLOCK *x, const int_mv *const cur_mv, + const BLOCK_SIZE bsize, const PREDICTION_MODE this_mode, int *rs2, + 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 mode_rate, int64_t rd_thresh, int *calc_pred_masked_compound, + int32_t *comp_rate, int64_t *comp_dist, int32_t *comp_model_rate, + int64_t *comp_model_dist, const int64_t comp_best_model_rd, + int64_t *const comp_model_rd_cur, int *comp_rs2, int64_t ref_skip_rd) { + 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; + // This function will be called only for COMPOUND_WEDGE and COMPOUND_DIFFWTD + assert(compound_type == COMPOUND_WEDGE || compound_type == COMPOUND_DIFFWTD); + int rate_sum, tmp_skip_txfm_sb; + int64_t dist_sum, tmp_skip_sse_sb; + pick_interinter_mask_type pick_interinter_mask[2] = { pick_interinter_wedge, + pick_interinter_seg }; + + // TODO(any): Save pred and mask calculation as well into records. However + // this may increase memory requirements as compound segment mask needs to be + // stored in each record. + if (*calc_pred_masked_compound) { + get_inter_predictors_masked_compound(x, bsize, preds0, preds1, residual1, + diff10, strides); + *calc_pred_masked_compound = 0; + } + if (cpi->sf.inter_sf.prune_wedge_pred_diff_based && + compound_type == COMPOUND_WEDGE) { + unsigned int sse; + if (is_cur_buf_hbd(xd)) + (void)cpi->fn_ptr[bsize].vf(CONVERT_TO_BYTEPTR(*preds0), *strides, + CONVERT_TO_BYTEPTR(*preds1), *strides, &sse); + else + (void)cpi->fn_ptr[bsize].vf(*preds0, *strides, *preds1, *strides, &sse); + 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)) { + *comp_model_rd_cur = INT64_MAX; + return INT64_MAX; + } + } + // Function pointer to pick the appropriate mask + // compound_type == COMPOUND_WEDGE, calls pick_interinter_wedge() + // compound_type == COMPOUND_DIFFWTD, calls pick_interinter_seg() + uint64_t cur_sse = UINT64_MAX; + best_rd_cur = pick_interinter_mask[compound_type - COMPOUND_WEDGE]( + cpi, x, bsize, *preds0, *preds1, residual1, diff10, &cur_sse); + *rs2 += get_interinter_compound_mask_rate(x, mbmi); + best_rd_cur += RDCOST(x->rdmult, *rs2 + rate_mv, 0); + assert(cur_sse != UINT64_MAX); + int64_t skip_rd_cur = RDCOST(x->rdmult, *rs2 + rate_mv, (cur_sse << 4)); + + // Although the true rate_mv might be different after motion search, but it + // 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 > rd_thresh) { + *comp_model_rd_cur = INT64_MAX; + return INT64_MAX; + } + + // Check if the mode is good enough based on skip rd + // TODO(nithya): Handle wedge_newmv_search if extending for lower speed + // setting + if (cpi->sf.inter_sf.txfm_rd_gate_level) { + int eval_txfm = check_txfm_eval(x, bsize, ref_skip_rd, skip_rd_cur, + cpi->sf.inter_sf.txfm_rd_gate_level, 1); + if (!eval_txfm) { + *comp_model_rd_cur = INT64_MAX; + return INT64_MAX; + } + } + + // Compute cost if matching record not found, else, reuse data + if (comp_rate[compound_type] == INT_MAX) { + // Check whether new MV search for wedge is to be done + int wedge_newmv_search = + have_newmv_in_inter_mode(this_mode) && + (compound_type == COMPOUND_WEDGE) && + (!cpi->sf.inter_sf.disable_interinter_wedge_newmv_search); + int diffwtd_newmv_search = + cpi->sf.inter_sf.enable_interinter_diffwtd_newmv_search && + compound_type == COMPOUND_DIFFWTD && + have_newmv_in_inter_mode(this_mode); + + // Search for new MV if needed and build predictor + if (wedge_newmv_search) { + *out_rate_mv = av1_interinter_compound_motion_search(cpi, x, cur_mv, + bsize, this_mode); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, ctx, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + } else if (diffwtd_newmv_search) { + *out_rate_mv = av1_interinter_compound_motion_search(cpi, x, cur_mv, + bsize, this_mode); + // we need to update the mask according to the new motion vector + CompoundTypeRdBuffers tmp_buf; + int64_t tmp_rd = INT64_MAX; + alloc_compound_type_rd_buffers_no_check(&tmp_buf); + + uint8_t *tmp_preds0[1] = { tmp_buf.pred0 }; + uint8_t *tmp_preds1[1] = { tmp_buf.pred1 }; + + get_inter_predictors_masked_compound(x, bsize, tmp_preds0, tmp_preds1, + tmp_buf.residual1, tmp_buf.diff10, + strides); + + tmp_rd = pick_interinter_mask[compound_type - COMPOUND_WEDGE]( + cpi, x, bsize, *tmp_preds0, *tmp_preds1, tmp_buf.residual1, + tmp_buf.diff10, &cur_sse); + // we can reuse rs2 here + tmp_rd += RDCOST(x->rdmult, *rs2 + *out_rate_mv, 0); + + if (tmp_rd >= best_rd_cur) { + // restore the motion vector + 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); + } else { + // build the final prediciton using the updated mv + av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, tmp_preds0, + strides, tmp_preds1, strides); + } + av1_release_compound_type_rd_buffers(&tmp_buf); + } else { + *out_rate_mv = rate_mv; + av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, preds0, strides, + preds1, strides); + } + // Get the RD cost from model RD + model_rd_sb_fn[MODELRD_TYPE_MASKED_COMPOUND]( + cpi, bsize, x, xd, 0, 0, &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; + // Override with best if current is worse than best for new MV + if (wedge_newmv_search) { + 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; + } + } + if (cpi->sf.inter_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; + } + // Compute RD cost for the current type + RD_STATS rd_stats; + const int64_t tmp_mode_rd = RDCOST(x->rdmult, *rs2 + *out_rate_mv, 0); + const int64_t tmp_rd_thresh = rd_thresh - tmp_mode_rd; + rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &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 + backup_stats(compound_type, comp_rate, comp_dist, comp_model_rate, + comp_model_dist, rate_sum, dist_sum, &rd_stats, comp_rs2, + *rs2); + } + } else { + // Reuse data as matching record is found + assert(comp_dist[compound_type] != INT64_MAX); + // 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.inter_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]); + // Recalculate model rdcost with the updated rate + *comp_model_rd_cur = + RDCOST(x->rdmult, *rs2 + *out_rate_mv + comp_model_rate[compound_type], + comp_model_dist[compound_type]); + } + return rd; +} + +// scaling values to be used for gating wedge/compound segment based on best +// approximate rd +static int comp_type_rd_threshold_mul[3] = { 1, 11, 12 }; +static int comp_type_rd_threshold_div[3] = { 3, 16, 16 }; + +int av1_compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int_mv *cur_mv, int mode_search_mask, + int masked_compound_used, const BUFFER_SET *orig_dst, + const BUFFER_SET *tmp_dst, + const CompoundTypeRdBuffers *buffers, int *rate_mv, + int64_t *rd, RD_STATS *rd_stats, int64_t ref_best_rd, + int64_t ref_skip_rd, int *is_luma_interp_done, + int64_t rd_thresh) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + const PREDICTION_MODE this_mode = mbmi->mode; + const int bw = block_size_wide[bsize]; + int rs2; + int_mv best_mv[2]; + int best_tmp_rate_mv = *rate_mv; + BEST_COMP_TYPE_STATS best_type_stats; + // Initializing BEST_COMP_TYPE_STATS + best_type_stats.best_compound_data.type = COMPOUND_AVERAGE; + best_type_stats.best_compmode_interinter_cost = 0; + best_type_stats.comp_best_model_rd = INT64_MAX; + + uint8_t *preds0[1] = { buffers->pred0 }; + uint8_t *preds1[1] = { buffers->pred1 }; + int strides[1] = { bw }; + int tmp_rate_mv; + const int num_pix = 1 << num_pels_log2_lookup[bsize]; + const int mask_len = 2 * num_pix * sizeof(uint8_t); + COMPOUND_TYPE cur_type; + // Local array to store the mask cost for different compound types + int masked_type_cost[COMPOUND_TYPES]; + + int calc_pred_masked_compound = 1; + 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 }; + int comp_rs2[COMPOUND_TYPES] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; + int32_t comp_model_rate[COMPOUND_TYPES] = { INT_MAX, INT_MAX, INT_MAX, + INT_MAX }; + int64_t comp_model_dist[COMPOUND_TYPES] = { INT64_MAX, INT64_MAX, INT64_MAX, + INT64_MAX }; + int match_index = 0; + const int match_found = + find_comp_rd_in_stats(cpi, x, mbmi, comp_rate, comp_dist, comp_model_rate, + comp_model_dist, comp_rs2, &match_index); + 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; + + // Local array to store the valid compound types to be evaluated in the core + // loop + COMPOUND_TYPE valid_comp_types[COMPOUND_TYPES] = { + COMPOUND_AVERAGE, COMPOUND_DISTWTD, COMPOUND_WEDGE, COMPOUND_DIFFWTD + }; + int valid_type_count = 0; + int try_average_and_distwtd_comp = 0; + // compute_valid_comp_types() returns the number of valid compound types to be + // evaluated and populates the same in the local array valid_comp_types[]. + // It also sets the flag 'try_average_and_distwtd_comp' + valid_type_count = compute_valid_comp_types( + x, cpi, &try_average_and_distwtd_comp, bsize, masked_compound_used, + mode_search_mask, valid_comp_types); + + // The following context indices are independent of compound type + const int comp_group_idx_ctx = get_comp_group_idx_context(xd); + const int comp_index_ctx = get_comp_index_context(cm, xd); + + // Populates masked_type_cost local array for the 4 compound types + calc_masked_type_cost(x, bsize, comp_group_idx_ctx, comp_index_ctx, + masked_compound_used, masked_type_cost); + + int64_t comp_model_rd_cur = INT64_MAX; + int64_t best_rd_cur = INT64_MAX; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + // If the match is found, calculate the rd cost using the + // stored stats and update the mbmi appropriately. + if (match_found && cpi->sf.inter_sf.reuse_compound_type_decision) { + return populate_reuse_comp_type_data(x, mbmi, &best_type_stats, cur_mv, + comp_rate, comp_dist, comp_rs2, + rate_mv, rd, match_index); + } + // 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. + if (try_average_and_distwtd_comp) { + int est_rate[2]; + int64_t est_dist[2], est_rd; + COMPOUND_TYPE best_type; + // Since modelled rate and dist are separately stored, + // compute better of COMPOUND_AVERAGE and COMPOUND_DISTWTD + // using the stored stats. + if ((comp_model_rate[COMPOUND_AVERAGE] != INT_MAX) && + comp_model_rate[COMPOUND_DISTWTD] != INT_MAX) { + // Choose the better of the COMPOUND_AVERAGE, + // COMPOUND_DISTWTD on modeled cost. + best_type = find_best_avg_distwtd_comp_type( + x, comp_model_rate, comp_model_dist, *rate_mv, &est_rd); + update_mbmi_for_compound_type(mbmi, best_type); + if (comp_rate[best_type] != INT_MAX) + best_rd_cur = RDCOST( + x->rdmult, + masked_type_cost[best_type] + *rate_mv + comp_rate[best_type], + comp_dist[best_type]); + comp_model_rd_cur = est_rd; + // Update stats for best compound type + if (best_rd_cur < *rd) { + update_best_info(mbmi, rd, &best_type_stats, best_rd_cur, + comp_model_rd_cur, masked_type_cost[best_type]); + } + restore_dst_buf(xd, *tmp_dst, 1); + } else { + int64_t sse_y[COMPOUND_DISTWTD + 1]; + // Calculate model_rd for COMPOUND_AVERAGE and COMPOUND_DISTWTD + for (int comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; + comp_type++) { + update_mbmi_for_compound_type(mbmi, comp_type); + 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, &est_rate[comp_type], &est_dist[comp_type], + NULL, NULL, NULL, NULL, NULL); + est_rate[comp_type] += masked_type_cost[comp_type]; + comp_model_rate[comp_type] = est_rate[comp_type]; + comp_model_dist[comp_type] = est_dist[comp_type]; + sse_y[comp_type] = x->pred_sse[xd->mi[0]->ref_frame[0]]; + if (comp_type == COMPOUND_AVERAGE) { + *is_luma_interp_done = 1; + restore_dst_buf(xd, *tmp_dst, 1); + } + } + // Choose the better of the two based on modeled cost and call + // estimate_yrd_for_sb() for that one. + best_type = find_best_avg_distwtd_comp_type( + x, comp_model_rate, comp_model_dist, *rate_mv, &est_rd); + update_mbmi_for_compound_type(mbmi, best_type); + if (best_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *orig_dst, 1); + rs2 = masked_type_cost[best_type]; + RD_STATS est_rd_stats; + const int64_t mode_rd = RDCOST(x->rdmult, rs2 + *rate_mv, 0); + const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh) - mode_rd; + int64_t est_rd_ = INT64_MAX; + int eval_txfm = 1; + // Check if the mode is good enough based on skip rd + if (cpi->sf.inter_sf.txfm_rd_gate_level) { + int64_t skip_rd = + RDCOST(x->rdmult, rs2 + *rate_mv, (sse_y[best_type] << 4)); + eval_txfm = check_txfm_eval(x, bsize, ref_skip_rd, skip_rd, + cpi->sf.inter_sf.txfm_rd_gate_level, 1); + } + // Evaluate further if skip rd is low enough + if (eval_txfm) { + est_rd_ = + estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &est_rd_stats); + } + + 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 + backup_stats(best_type, comp_rate, comp_dist, comp_model_rate, + comp_model_dist, est_rate[best_type], est_dist[best_type], + &est_rd_stats, comp_rs2, rs2); + comp_model_rd_cur = est_rd; + } + if (best_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); + // Update stats for best compound type + if (best_rd_cur < *rd) { + update_best_info(mbmi, rd, &best_type_stats, best_rd_cur, + comp_model_rd_cur, rs2); + } + } + } + + // If COMPOUND_AVERAGE is not valid, use the spare buffer + if (valid_comp_types[0] != COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); + + // Loop over valid compound types + for (int i = 0; i < valid_type_count; i++) { + cur_type = valid_comp_types[i]; + comp_model_rd_cur = INT64_MAX; + tmp_rate_mv = *rate_mv; + best_rd_cur = INT64_MAX; + + // Case COMPOUND_AVERAGE and COMPOUND_DISTWTD + if (cur_type < COMPOUND_WEDGE) { + update_mbmi_for_compound_type(mbmi, cur_type); + rs2 = masked_type_cost[cur_type]; + 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; + + // Compute RD cost for the current type + RD_STATS est_rd_stats; + const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh) - mode_rd; + int64_t est_rd = INT64_MAX; + int eval_txfm = 1; + // Check if the mode is good enough based on skip rd + if (cpi->sf.inter_sf.txfm_rd_gate_level) { + int64_t sse_y = compute_sse_plane(x, xd, PLANE_TYPE_Y, bsize); + int64_t skip_rd = RDCOST(x->rdmult, rs2 + *rate_mv, (sse_y << 4)); + eval_txfm = check_txfm_eval(x, bsize, ref_skip_rd, skip_rd, + cpi->sf.inter_sf.txfm_rd_gate_level, 1); + } + // Evaluate further if skip rd is low enough + if (eval_txfm) { + est_rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, + &est_rd_stats); + } + + 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, &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); + + // Backup rate and distortion for future reuse + backup_stats(cur_type, comp_rate, comp_dist, comp_model_rate, + comp_model_dist, rate_sum, dist_sum, &est_rd_stats, + comp_rs2, rs2); + } + } 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]); + // Recalculate model rdcost with the updated rate + comp_model_rd_cur = + RDCOST(x->rdmult, rs2 + *rate_mv + comp_model_rate[cur_type], + comp_model_dist[cur_type]); + } + } + // use spare buffer for following compound type try + if (cur_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); + } else { + // Handle masked compound types + update_mbmi_for_compound_type(mbmi, cur_type); + rs2 = masked_type_cost[cur_type]; + // Factors to control gating of compound type selection based on best + // approximate rd so far + const int max_comp_type_rd_threshold_mul = + comp_type_rd_threshold_mul[cpi->sf.inter_sf + .prune_comp_type_by_comp_avg]; + const int max_comp_type_rd_threshold_div = + comp_type_rd_threshold_div[cpi->sf.inter_sf + .prune_comp_type_by_comp_avg]; + // Evaluate COMPOUND_WEDGE / COMPOUND_DIFFWTD if approximated cost is + // within threshold + int64_t approx_rd = ((*rd / max_comp_type_rd_threshold_div) * + max_comp_type_rd_threshold_mul); + + if (approx_rd < ref_best_rd) { + const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh); + best_rd_cur = masked_compound_type_rd( + cpi, x, cur_mv, bsize, this_mode, &rs2, *rate_mv, orig_dst, + &tmp_rate_mv, preds0, preds1, buffers->residual1, buffers->diff10, + strides, rd_stats->rate, tmp_rd_thresh, &calc_pred_masked_compound, + comp_rate, comp_dist, comp_model_rate, comp_model_dist, + best_type_stats.comp_best_model_rd, &comp_model_rd_cur, comp_rs2, + ref_skip_rd); + } + } + // Update stats for best compound type + if (best_rd_cur < *rd) { + update_best_info(mbmi, rd, &best_type_stats, best_rd_cur, + comp_model_rd_cur, rs2); + if (masked_compound_used && cur_type >= COMPOUND_WEDGE) { + memcpy(buffers->tmp_best_mask_buf, xd->seg_mask, mask_len); + if (have_newmv_in_inter_mode(this_mode)) + update_mask_best_mv(mbmi, best_mv, cur_mv, cur_type, + &best_tmp_rate_mv, tmp_rate_mv, &cpi->sf); + } + } + // reset to original mvs for next iteration + mbmi->mv[0].as_int = cur_mv[0].as_int; + mbmi->mv[1].as_int = cur_mv[1].as_int; + } + if (mbmi->interinter_comp.type != best_type_stats.best_compound_data.type) { + mbmi->comp_group_idx = + (best_type_stats.best_compound_data.type < COMPOUND_WEDGE) ? 0 : 1; + mbmi->compound_idx = + !(best_type_stats.best_compound_data.type == COMPOUND_DISTWTD); + mbmi->interinter_comp = best_type_stats.best_compound_data; + memcpy(xd->seg_mask, buffers->tmp_best_mask_buf, mask_len); + } + if (have_newmv_in_inter_mode(this_mode)) { + mbmi->mv[0].as_int = best_mv[0].as_int; + mbmi->mv[1].as_int = best_mv[1].as_int; + if (mbmi->interinter_comp.type == COMPOUND_WEDGE) { + rd_stats->rate += best_tmp_rate_mv - *rate_mv; + *rate_mv = best_tmp_rate_mv; + } + } + restore_dst_buf(xd, *orig_dst, 1); + if (!match_found) + save_comp_rd_search_stat(x, mbmi, comp_rate, comp_dist, comp_model_rate, + comp_model_dist, cur_mv, comp_rs2); + return best_type_stats.best_compmode_interinter_cost; +} diff --git a/media/libaom/src/av1/encoder/compound_type.h b/media/libaom/src/av1/encoder/compound_type.h new file mode 100644 index 0000000000..f2bd857c9a --- /dev/null +++ b/media/libaom/src/av1/encoder/compound_type.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, 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_COMPOUND_TYPE_H_ +#define AOM_AV1_ENCODER_COMPOUND_TYPE_H_ + +#include "av1/encoder/encoder.h" +#include "av1/encoder/interp_search.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Structure to store the compound type related stats for best compound type +typedef struct { + INTERINTER_COMPOUND_DATA best_compound_data; + int64_t comp_best_model_rd; + int best_compmode_interinter_cost; +} BEST_COMP_TYPE_STATS; + +int av1_handle_inter_intra_mode(const AV1_COMP *const cpi, MACROBLOCK *const x, + BLOCK_SIZE bsize, MB_MODE_INFO *mbmi, + HandleInterModeArgs *args, int64_t ref_best_rd, + int *rate_mv, int *tmp_rate2, + const BUFFER_SET *orig_dst); + +int av1_compound_type_rd(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int_mv *cur_mv, int mode_search_mask, + int masked_compound_used, const BUFFER_SET *orig_dst, + const BUFFER_SET *tmp_dst, + const CompoundTypeRdBuffers *buffers, int *rate_mv, + int64_t *rd, RD_STATS *rd_stats, int64_t ref_best_rd, + int64_t ref_skip_rd, int *is_luma_interp_done, + int64_t rd_thresh); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_COMPOUND_TYPE_H_ diff --git a/media/libaom/src/av1/encoder/context_tree.c b/media/libaom/src/av1/encoder/context_tree.c index 00f7509d66..9b5b1cbf9d 100644 --- a/media/libaom/src/av1/encoder/context_tree.c +++ b/media/libaom/src/av1/encoder/context_tree.c @@ -131,16 +131,26 @@ static AOM_INLINE void free_tree_contexts(PC_TREE *tree, const int num_planes) { free_mode_context(&tree->vertical[1], num_planes); } +// This function will compute the number of pc_tree nodes to be allocated +// or freed as per the super block size of BLOCK_128X128 or BLOCK_64X64 +static AOM_INLINE int get_pc_tree_nodes(const int is_sb_size_128, + int stat_generation_stage) { + const int tree_nodes_inc = is_sb_size_128 ? 1024 : 0; + const int tree_nodes = + stat_generation_stage ? 1 : (tree_nodes_inc + 256 + 64 + 16 + 4 + 1); + return tree_nodes; +} + // This function sets up a tree of contexts such that at each square // partition level. There are contexts for none, horizontal, vertical, and // split. Along with a block_size value and a selected block_size which // represents the state of our search. -void av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) { - int i, j; - const int tree_nodes_inc = 1024; - const int leaf_factor = 4; - const int leaf_nodes = 256 * leaf_factor; - const int tree_nodes = tree_nodes_inc + 256 + 64 + 16 + 4 + 1; +void av1_setup_pc_tree(AV1_COMP *const cpi, ThreadData *td) { + AV1_COMMON *const cm = &cpi->common; + int i, j, stat_generation_stage = is_stat_generation_stage(cpi); + const int is_sb_size_128 = cm->seq_params.sb_size == BLOCK_128X128; + const int tree_nodes = + get_pc_tree_nodes(is_sb_size_128, stat_generation_stage); int pc_tree_index = 0; PC_TREE *this_pc; PC_TREE_SHARED_BUFFERS shared_bufs; @@ -165,45 +175,54 @@ void av1_setup_pc_tree(AV1_COMMON *cm, ThreadData *td) { shared_bufs.dqcoeff_buf[i] = td->tree_dqcoeff_buf[i]; } - // Sets up all the leaf nodes in the tree. - for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) { - PC_TREE *const tree = &td->pc_tree[pc_tree_index]; - tree->block_size = square[0]; - alloc_tree_contexts(cm, tree, 16, 1, &shared_bufs); - } + if (!stat_generation_stage) { + const int leaf_factor = is_sb_size_128 ? 4 : 1; + const int leaf_nodes = 256 * leaf_factor; - // Each node has 4 leaf nodes, fill each block_size level of the tree - // from leafs to the root. - for (nodes = leaf_nodes >> 2; nodes > 0; nodes >>= 2) { - for (i = 0; i < nodes; ++i) { + // Sets up all the leaf nodes in the tree. + for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) { PC_TREE *const tree = &td->pc_tree[pc_tree_index]; - alloc_tree_contexts(cm, tree, 16 << (2 * square_index), 0, &shared_bufs); - tree->block_size = square[square_index]; - for (j = 0; j < 4; j++) tree->split[j] = this_pc++; - ++pc_tree_index; + tree->block_size = square[0]; + alloc_tree_contexts(cm, tree, 16, 1, &shared_bufs); } - ++square_index; + + // Each node has 4 leaf nodes, fill each block_size level of the tree + // from leafs to the root. + for (nodes = leaf_nodes >> 2; nodes > 0; nodes >>= 2) { + for (i = 0; i < nodes; ++i) { + PC_TREE *const tree = &td->pc_tree[pc_tree_index]; + alloc_tree_contexts(cm, tree, 16 << (2 * square_index), 0, + &shared_bufs); + tree->block_size = square[square_index]; + for (j = 0; j < 4; j++) tree->split[j] = this_pc++; + ++pc_tree_index; + } + ++square_index; + } + } else { + // Allocation for firstpass/LAP stage + // TODO(Mufaddal): refactor square_index to use a common block_size macro + // from firstpass.c + PC_TREE *const tree = &td->pc_tree[pc_tree_index]; + square_index = 2; + alloc_tree_contexts(cm, tree, 16 << (2 * square_index), 1, &shared_bufs); + tree->block_size = square[square_index]; } - // Set up the root node for the largest superblock size - i = MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2; - td->pc_root[i] = &td->pc_tree[tree_nodes - 1]; + // Set up the root node for the applicable superblock size + td->pc_root = &td->pc_tree[tree_nodes - 1]; #if CONFIG_INTERNAL_STATS - td->pc_root[i]->none.best_mode_index = THR_INVALID; + td->pc_root->none.best_mode_index = THR_INVALID; #endif // CONFIG_INTERNAL_STATS - // Set up the root nodes for the rest of the possible superblock sizes - while (--i >= 0) { - td->pc_root[i] = td->pc_root[i + 1]->split[0]; -#if CONFIG_INTERNAL_STATS - td->pc_root[i]->none.best_mode_index = THR_INVALID; -#endif // CONFIG_INTERNAL_STATS - } } -void av1_free_pc_tree(ThreadData *td, const int num_planes) { +void av1_free_pc_tree(const AV1_COMP *const cpi, ThreadData *td, + const int num_planes, BLOCK_SIZE sb_size) { + int stat_generation_stage = is_stat_generation_stage(cpi); if (td->pc_tree != NULL) { - const int tree_nodes_inc = 1024; - const int tree_nodes = tree_nodes_inc + 256 + 64 + 16 + 4 + 1; + const int is_sb_size_128 = sb_size == BLOCK_128X128; + const int tree_nodes = + get_pc_tree_nodes(is_sb_size_128, stat_generation_stage); for (int i = 0; i < tree_nodes; ++i) { free_tree_contexts(&td->pc_tree[i], num_planes); } @@ -223,7 +242,7 @@ void av1_free_pc_tree(ThreadData *td, const int num_planes) { void av1_copy_tree_context(PICK_MODE_CONTEXT *dst_ctx, PICK_MODE_CONTEXT *src_ctx) { dst_ctx->mic = src_ctx->mic; - dst_ctx->mbmi_ext = src_ctx->mbmi_ext; + dst_ctx->mbmi_ext_best = src_ctx->mbmi_ext_best; dst_ctx->num_4x4_blk = src_ctx->num_4x4_blk; dst_ctx->skippable = src_ctx->skippable; diff --git a/media/libaom/src/av1/encoder/context_tree.h b/media/libaom/src/av1/encoder/context_tree.h index ca311cc207..a39979413e 100644 --- a/media/libaom/src/av1/encoder/context_tree.h +++ b/media/libaom/src/av1/encoder/context_tree.h @@ -28,7 +28,7 @@ struct ThreadData; // Structure to hold snapshot of coding context during the mode picking process typedef struct { MB_MODE_INFO mic; - MB_MODE_INFO_EXT mbmi_ext; + MB_MODE_INFO_EXT_FRAME mbmi_ext_best; uint8_t *color_index_map[2]; uint8_t *blk_skip; @@ -77,15 +77,16 @@ typedef struct PC_TREE { int index; // Simple motion search_features - MV mv_ref_fulls[REF_FRAMES]; + FULLPEL_MV start_mvs[REF_FRAMES]; unsigned int sms_none_feat[2]; unsigned int sms_rect_feat[8]; int sms_none_valid; int sms_rect_valid; } PC_TREE; -void av1_setup_pc_tree(struct AV1Common *cm, struct ThreadData *td); -void av1_free_pc_tree(struct ThreadData *td, const int num_planes); +void av1_setup_pc_tree(struct AV1_COMP *const cpi, struct ThreadData *td); +void av1_free_pc_tree(const struct AV1_COMP *const cpi, struct ThreadData *td, + const int num_planes, BLOCK_SIZE sb_size); void av1_copy_tree_context(PICK_MODE_CONTEXT *dst_ctx, PICK_MODE_CONTEXT *src_ctx); diff --git a/media/libaom/src/av1/encoder/enc_enums.h b/media/libaom/src/av1/encoder/enc_enums.h index 7ea388abcc..5a06514838 100644 --- a/media/libaom/src/av1/encoder/enc_enums.h +++ b/media/libaom/src/av1/encoder/enc_enums.h @@ -214,6 +214,8 @@ enum { SINGLE_REF_MODE_START = THR_NEARESTMV, SINGLE_REF_MODE_END = THR_COMP_NEAREST_NEARESTLA, NUM_SINGLE_REF_MODES = SINGLE_REF_MODE_END - SINGLE_REF_MODE_START, + THR_MODE_START = THR_NEARESTMV, + THR_MODE_END = MAX_MODES, THR_INVALID = 255 } UENUM1BYTE(THR_MODES); diff --git a/media/libaom/src/av1/encoder/encode_strategy.c b/media/libaom/src/av1/encoder/encode_strategy.c index e3c869a620..8eb73d8d3a 100644 --- a/media/libaom/src/av1/encoder/encode_strategy.c +++ b/media/libaom/src/av1/encoder/encode_strategy.c @@ -23,7 +23,7 @@ #include "aom_util/debug_util.h" #endif // CONFIG_MISMATCH_DEBUG -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/reconinter.h" #include "av1/encoder/encoder.h" @@ -43,32 +43,29 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, // 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? + const ExternalFlags *const ext_flags = &cpi->ext_flags; cpi->rc.is_src_frame_alt_ref = 0; switch (type) { case KF_UPDATE: - frame_params->refresh_last_frame = 1; frame_params->refresh_golden_frame = 1; frame_params->refresh_bwd_ref_frame = 1; frame_params->refresh_alt_ref_frame = 1; break; case LF_UPDATE: - frame_params->refresh_last_frame = 1; frame_params->refresh_golden_frame = 0; frame_params->refresh_bwd_ref_frame = 0; frame_params->refresh_alt_ref_frame = 0; break; case GF_UPDATE: - frame_params->refresh_last_frame = 0; frame_params->refresh_golden_frame = 1; frame_params->refresh_bwd_ref_frame = 0; frame_params->refresh_alt_ref_frame = 0; break; case OVERLAY_UPDATE: - frame_params->refresh_last_frame = 0; frame_params->refresh_golden_frame = 1; frame_params->refresh_bwd_ref_frame = 0; frame_params->refresh_alt_ref_frame = 0; @@ -77,7 +74,6 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, break; case ARF_UPDATE: - frame_params->refresh_last_frame = 0; frame_params->refresh_golden_frame = 0; // NOTE: BWDREF does not get updated along with ALTREF_FRAME. frame_params->refresh_bwd_ref_frame = 0; @@ -85,7 +81,6 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, break; case INTNL_OVERLAY_UPDATE: - frame_params->refresh_last_frame = 1; frame_params->refresh_golden_frame = 0; frame_params->refresh_bwd_ref_frame = 0; frame_params->refresh_alt_ref_frame = 0; @@ -94,7 +89,6 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, break; case INTNL_ARF_UPDATE: - frame_params->refresh_last_frame = 0; frame_params->refresh_golden_frame = 0; frame_params->refresh_bwd_ref_frame = 1; frame_params->refresh_alt_ref_frame = 0; @@ -103,16 +97,14 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, 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; + if (ext_flags->refresh_frame_flags_pending && + (!is_stat_generation_stage(cpi))) { + frame_params->refresh_golden_frame = ext_flags->refresh_golden_frame; + frame_params->refresh_alt_ref_frame = ext_flags->refresh_alt_ref_frame; + frame_params->refresh_bwd_ref_frame = ext_flags->refresh_bwd_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_alt_ref_frame = 1; @@ -121,9 +113,15 @@ void av1_configure_buffer_updates(AV1_COMP *const cpi, static void set_additional_frame_flags(const AV1_COMMON *const cm, unsigned int *const frame_flags) { - if (frame_is_intra_only(cm)) *frame_flags |= FRAMEFLAGS_INTRAONLY; - if (frame_is_sframe(cm)) *frame_flags |= FRAMEFLAGS_SWITCH; - if (cm->error_resilient_mode) *frame_flags |= FRAMEFLAGS_ERROR_RESILIENT; + if (frame_is_intra_only(cm)) { + *frame_flags |= FRAMEFLAGS_INTRAONLY; + } + if (frame_is_sframe(cm)) { + *frame_flags |= FRAMEFLAGS_SWITCH; + } + if (cm->features.error_resilient_mode) { + *frame_flags |= FRAMEFLAGS_ERROR_RESILIENT; + } } static INLINE void update_keyframe_counters(AV1_COMP *cpi) { @@ -139,16 +137,17 @@ static INLINE void update_keyframe_counters(AV1_COMP *cpi) { } } -static INLINE int is_frame_droppable(const AV1_COMP *const cpi) { +static INLINE int is_frame_droppable(const SVC *const svc, + const ExternalFlags *const ext_flags) { // Droppable frame is only used by external refresh flags. VoD setting won't // trigger its use case. - if (cpi->svc.external_ref_frame_config) - return cpi->svc.non_reference_frame; - else if (cpi->ext_refresh_frame_flags_pending) - return !(cpi->ext_refresh_alt_ref_frame || - cpi->ext_refresh_alt2_ref_frame || - cpi->ext_refresh_bwd_ref_frame || cpi->ext_refresh_golden_frame || - cpi->ext_refresh_last_frame); + if (svc->external_ref_frame_config) + return svc->non_reference_frame; + else if (ext_flags->refresh_frame_flags_pending) + return !(ext_flags->refresh_alt_ref_frame || + ext_flags->refresh_alt2_ref_frame || + ext_flags->refresh_bwd_ref_frame || + ext_flags->refresh_golden_frame || ext_flags->refresh_last_frame); else return 0; } @@ -158,7 +157,8 @@ static INLINE void update_frames_till_gf_update(AV1_COMP *cpi) { // is a work-around to handle the condition when a frame is drop. // We should fix the cpi->common.show_frame flag // instead of checking the other condition to update the counter properly. - if (cpi->common.show_frame || is_frame_droppable(cpi)) { + if (cpi->common.show_frame || + is_frame_droppable(&cpi->svc, &cpi->ext_flags)) { // Decrement count down till next gf if (cpi->rc.frames_till_gf_update_due > 0) cpi->rc.frames_till_gf_update_due--; @@ -182,26 +182,25 @@ static void update_rc_counts(AV1_COMP *cpi) { update_gf_group_index(cpi); } -static void set_ext_overrides(AV1_COMP *const cpi, - EncodeFrameParams *const frame_params) { +static void set_ext_overrides(AV1_COMMON *const cm, + EncodeFrameParams *const frame_params, + ExternalFlags *const ext_flags) { // Overrides the defaults with the externally supplied values with // av1_update_reference() and av1_update_entropy() calls // Note: The overrides are valid only for the next frame passed // to av1_encode_lowlevel() - AV1_COMMON *const cm = &cpi->common; - - if (cpi->ext_use_s_frame) { + if (ext_flags->use_s_frame) { frame_params->frame_type = S_FRAME; } - if (cpi->ext_refresh_frame_context_pending) { - cm->refresh_frame_context = cpi->ext_refresh_frame_context; - cpi->ext_refresh_frame_context_pending = 0; + if (ext_flags->refresh_frame_context_pending) { + cm->features.refresh_frame_context = ext_flags->refresh_frame_context; + ext_flags->refresh_frame_context_pending = 0; } - cm->allow_ref_frame_mvs = cpi->ext_use_ref_frame_mvs; + cm->features.allow_ref_frame_mvs = ext_flags->use_ref_frame_mvs; - frame_params->error_resilient_mode = cpi->ext_use_error_resilient; + frame_params->error_resilient_mode = ext_flags->use_error_resilient; // A keyframe is already error resilient and keyframes with // error_resilient_mode interferes with the use of show_existing_frame // when forward reference keyframes are enabled. @@ -210,43 +209,6 @@ static void set_ext_overrides(AV1_COMP *const cpi, frame_params->error_resilient_mode |= frame_params->frame_type == S_FRAME; } -static int get_ref_frame_flags(const AV1_COMP *const cpi) { - static const MV_REFERENCE_FRAME - ref_frame_priority_order[INTER_REFS_PER_FRAME] = { - LAST_FRAME, ALTREF_FRAME, BWDREF_FRAME, GOLDEN_FRAME, - ALTREF2_FRAME, LAST2_FRAME, LAST3_FRAME, - }; - const AV1_COMMON *const cm = &cpi->common; - const RefCntBuffer *ref_frames[INTER_REFS_PER_FRAME]; - for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { - ref_frames[i] = get_ref_frame_buf(cm, ref_frame_priority_order[i]); - } - - // cpi->ext_ref_frame_flags allows certain reference types to be disabled - // by the external interface. These are set by av1_apply_encoding_flags(). - // Start with what the external interface allows, then suppress any reference - // types which we have found to be duplicates. - int flags = cpi->ext_ref_frame_flags; - - for (int i = 1; i < INTER_REFS_PER_FRAME; ++i) { - const RefCntBuffer *const this_ref = ref_frames[i]; - // If this_ref has appeared before, mark the corresponding ref frame as - // invalid. For fast_nonrd mode, only disable GOLDEN_FRAME if it's the same - // as LAST_FRAME. - int index = (cpi->sf.use_fast_nonrd_pick_mode && - ref_frame_priority_order[i] == GOLDEN_FRAME) - ? 1 - : i; - for (int j = 0; j < index; ++j) { - if (this_ref == ref_frames[j]) { - flags &= ~(1 << (ref_frame_priority_order[i] - 1)); - break; - } - } - } - return flags; -} - static int get_current_frame_ref_type( const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) { // We choose the reference "type" of this frame from the flags which indicate @@ -275,14 +237,19 @@ static int choose_primary_ref_frame( const int intra_only = frame_params->frame_type == KEY_FRAME || frame_params->frame_type == INTRA_ONLY_FRAME; if (intra_only || frame_params->error_resilient_mode || cpi->use_svc || - cpi->ext_use_primary_ref_none) { + cpi->ext_flags.use_primary_ref_none) { return PRIMARY_REF_NONE; } + // In large scale case, always use Last frame's frame contexts. + // Note(yunqing): In other cases, primary_ref_frame is chosen based on + // cpi->gf_group.layer_depth[cpi->gf_group.index], which also controls + // frame bit allocation. + if (cm->tiles.large_scale) return (LAST_FRAME - LAST_FRAME); + // Find the most recent reference frame with the same reference type as the // current frame - FRAME_CONTEXT_INDEX current_ref_type = - get_current_frame_ref_type(cpi, frame_params); + const int current_ref_type = get_current_frame_ref_type(cpi, frame_params); int wanted_fb = cpi->fb_of_context_type[current_ref_type]; int primary_ref_frame = PRIMARY_REF_NONE; @@ -302,8 +269,8 @@ static void update_fb_of_context_type( const int current_frame_ref_type = get_current_frame_ref_type(cpi, frame_params); - if (frame_is_intra_only(cm) || cm->error_resilient_mode || - cpi->ext_use_primary_ref_none) { + if (frame_is_intra_only(cm) || cm->features.error_resilient_mode || + cpi->ext_flags.use_primary_ref_none) { for (int i = 0; i < REF_FRAMES; i++) { fb_of_context_type[i] = -1; } @@ -343,8 +310,8 @@ static int get_order_offset(const GF_GROUP *const gf_group, return AOMMIN((MAX_GF_INTERVAL - 1), arf_offset); } -static void adjust_frame_rate(AV1_COMP *cpi, - const struct lookahead_entry *source) { +static void adjust_frame_rate(AV1_COMP *cpi, int64_t ts_start, int64_t ts_end) { + TimeStamps *time_stamps = &cpi->time_stamps; int64_t this_duration; int step = 0; @@ -357,14 +324,14 @@ static void adjust_frame_rate(AV1_COMP *cpi, return; } - if (source->ts_start == cpi->first_time_stamp_ever) { - this_duration = source->ts_end - source->ts_start; + if (ts_start == time_stamps->first_ever) { + this_duration = ts_end - ts_start; step = 1; } else { int64_t last_duration = - cpi->last_end_time_stamp_seen - cpi->last_time_stamp_seen; + time_stamps->prev_end_seen - time_stamps->prev_start_seen; - this_duration = source->ts_end - cpi->last_end_time_stamp_seen; + this_duration = ts_end - time_stamps->prev_end_seen; // do a step update if the duration changes by 10% if (last_duration) @@ -378,8 +345,8 @@ static void adjust_frame_rate(AV1_COMP *cpi, // Average this frame's rate into the last second's average // frame rate. If we haven't seen 1 second yet, then average // over the whole interval seen. - const double interval = AOMMIN( - (double)(source->ts_end - cpi->first_time_stamp_ever), 10000000.0); + const double interval = + AOMMIN((double)(ts_end - time_stamps->first_ever), 10000000.0); double avg_duration = 10000000.0 / cpi->framerate; avg_duration *= (interval - avg_duration + this_duration); avg_duration /= interval; @@ -387,8 +354,8 @@ static void adjust_frame_rate(AV1_COMP *cpi, av1_new_framerate(cpi, 10000000.0 / avg_duration); } } - cpi->last_time_stamp_seen = source->ts_start; - cpi->last_end_time_stamp_seen = source->ts_end; + time_stamps->prev_start_seen = ts_start; + time_stamps->prev_end_seen = ts_end; } // If this is an alt-ref, returns the offset of the source frame used @@ -416,11 +383,10 @@ static struct lookahead_entry *setup_arf_frame( *code_arf = 0; struct lookahead_entry *source = - av1_lookahead_peek(cpi->lookahead, arf_src_index); + av1_lookahead_peek(cpi->lookahead, arf_src_index, cpi->compressor_stage); if (source != NULL) { cm->showable_frame = 1; - cpi->alt_ref_source = source; // When arf_src_index == rc->frames_to_key, it indicates a fwd_kf if (arf_src_index == rc->frames_to_key) { @@ -451,21 +417,23 @@ static struct lookahead_entry *setup_arf_frame( } // Determine whether there is a forced keyframe pending in the lookahead buffer -static int is_forced_keyframe_pending(struct lookahead_ctx *lookahead, - const int up_to_index) { +int is_forced_keyframe_pending(struct lookahead_ctx *lookahead, + const int up_to_index, + const COMPRESSOR_STAGE compressor_stage) { for (int i = 0; i <= up_to_index; i++) { - const struct lookahead_entry *e = av1_lookahead_peek(lookahead, i); + const struct lookahead_entry *e = + av1_lookahead_peek(lookahead, i, compressor_stage); if (e == NULL) { // We have reached the end of the lookahead buffer and not early-returned // so there isn't a forced key-frame pending. - return 0; + return -1; } else if (e->flags == AOM_EFLAG_FORCE_KF) { - return 1; + return (i + 1); } else { continue; } } - return 0; // Never reached + return -1; // Never reached } // Check if we should encode an ARF or internal ARF. If not, try a LAST @@ -482,8 +450,11 @@ static struct lookahead_entry *choose_frame_source( // Should we encode an alt-ref frame. int arf_src_index = get_arf_src_index(&cpi->gf_group, cpi->oxcf.pass); + // TODO(Aasaipriya): Forced key frames need to be fixed when rc_mode != AOM_Q if (arf_src_index && - is_forced_keyframe_pending(cpi->lookahead, arf_src_index)) { + (is_forced_keyframe_pending(cpi->lookahead, arf_src_index, + cpi->compressor_stage) != -1) && + cpi->oxcf.rc_mode != AOM_Q) { arf_src_index = 0; *flush = 1; } @@ -495,15 +466,13 @@ static struct lookahead_entry *choose_frame_source( if (!source) { // Get last frame source. if (cm->current_frame.frame_number > 0) { - *last_source = av1_lookahead_peek(cpi->lookahead, -1); + *last_source = + av1_lookahead_peek(cpi->lookahead, -1, cpi->compressor_stage); } // Read in the source frame. - source = av1_lookahead_pop(cpi->lookahead, *flush); + source = av1_lookahead_pop(cpi->lookahead, *flush, cpi->compressor_stage); if (source == NULL) return NULL; frame_params->show_frame = 1; - - // Check to see if the frame should be encoded as an arf overlay. - if (cpi->alt_ref_source == source) cpi->alt_ref_source = NULL; } return source; } @@ -516,7 +485,7 @@ 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); + av1_lookahead_peek(cpi->lookahead, 0, cpi->compressor_stage); if (lookahead_src == NULL) return 1; const int is_error_resilient = @@ -663,7 +632,7 @@ static void update_arf_stack(int ref_map_index, // Update reference frame stack info. void av1_update_ref_frame_map(AV1_COMP *cpi, FRAME_UPDATE_TYPE frame_update_type, - int ref_map_index, + int show_existing_frame, int ref_map_index, RefBufferStack *ref_buffer_stack) { AV1_COMMON *const cm = &cpi->common; // TODO(jingning): Consider the S-frame same as key frame for the @@ -671,10 +640,13 @@ void av1_update_ref_frame_map(AV1_COMP *cpi, // expressed than converting the frame update type. if (frame_is_sframe(cm)) frame_update_type = KEY_FRAME; - if (is_frame_droppable(cpi)) return; + if (is_frame_droppable(&cpi->svc, &cpi->ext_flags)) return; switch (frame_update_type) { case KEY_FRAME: + if (show_existing_frame) + ref_map_index = stack_pop(ref_buffer_stack->arf_stack, + &ref_buffer_stack->arf_stack_size); stack_reset(ref_buffer_stack->lst_stack, &ref_buffer_stack->lst_stack_size); stack_reset(ref_buffer_stack->gld_stack, @@ -688,8 +660,8 @@ void av1_update_ref_frame_map(AV1_COMP *cpi, update_arf_stack(ref_map_index, ref_buffer_stack); stack_push(ref_buffer_stack->gld_stack, &ref_buffer_stack->gld_stack_size, ref_map_index); - // For fast nonrd_mode: update LAST as well on GF_UPDATE frame. - if (cpi->sf.use_fast_nonrd_pick_mode) + // For nonrd_mode: update LAST as well on GF_UPDATE frame. + if (cpi->sf.rt_sf.use_nonrd_pick_mode) stack_push(ref_buffer_stack->lst_stack, &ref_buffer_stack->lst_stack_size, ref_map_index); break; @@ -718,7 +690,6 @@ void av1_update_ref_frame_map(AV1_COMP *cpi, break; default: assert(0 && "unknown type"); } - return; } @@ -756,7 +727,8 @@ int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, FRAME_UPDATE_TYPE frame_update_type, const RefBufferStack *const ref_buffer_stack) { const AV1_COMMON *const cm = &cpi->common; - + const ExternalFlags *const ext_flags = &cpi->ext_flags; + const SVC *const svc = &cpi->svc; // 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) @@ -770,16 +742,15 @@ int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, return 0; } - if (is_frame_droppable(cpi)) return 0; + if (is_frame_droppable(svc, ext_flags)) return 0; int refresh_mask = 0; - if (cpi->ext_refresh_frame_flags_pending) { - if (cpi->svc.external_ref_frame_config) { + if (ext_flags->refresh_frame_flags_pending) { + if (svc->external_ref_frame_config) { for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) { - int ref_frame_map_idx = cpi->svc.ref_idx[i]; - refresh_mask |= cpi->svc.refresh[ref_frame_map_idx] - << ref_frame_map_idx; + int ref_frame_map_idx = svc->ref_idx[i]; + refresh_mask |= svc->refresh[ref_frame_map_idx] << ref_frame_map_idx; } return refresh_mask; } @@ -788,28 +759,28 @@ int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, // order to preserve the behaviour of the flag overrides. int ref_frame_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_last_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_last_frame << ref_frame_map_idx; ref_frame_map_idx = get_ref_frame_map_idx(cm, EXTREF_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_bwd_ref_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_bwd_ref_frame << ref_frame_map_idx; ref_frame_map_idx = get_ref_frame_map_idx(cm, ALTREF2_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_alt2_ref_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_alt2_ref_frame << ref_frame_map_idx; if (frame_update_type == OVERLAY_UPDATE) { ref_frame_map_idx = get_ref_frame_map_idx(cm, ALTREF_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_golden_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_golden_frame << ref_frame_map_idx; } else { ref_frame_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_golden_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_golden_frame << ref_frame_map_idx; ref_frame_map_idx = get_ref_frame_map_idx(cm, ALTREF_FRAME); if (ref_frame_map_idx != INVALID_IDX) - refresh_mask |= cpi->ext_refresh_alt_ref_frame << ref_frame_map_idx; + refresh_mask |= ext_flags->refresh_alt_ref_frame << ref_frame_map_idx; } return refresh_mask; } @@ -840,6 +811,10 @@ int av1_get_refresh_frame_flags(const AV1_COMP *const cpi, refresh_mask = 1 << ref_buffer_stack ->lst_stack[ref_buffer_stack->lst_stack_size - 1]; + else if (ref_buffer_stack->gld_stack_size >= 2) + refresh_mask = + 1 << ref_buffer_stack + ->gld_stack[ref_buffer_stack->gld_stack_size - 1]; else assert(0 && "No ref map index found"); } @@ -889,10 +864,7 @@ void setup_mi(AV1_COMP *const cpi, YV12_BUFFER_CONFIG *src) { av1_setup_block_planes(xd, cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, num_planes); - xd->mi = cm->mi_grid_base; - xd->mi[0] = cm->mi; - xd->tx_type_map = cm->tx_type_map; - xd->tx_type_map_stride = cm->mi_stride; + set_mi_offsets(&cm->mi_params, xd, 0, 0); } // Apply temporal filtering to key frames and encode the filtered frame. @@ -901,51 +873,36 @@ void setup_mi(AV1_COMP *const cpi, YV12_BUFFER_CONFIG *src) { static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, EncodeFrameInput *const frame_input, EncodeFrameParams *const frame_params, - EncodeFrameResults *const frame_results, - int *temporal_filtered) { - if (frame_params->frame_type != KEY_FRAME || - !cpi->oxcf.enable_keyframe_filtering) { - if (av1_encode(cpi, dest, frame_input, frame_params, frame_results) != - AOM_CODEC_OK) { - return AOM_CODEC_ERROR; - } - return AOM_CODEC_OK; - } - + EncodeFrameResults *const frame_results) { const AV1EncoderConfig *const oxcf = &cpi->oxcf; AV1_COMMON *const cm = &cpi->common; - double noise_level; - const int use_hbd = frame_input->source->flags & YV12_FLAG_HIGHBITDEPTH; - const int num_planes = av1_num_planes(cm); - if (use_hbd) { - noise_level = highbd_estimate_noise( - frame_input->source->y_buffer, frame_input->source->y_crop_width, - frame_input->source->y_crop_height, frame_input->source->y_stride, - cm->seq_params.bit_depth, EDGE_THRESHOLD); - } else { - noise_level = estimate_noise(frame_input->source->y_buffer, - frame_input->source->y_crop_width, - frame_input->source->y_crop_height, - frame_input->source->y_stride, EDGE_THRESHOLD); - } - const int apply_filtering = - oxcf->pass == 2 && frame_params->frame_type == KEY_FRAME && - cpi->rc.frames_to_key > NUM_KEY_FRAME_DENOISING && noise_level > 0 && + // Decide whether to apply temporal filtering to the source frame. + int apply_filtering = + frame_params->frame_type == KEY_FRAME && + oxcf->enable_keyframe_filtering && !is_stat_generation_stage(cpi) && + !frame_params->show_existing_frame && + cpi->rc.frames_to_key > TF_NUM_FILTERING_FRAMES_FOR_KEY_FRAME && !is_lossless_requested(oxcf) && oxcf->arnr_max_frames > 0; + if (apply_filtering) { + const double y_noise_level = av1_estimate_noise_from_single_plane( + frame_input->source, 0, cm->seq_params.bit_depth); + apply_filtering = y_noise_level > 0; + } + // Save the pointer to the original source image. YV12_BUFFER_CONFIG *source_kf_buffer = frame_input->source; - // Apply filtering to key frame and encode. + // Apply filtering to key frame. if (apply_filtering) { // Initialization for frame motion estimation. MACROBLOCKD *const xd = &cpi->td.mb.e_mbd; - av1_init_context_buffers(cm); + av1_init_mi_buffers(&cm->mi_params); setup_mi(cpi, frame_input->source); av1_init_macroblockd(cm, xd, NULL); - const int ext_mi_size = cm->mi_alloc_rows * cm->mi_alloc_cols; - memset(cpi->mbmi_ext_frame_base, 0, - ext_mi_size * sizeof(*cpi->mbmi_ext_frame_base)); + memset( + cpi->mbmi_ext_info.frame_base, 0, + cpi->mbmi_ext_info.alloc_size * sizeof(*cpi->mbmi_ext_info.frame_base)); av1_set_speed_features_framesize_independent(cpi, oxcf->speed); av1_set_speed_features_framesize_dependent(cpi, oxcf->speed); @@ -955,19 +912,25 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, av1_frame_init_quantizer(cpi); av1_setup_past_independence(cm); - av1_temporal_filter(cpi, -1, NULL); - aom_extend_frame_borders(&cpi->alt_ref_buffer, num_planes); + if (!frame_params->show_frame) { + int arf_src_index = get_arf_src_index(&cpi->gf_group, cpi->oxcf.pass); + av1_temporal_filter(cpi, -1 * arf_src_index, NULL); + } else { + av1_temporal_filter(cpi, -1, NULL); + } + aom_extend_frame_borders(&cpi->alt_ref_buffer, av1_num_planes(cm)); // Use the filtered frame for encoding. frame_input->source = &cpi->alt_ref_buffer; - *temporal_filtered = 1; + // Copy metadata info to alt-ref buffer. + aom_remove_metadata_from_frame_buffer(frame_input->source); + aom_copy_metadata_to_frame_buffer(frame_input->source, + source_kf_buffer->metadata); } - if (oxcf->lag_in_frames > 0 && oxcf->pass != 1 && - frame_params->frame_type == KEY_FRAME && frame_params->show_frame) { - av1_configure_buffer_updates(cpi, frame_params, KEY_FRAME, 0); - av1_set_frame_size(cpi, cm->width, cm->height); - av1_set_speed_features_framesize_independent(cpi, oxcf->speed); - av1_tpl_setup_stats(cpi, frame_params, frame_input); + if (frame_params->frame_type == KEY_FRAME && !is_stat_generation_stage(cpi) && + oxcf->enable_tpl_model && oxcf->lag_in_frames > 0 && + frame_params->show_frame) { + av1_tpl_setup_stats(cpi, 0, frame_params, frame_input); } if (av1_encode(cpi, dest, frame_input, frame_params, frame_results) != @@ -976,7 +939,7 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, } // Set frame_input source to true source for psnr calculation. - if (oxcf->arnr_max_frames > 0 && *temporal_filtered) { + if (apply_filtering) { cpi->source = source_kf_buffer; cpi->unscaled_source = source_kf_buffer; } @@ -985,109 +948,86 @@ static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest, } #endif // !CONFIG_REALTIME_ONLY +static INLINE int find_unused_ref_frame(const int *used_ref_frames, + const int *stack, int stack_size) { + for (int i = 0; i < stack_size; ++i) { + const int this_ref = stack[i]; + int ref_idx = 0; + for (ref_idx = 0; ref_idx <= ALTREF_FRAME - LAST_FRAME; ++ref_idx) { + if (this_ref == used_ref_frames[ref_idx]) break; + } + + // not in use + if (ref_idx > ALTREF_FRAME - LAST_FRAME) return this_ref; + } + + return INVALID_IDX; +} + void av1_get_ref_frames(AV1_COMP *const cpi, RefBufferStack *ref_buffer_stack) { AV1_COMMON *cm = &cpi->common; - + int *const remapped_ref_idx = cm->remapped_ref_idx; + int *const arf_stack = ref_buffer_stack->arf_stack; + int *const lst_stack = ref_buffer_stack->lst_stack; + int *const gld_stack = ref_buffer_stack->gld_stack; const int arf_stack_size = ref_buffer_stack->arf_stack_size; const int lst_stack_size = ref_buffer_stack->lst_stack_size; const int gld_stack_size = ref_buffer_stack->gld_stack_size; // Initialization - for (int i = 0; i < REF_FRAMES; ++i) cm->remapped_ref_idx[i] = INVALID_IDX; + for (int i = 0; i < REF_FRAMES; ++i) remapped_ref_idx[i] = INVALID_IDX; if (arf_stack_size) { - cm->remapped_ref_idx[ALTREF_FRAME - LAST_FRAME] = - ref_buffer_stack->arf_stack[arf_stack_size - 1]; + remapped_ref_idx[ALTREF_FRAME - LAST_FRAME] = arf_stack[arf_stack_size - 1]; if (arf_stack_size > 1) - cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = - ref_buffer_stack->arf_stack[0]; + remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = arf_stack[0]; if (arf_stack_size > 2) - cm->remapped_ref_idx[ALTREF2_FRAME - LAST_FRAME] = - ref_buffer_stack->arf_stack[1]; + remapped_ref_idx[ALTREF2_FRAME - LAST_FRAME] = arf_stack[1]; } if (lst_stack_size) { - cm->remapped_ref_idx[LAST_FRAME - LAST_FRAME] = - ref_buffer_stack->lst_stack[0]; + remapped_ref_idx[LAST_FRAME - LAST_FRAME] = lst_stack[0]; if (lst_stack_size > 1) - cm->remapped_ref_idx[LAST2_FRAME - LAST_FRAME] = - ref_buffer_stack->lst_stack[1]; + remapped_ref_idx[LAST2_FRAME - LAST_FRAME] = lst_stack[1]; } if (gld_stack_size) { - cm->remapped_ref_idx[GOLDEN_FRAME - LAST_FRAME] = - ref_buffer_stack->gld_stack[0]; + remapped_ref_idx[GOLDEN_FRAME - LAST_FRAME] = gld_stack[0]; if (gld_stack_size > 1) { if (arf_stack_size <= 1) - cm->remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = - ref_buffer_stack->gld_stack[1]; + remapped_ref_idx[BWDREF_FRAME - LAST_FRAME] = gld_stack[1]; else - cm->remapped_ref_idx[LAST3_FRAME - LAST_FRAME] = - ref_buffer_stack->gld_stack[1]; + remapped_ref_idx[LAST3_FRAME - LAST_FRAME] = gld_stack[1]; } } for (int idx = ALTREF_FRAME - LAST_FRAME; idx >= 0; --idx) { - int ref_map_index = cm->remapped_ref_idx[idx]; + int ref_map_index = remapped_ref_idx[idx]; if (ref_map_index != INVALID_IDX) continue; - for (int i = 0; - i < ref_buffer_stack->arf_stack_size && ref_map_index == INVALID_IDX; - ++i) { - int ref_idx = 0; - for (ref_idx = 0; ref_idx <= ALTREF_FRAME - LAST_FRAME; ++ref_idx) - if (ref_buffer_stack->arf_stack[i] == cm->remapped_ref_idx[ref_idx]) - break; + ref_map_index = + find_unused_ref_frame(remapped_ref_idx, arf_stack, arf_stack_size); - // not in use - if (ref_idx > ALTREF_FRAME - LAST_FRAME) { - ref_map_index = ref_buffer_stack->arf_stack[i]; - break; - } + if (ref_map_index == INVALID_IDX) { + ref_map_index = + find_unused_ref_frame(remapped_ref_idx, gld_stack, gld_stack_size); } - for (int i = 0; - i < ref_buffer_stack->gld_stack_size && ref_map_index == INVALID_IDX; - ++i) { - int ref_idx = 0; - for (ref_idx = 0; ref_idx <= ALTREF_FRAME - LAST_FRAME; ++ref_idx) - if (ref_buffer_stack->gld_stack[i] == cm->remapped_ref_idx[ref_idx]) - break; - - // not in use - if (ref_idx > ALTREF_FRAME - LAST_FRAME) { - ref_map_index = ref_buffer_stack->gld_stack[i]; - break; - } - } - - for (int i = 0; - i < ref_buffer_stack->lst_stack_size && ref_map_index == INVALID_IDX; - ++i) { - int ref_idx = 0; - for (ref_idx = 0; ref_idx <= ALTREF_FRAME - LAST_FRAME; ++ref_idx) - if (ref_buffer_stack->lst_stack[i] == cm->remapped_ref_idx[ref_idx]) - break; - - // not in use - if (ref_idx > ALTREF_FRAME - LAST_FRAME) { - ref_map_index = ref_buffer_stack->lst_stack[i]; - break; - } + if (ref_map_index == INVALID_IDX) { + ref_map_index = + find_unused_ref_frame(remapped_ref_idx, lst_stack, lst_stack_size); } if (ref_map_index != INVALID_IDX) - cm->remapped_ref_idx[idx] = ref_map_index; + remapped_ref_idx[idx] = ref_map_index; else - cm->remapped_ref_idx[idx] = ref_buffer_stack->gld_stack[0]; + remapped_ref_idx[idx] = ref_buffer_stack->gld_stack[0]; } - - return; } int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, @@ -1098,6 +1038,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, const AV1EncoderConfig *const oxcf = &cpi->oxcf; AV1_COMMON *const cm = &cpi->common; GF_GROUP *gf_group = &cpi->gf_group; + ExternalFlags *const ext_flags = &cpi->ext_flags; EncodeFrameInput frame_input; EncodeFrameParams frame_params; @@ -1107,15 +1048,25 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, memset(&frame_results, 0, sizeof(frame_results)); // TODO(sarahparker) finish bit allocation for one pass pyramid - if (oxcf->pass == 0 && oxcf->rc_mode != AOM_Q) - cpi->oxcf.gf_max_pyr_height = USE_ALTREF_FOR_ONE_PASS; + if (has_no_stats_stage(cpi) && oxcf->rc_mode != AOM_Q) { + cpi->oxcf.gf_max_pyr_height = + AOMMIN(cpi->oxcf.gf_max_pyr_height, USE_ALTREF_FOR_ONE_PASS); + cpi->oxcf.gf_min_pyr_height = + AOMMIN(cpi->oxcf.gf_min_pyr_height, cpi->oxcf.gf_max_pyr_height); + } - if (oxcf->pass == 0 || oxcf->pass == 2) { - frame_params.show_existing_frame = - ((oxcf->enable_overlay == 0 || cpi->sf.disable_overlay_frames || - cpi->show_existing_alt_ref) && - gf_group->update_type[gf_group->index] == OVERLAY_UPDATE) || - gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE; + if (!is_stat_generation_stage(cpi)) { + // If this is a forward keyframe, mark as a show_existing_frame + if (cpi->oxcf.fwd_kf_enabled && (gf_group->index == gf_group->size) && + gf_group->update_type[1] == ARF_UPDATE && cpi->rc.frames_to_key == 0) { + frame_params.show_existing_frame = 1; + } else { + frame_params.show_existing_frame = + ((oxcf->enable_overlay == 0 || cpi->sf.hl_sf.disable_overlay_frames || + cpi->show_existing_alt_ref) && + gf_group->update_type[gf_group->index] == OVERLAY_UPDATE) || + gf_group->update_type[gf_group->index] == INTNL_OVERLAY_UPDATE; + } frame_params.show_existing_frame &= allow_show_existing(cpi, *frame_flags); // Reset show_existing_alt_ref decision to 0 after it is used. @@ -1130,7 +1081,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, struct lookahead_entry *source = NULL; struct lookahead_entry *last_source = NULL; if (frame_params.show_existing_frame) { - source = av1_lookahead_pop(cpi->lookahead, flush); + source = av1_lookahead_pop(cpi->lookahead, flush, cpi->compressor_stage); frame_params.show_frame = 1; } else { int show_existing_alt_ref = 0; @@ -1153,12 +1104,14 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, frame_input.source = code_arf ? &cpi->alt_ref_buffer : &source->img; frame_input.last_source = last_source != NULL ? &last_source->img : NULL; frame_input.ts_duration = source->ts_end - source->ts_start; + // Save unfiltered source. It is used in av1_get_second_pass_params(). + cpi->unfiltered_source = frame_input.source; *time_stamp = source->ts_start; *time_end = source->ts_end; - if (source->ts_start < cpi->first_time_stamp_ever) { - cpi->first_time_stamp_ever = source->ts_start; - cpi->last_end_time_stamp_seen = source->ts_start; + if (source->ts_start < cpi->time_stamps.first_ever) { + cpi->time_stamps.first_ever = source->ts_start; + cpi->time_stamps.prev_end_seen = source->ts_start; } av1_apply_encoding_flags(cpi, source->flags); @@ -1166,7 +1119,8 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, *frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0; // Shown frames and arf-overlay frames need frame-rate considering - if (frame_params.show_frame) adjust_frame_rate(cpi, source); + if (frame_params.show_frame) + adjust_frame_rate(cpi, source->ts_start, source->ts_end); if (!frame_params.show_existing_frame) { if (cpi->film_grain_table) { @@ -1186,10 +1140,11 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, #if CONFIG_REALTIME_ONLY av1_get_one_pass_rt_params(cpi, &frame_params, *frame_flags); #else - if (oxcf->pass == 0 && oxcf->mode == REALTIME && oxcf->lag_in_frames == 0) + if (has_no_stats_stage(cpi) && oxcf->mode == REALTIME && + oxcf->lag_in_frames == 0) av1_get_one_pass_rt_params(cpi, &frame_params, *frame_flags); - else if (oxcf->pass != 1) - av1_get_second_pass_params(cpi, &frame_params, *frame_flags); + else if (!is_stat_generation_stage(cpi)) + av1_get_second_pass_params(cpi, &frame_params, &frame_input, *frame_flags); #endif FRAME_UPDATE_TYPE frame_update_type = get_frame_update_type(gf_group); @@ -1211,9 +1166,9 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, frame_params.speed = oxcf->speed; // Work out some encoding parameters specific to the pass: - if (cpi->oxcf.pass == 0 && cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { + if (has_no_stats_stage(cpi) && cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_update_parameters(cpi); - } else if (oxcf->pass == 1) { + } else if (is_stat_generation_stage(cpi)) { cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf); const int kf_requested = (cm->current_frame.frame_number == 0 || (*frame_flags & FRAMEFLAGS_KEY)); @@ -1223,7 +1178,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, } else { frame_params.frame_type = INTER_FRAME; } - } else if (oxcf->pass == 2) { + } else if (is_stat_consumption_stage(cpi)) { #if CONFIG_MISMATCH_DEBUG mismatch_move_frame_idx_w(); #endif @@ -1233,7 +1188,8 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, #endif } - if (oxcf->pass == 0 || oxcf->pass == 2) set_ext_overrides(cpi, &frame_params); + if (!is_stat_generation_stage(cpi)) + set_ext_overrides(cm, &frame_params, ext_flags); // Shown keyframes and S frames refresh all reference buffers const int force_refresh_all = @@ -1244,16 +1200,25 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, av1_configure_buffer_updates(cpi, &frame_params, frame_update_type, force_refresh_all); - if (oxcf->pass == 0 || oxcf->pass == 2) { - if (!cpi->ext_refresh_frame_flags_pending) { + if (!is_stat_generation_stage(cpi)) { + const RefCntBuffer *ref_frames[INTER_REFS_PER_FRAME]; + const YV12_BUFFER_CONFIG *ref_frame_buf[INTER_REFS_PER_FRAME]; + + if (!ext_flags->refresh_frame_flags_pending) { av1_get_ref_frames(cpi, &cpi->ref_buffer_stack); } else if (cpi->svc.external_ref_frame_config) { for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) cm->remapped_ref_idx[i] = cpi->svc.ref_idx[i]; } + // Get the reference frames + for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { + ref_frames[i] = get_ref_frame_buf(cm, ref_frame_priority_order[i]); + ref_frame_buf[i] = ref_frames[i] != NULL ? &ref_frames[i]->buf : NULL; + } // Work out which reference frame slots may be used. - frame_params.ref_frame_flags = get_ref_frame_flags(cpi); + frame_params.ref_frame_flags = get_ref_frame_flags( + &cpi->sf, ref_frame_buf, ext_flags->ref_frame_flags); frame_params.primary_ref_frame = choose_primary_ref_frame(cpi, &frame_params); @@ -1284,15 +1249,13 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, cpi->td.mb.e_mbd.delta_qindex = 0; 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; + cm->quant_params.using_qmatrix = cpi->oxcf.using_qm; #if !CONFIG_REALTIME_ONLY - if (oxcf->lag_in_frames > 0 && oxcf->pass != 1) { + if (oxcf->lag_in_frames > 0 && !is_stat_generation_stage(cpi)) { if (cpi->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_params, &frame_input); + av1_tpl_setup_stats(cpi, 0, &frame_params, &frame_input); assert(cpi->num_gf_group_show_frames == 1); } } @@ -1305,27 +1268,28 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, return AOM_CODEC_ERROR; } #else - if (denoise_and_encode(cpi, dest, &frame_input, &frame_params, &frame_results, - &code_arf) != AOM_CODEC_OK) { + if (denoise_and_encode(cpi, dest, &frame_input, &frame_params, + &frame_results) != AOM_CODEC_OK) { return AOM_CODEC_ERROR; } #endif // CONFIG_REALTIME_ONLY - if (oxcf->pass != 1) cpi->num_gf_group_show_frames += frame_params.show_frame; + if (!is_stat_generation_stage(cpi)) + cpi->num_gf_group_show_frames += frame_params.show_frame; - if (oxcf->pass == 0 || oxcf->pass == 2) { + if (!is_stat_generation_stage(cpi)) { // First pass doesn't modify reference buffer assignment or produce frame // flags update_frame_flags(cpi, frame_flags); - if (!cpi->ext_refresh_frame_flags_pending) { + if (!ext_flags->refresh_frame_flags_pending) { int ref_map_index = av1_get_refresh_ref_frame_map(cm->current_frame.refresh_frame_flags); - av1_update_ref_frame_map(cpi, frame_update_type, ref_map_index, - &cpi->ref_buffer_stack); + av1_update_ref_frame_map(cpi, frame_update_type, cm->show_existing_frame, + ref_map_index, &cpi->ref_buffer_stack); } } #if !CONFIG_REALTIME_ONLY - if (oxcf->pass != 1) { + if (!is_stat_generation_stage(cpi)) { #if TXCOEFF_COST_TIMER cm->cum_txcoeff_cost_timer += cm->txcoeff_cost_timer; fprintf(stderr, @@ -1338,7 +1302,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, } #endif // !CONFIG_REALTIME_ONLY - if (oxcf->pass != 1) { + if (!is_stat_generation_stage(cpi)) { update_fb_of_context_type(cpi, &frame_params, cpi->fb_of_context_type); set_additional_frame_flags(cm, frame_flags); update_rc_counts(cpi); @@ -1349,7 +1313,7 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size, // Leave a signal for a higher level caller about if this frame is droppable if (*size > 0) { - cpi->droppable = is_frame_droppable(cpi); + cpi->droppable = is_frame_droppable(&cpi->svc, ext_flags); } if (cpi->use_svc) av1_save_layer_context(cpi); diff --git a/media/libaom/src/av1/encoder/encode_strategy.h b/media/libaom/src/av1/encoder/encode_strategy.h index 76eb1bb47f..b05224ba11 100644 --- a/media/libaom/src/av1/encoder/encode_strategy.h +++ b/media/libaom/src/av1/encoder/encode_strategy.h @@ -49,11 +49,14 @@ int av1_get_refresh_ref_frame_map(int refresh_frame_flags); void av1_update_ref_frame_map(AV1_COMP *cpi, FRAME_UPDATE_TYPE frame_update_type, - int ref_map_index, + int show_existing_frame, int ref_map_index, RefBufferStack *ref_buffer_stack); void av1_get_ref_frames(AV1_COMP *const cpi, RefBufferStack *ref_buffer_stack); +int is_forced_keyframe_pending(struct lookahead_ctx *lookahead, + const int up_to_index, + const COMPRESSOR_STAGE compressor_stage); #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/encodeframe.c b/media/libaom/src/av1/encoder/encodeframe.c index 9bcc3c7f32..53b47d49e9 100644 --- a/media/libaom/src/av1/encoder/encodeframe.c +++ b/media/libaom/src/av1/encoder/encodeframe.c @@ -56,6 +56,7 @@ #include "av1/encoder/ethread.h" #include "av1/encoder/extend.h" #include "av1/encoder/ml.h" +#include "av1/encoder/motion_search_facade.h" #include "av1/encoder/partition_strategy.h" #if !CONFIG_REALTIME_ONLY #include "av1/encoder/partition_model_weights.h" @@ -68,10 +69,13 @@ #include "av1/encoder/tpl_model.h" #include "av1/encoder/var_based_part.h" +#if CONFIG_TUNE_VMAF +#include "av1/encoder/tune_vmaf.h" +#endif + static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, TileDataEnc *tile_data, ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run, - int mi_row, int mi_col, BLOCK_SIZE bsize, int *rate); // This is used as a reference when computing the source variance for the @@ -143,7 +147,42 @@ static const uint16_t AV1_HIGH_VAR_OFFS_12[MAX_SB_SIZE] = { 128 * 16, 128 * 16 }; -enum { PICK_MODE_RD = 0, PICK_MODE_NONRD, PICK_MODE_FAST_NONRD }; +typedef struct { + ENTROPY_CONTEXT a[MAX_MIB_SIZE * MAX_MB_PLANE]; + ENTROPY_CONTEXT l[MAX_MIB_SIZE * MAX_MB_PLANE]; + PARTITION_CONTEXT sa[MAX_MIB_SIZE]; + PARTITION_CONTEXT sl[MAX_MIB_SIZE]; + TXFM_CONTEXT *p_ta; + TXFM_CONTEXT *p_tl; + TXFM_CONTEXT ta[MAX_MIB_SIZE]; + TXFM_CONTEXT tl[MAX_MIB_SIZE]; +} RD_SEARCH_MACROBLOCK_CONTEXT; + +enum { PICK_MODE_RD = 0, PICK_MODE_NONRD }; + +enum { + SB_SINGLE_PASS, // Single pass encoding: all ctxs get updated normally + SB_DRY_PASS, // First pass of multi-pass: does not update the ctxs + SB_WET_PASS // Second pass of multi-pass: finalize and update the ctx +} UENUM1BYTE(SB_MULTI_PASS_MODE); + +// This struct is used to store the statistics used by sb-level multi-pass +// encoding. Currently, this is only used to make a copy of the state before we +// perform the first pass +typedef struct SB_FIRST_PASS_STATS { + RD_SEARCH_MACROBLOCK_CONTEXT x_ctx; + RD_COUNTS rd_count; + + int split_count; + FRAME_COUNTS fc; + InterModeRdModel inter_mode_rd_models[BLOCK_SIZES_ALL]; + int thresh_freq_fact[BLOCK_SIZES_ALL][MAX_MODES]; + int current_qindex; + +#if CONFIG_INTERNAL_STATS + unsigned int mode_chosen_counts[MAX_MODES]; +#endif // CONFIG_INTERNAL_STATS +} SB_FIRST_PASS_STATS; unsigned int av1_get_sby_perpixel_variance(const AV1_COMP *cpi, const struct buf_2d *ref, @@ -158,28 +197,17 @@ unsigned int av1_high_get_sby_perpixel_variance(const AV1_COMP *cpi, const struct buf_2d *ref, BLOCK_SIZE bs, int bd) { unsigned int var, sse; - switch (bd) { - case 10: - var = - cpi->fn_ptr[bs].vf(ref->buf, ref->stride, - CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_10), 0, &sse); - break; - case 12: - var = - cpi->fn_ptr[bs].vf(ref->buf, ref->stride, - CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_12), 0, &sse); - break; - case 8: - default: - var = - cpi->fn_ptr[bs].vf(ref->buf, ref->stride, - CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_8), 0, &sse); - break; - } + assert(bd == 8 || bd == 10 || bd == 12); + const int off_index = (bd - 8) >> 1; + const uint16_t *high_var_offs[3] = { AV1_HIGH_VAR_OFFS_8, + AV1_HIGH_VAR_OFFS_10, + AV1_HIGH_VAR_OFFS_12 }; + var = + cpi->fn_ptr[bs].vf(ref->buf, ref->stride, + CONVERT_TO_BYTEPTR(high_var_offs[off_index]), 0, &sse); return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]); } -#if !CONFIG_REALTIME_ONLY static unsigned int get_sby_perpixel_diff_variance(const AV1_COMP *const cpi, const struct buf_2d *ref, int mi_row, int mi_col, @@ -209,13 +237,12 @@ static BLOCK_SIZE get_rd_var_based_fixed_partition(AV1_COMP *cpi, MACROBLOCK *x, else return BLOCK_8X8; } -#endif // !CONFIG_REALTIME_ONLY static int set_deltaq_rdmult(const AV1_COMP *const cpi, MACROBLOCKD *const xd) { const AV1_COMMON *const cm = &cpi->common; - - return av1_compute_rd_mult( - cpi, cm->base_qindex + xd->delta_qindex + cm->y_dc_delta_q); + const CommonQuantParams *quant_params = &cm->quant_params; + return av1_compute_rd_mult(cpi, quant_params->base_qindex + xd->delta_qindex + + quant_params->y_dc_delta_q); } static AOM_INLINE void set_ssim_rdmult(const AV1_COMP *const cpi, @@ -227,8 +254,8 @@ static AOM_INLINE void set_ssim_rdmult(const AV1_COMP *const cpi, const int bsize_base = BLOCK_16X16; const int num_mi_w = mi_size_wide[bsize_base]; const int num_mi_h = mi_size_high[bsize_base]; - const int num_cols = (cm->mi_cols + num_mi_w - 1) / num_mi_w; - const int num_rows = (cm->mi_rows + num_mi_h - 1) / num_mi_h; + const int num_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w; + const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h; const int num_bcols = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w; const int num_brows = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h; int row, col; @@ -262,24 +289,20 @@ static int get_hier_tpl_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x, assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int tpl_idx = cpi->gf_group.index; - const TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_idx]; + const TplDepFrame *tpl_frame = &cpi->tpl_data.tpl_frame[tpl_idx]; MACROBLOCKD *const xd = &x->e_mbd; const int deltaq_rdmult = set_deltaq_rdmult(cpi, xd); - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - return deltaq_rdmult; - } if (tpl_frame->is_valid == 0) return deltaq_rdmult; if (!is_frame_tpl_eligible((AV1_COMP *)cpi)) return deltaq_rdmult; if (tpl_idx >= MAX_LAG_BUFFERS) return deltaq_rdmult; - if (cpi->oxcf.superres_mode != SUPERRES_NONE) return deltaq_rdmult; + if (cpi->superres_mode != SUPERRES_NONE) return deltaq_rdmult; if (cpi->oxcf.aq_mode != NO_AQ) return deltaq_rdmult; const int bsize_base = BLOCK_16X16; const int num_mi_w = mi_size_wide[bsize_base]; const int num_mi_h = mi_size_high[bsize_base]; - const int num_cols = (cm->mi_cols + num_mi_w - 1) / num_mi_w; - const int num_rows = (cm->mi_rows + num_mi_h - 1) / num_mi_h; + const int num_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w; + const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h; const int num_bcols = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w; const int num_brows = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h; int row, col; @@ -313,8 +336,10 @@ static int set_segment_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x, const AV1_COMMON *const cm = &cpi->common; av1_init_plane_quantizers(cpi, x, segment_id); aom_clear_system_state(); - int segment_qindex = av1_get_qindex(&cm->seg, segment_id, cm->base_qindex); - return av1_compute_rd_mult(cpi, segment_qindex + cm->y_dc_delta_q); + const int segment_qindex = + av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex); + return av1_compute_rd_mult(cpi, + segment_qindex + cm->quant_params.y_dc_delta_q); } static AOM_INLINE void setup_block_rdmult(const AV1_COMP *const cpi, @@ -343,13 +368,20 @@ static AOM_INLINE void setup_block_rdmult(const AV1_COMP *const cpi, } const AV1_COMMON *const cm = &cpi->common; - if (cm->delta_q_info.delta_q_present_flag) { + if (cm->delta_q_info.delta_q_present_flag && + !cpi->sf.rt_sf.use_nonrd_pick_mode) { x->rdmult = get_hier_tpl_rdmult(cpi, x, bsize, mi_row, mi_col, x->rdmult); } if (cpi->oxcf.tuning == AOM_TUNE_SSIM) { set_ssim_rdmult(cpi, x, bsize, mi_row, mi_col, &x->rdmult); } +#if CONFIG_TUNE_VMAF + if (cpi->oxcf.tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_set_vmaf_rdmult(cpi, x, bsize, mi_row, mi_col, &x->rdmult); + } +#endif } static AOM_INLINE void set_offsets_without_segment_id( @@ -362,10 +394,11 @@ static AOM_INLINE void set_offsets_without_segment_id( 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_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, x, xd, + mi_row, mi_col); - set_skip_context(xd, mi_row, mi_col, num_planes); - xd->above_txfm_context = cm->above_txfm_context[tile->tile_row] + mi_col; + set_entropy_context(xd, mi_row, mi_col, num_planes); + xd->above_txfm_context = cm->above_contexts.txfm[tile->tile_row] + mi_col; xd->left_txfm_context = xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); @@ -375,27 +408,21 @@ static AOM_INLINE void set_offsets_without_segment_id( // 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; + av1_set_mv_limits(&cm->mi_params, &x->mv_limits, mi_row, mi_col, mi_height, + mi_width, cpi->oxcf.border_in_pixels); 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))); - set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, cm->mi_rows, - cm->mi_cols); + set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, + cm->mi_params.mi_rows, cm->mi_params.mi_cols); // Set up source buffers. av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, bsize); // required by av1_append_sub8x8_mvs_for_idx() and av1_find_best_ref_mvs() xd->tile = *tile; - - xd->cfl.mi_row = mi_row; - xd->cfl.mi_col = mi_col; } static AOM_INLINE void set_offsets(const AV1_COMP *const cpi, @@ -415,9 +442,9 @@ static AOM_INLINE void set_offsets(const AV1_COMP *const cpi, if (seg->enabled) { if (seg->enabled && !cpi->vaq_refresh) { const uint8_t *const map = - seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; + seg->update_map ? cpi->enc_seg.map : cm->last_frame_seg_map; mbmi->segment_id = - map ? get_segment_id(cm, map, bsize, mi_row, mi_col) : 0; + map ? get_segment_id(&cm->mi_params, map, bsize, mi_row, mi_col) : 0; } av1_init_plane_quantizers(cpi, x, mbmi->segment_id); } @@ -480,7 +507,22 @@ static AOM_INLINE void reset_tx_size(MACROBLOCK *x, MB_MODE_INFO *mbmi, bw * sizeof(xd->tx_type_map[0])); } av1_zero(x->blk_skip); - x->skip = 0; + x->force_skip = 0; +} + +// This function will copy the best reference mode information from +// MB_MODE_INFO_EXT_FRAME to MB_MODE_INFO_EXT. +static INLINE void copy_mbmi_ext_frame_to_mbmi_ext( + MB_MODE_INFO_EXT *mbmi_ext, + const MB_MODE_INFO_EXT_FRAME *const mbmi_ext_best, uint8_t ref_frame_type) { + memcpy(mbmi_ext->ref_mv_stack[ref_frame_type], mbmi_ext_best->ref_mv_stack, + sizeof(mbmi_ext->ref_mv_stack[USABLE_REF_MV_STACK_SIZE])); + memcpy(mbmi_ext->weight[ref_frame_type], mbmi_ext_best->weight, + sizeof(mbmi_ext->weight[USABLE_REF_MV_STACK_SIZE])); + mbmi_ext->mode_context[ref_frame_type] = mbmi_ext_best->mode_context; + mbmi_ext->ref_mv_count[ref_frame_type] = mbmi_ext_best->ref_mv_count; + memcpy(mbmi_ext->global_mvs, mbmi_ext_best->global_mvs, + sizeof(mbmi_ext->global_mvs)); } static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, @@ -489,6 +531,7 @@ static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, RUN_TYPE dry_run) { int i, x_idx, y; const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; const int num_planes = av1_num_planes(cm); RD_COUNTS *const rdc = &td->rd_counts; MACROBLOCK *const x = &td->mb; @@ -500,27 +543,28 @@ static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, const struct segmentation *const seg = &cm->seg; const int bw = mi_size_wide[mi->sb_type]; const int bh = mi_size_high[mi->sb_type]; - const int mis = cm->mi_stride; + const int mis = mi_params->mi_stride; const int mi_width = mi_size_wide[bsize]; const int mi_height = mi_size_high[bsize]; assert(mi->sb_type == bsize); *mi_addr = *mi; - *x->mbmi_ext = ctx->mbmi_ext; + copy_mbmi_ext_frame_to_mbmi_ext(x->mbmi_ext, &ctx->mbmi_ext_best, + av1_ref_frame_type(ctx->mic.ref_frame)); memcpy(x->blk_skip, ctx->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - x->skip = ctx->rd_stats.skip; + x->force_skip = ctx->rd_stats.skip; xd->tx_type_map = ctx->tx_type_map; xd->tx_type_map_stride = mi_size_wide[bsize]; // If not dry_run, copy the transform type data into the frame level buffer. // Encoder will fetch tx types when writing bitstream. if (!dry_run) { - const int grid_idx = get_mi_grid_idx(cm, mi_row, mi_col); - uint8_t *const tx_type_map = cm->tx_type_map + grid_idx; - const int mi_stride = cm->mi_stride; + const int grid_idx = get_mi_grid_idx(mi_params, mi_row, mi_col); + uint8_t *const tx_type_map = mi_params->tx_type_map + grid_idx; + const int mi_stride = mi_params->mi_stride; for (int blk_row = 0; blk_row < bh; ++blk_row) { av1_copy_array(tx_type_map + blk_row * mi_stride, xd->tx_type_map + blk_row * xd->tx_type_map_stride, bw); @@ -534,17 +578,17 @@ static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, // For in frame complexity AQ copy the segment id from the segment map. if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { const uint8_t *const map = - seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; + seg->update_map ? cpi->enc_seg.map : cm->last_frame_seg_map; mi_addr->segment_id = - map ? get_segment_id(cm, map, bsize, mi_row, mi_col) : 0; - reset_tx_size(x, mi_addr, x->tx_mode); + map ? get_segment_id(mi_params, map, bsize, mi_row, mi_col) : 0; + reset_tx_size(x, mi_addr, x->tx_mode_search_type); } // Else for cyclic refresh mode update the segment map, set the segment id // and then update the quantizer. if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_update_segment(cpi, mi_addr, mi_row, mi_col, bsize, ctx->rd_stats.rate, ctx->rd_stats.dist, - x->skip); + x->force_skip); } if (mi_addr->uv_mode == UV_CFL_PRED && !is_cfl_allowed(xd)) mi_addr->uv_mode = UV_DC_PRED; @@ -607,7 +651,7 @@ static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, update_global_motion_used(mi_addr->mode, bsize, mi_addr, rdc); } - if (cm->interp_filter == SWITCHABLE && + if (cm->features.interp_filter == SWITCHABLE && mi_addr->motion_mode != WARPED_CAUSAL && !is_nontrans_global_motion(xd, xd->mi[0])) { update_filter_type_count(td->counts, xd, mi_addr); @@ -618,8 +662,8 @@ static AOM_INLINE void update_state(const AV1_COMP *const cpi, ThreadData *td, rdc->comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff; } - const int x_mis = AOMMIN(bw, cm->mi_cols - mi_col); - const int y_mis = AOMMIN(bh, cm->mi_rows - mi_row); + const int x_mis = AOMMIN(bw, mi_params->mi_cols - mi_col); + const int y_mis = AOMMIN(bh, mi_params->mi_rows - mi_row); if (cm->seq_params.order_hint_info.enable_ref_frame_mvs) av1_copy_frame_mvs(cm, mi, mi_row, mi_col, x_mis, y_mis); } @@ -662,23 +706,16 @@ static int use_pb_simple_motion_pred_sse(const AV1_COMP *const cpi) { return 0 && !frame_is_intra_only(&cpi->common); } -// This function will copy the winner reference mode information from block -// level (x->mbmi_ext) to frame level (cpi->mbmi_ext_frame_base). This frame -// level buffer (cpi->mbmi_ext_frame_base) will be used during bitstream -// preparation. -static INLINE void copy_winner_ref_mode_from_mbmi_ext(MACROBLOCK *const x) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); - memcpy(x->mbmi_ext_frame->ref_mv_stack, - x->mbmi_ext->ref_mv_stack[ref_frame_type], - sizeof(x->mbmi_ext->ref_mv_stack[USABLE_REF_MV_STACK_SIZE])); - memcpy(x->mbmi_ext_frame->weight, x->mbmi_ext->weight[ref_frame_type], - sizeof(x->mbmi_ext->weight[USABLE_REF_MV_STACK_SIZE])); - x->mbmi_ext_frame->mode_context = x->mbmi_ext->mode_context[ref_frame_type]; - x->mbmi_ext_frame->ref_mv_count = x->mbmi_ext->ref_mv_count[ref_frame_type]; - memcpy(x->mbmi_ext_frame->global_mvs, x->mbmi_ext->global_mvs, - sizeof(x->mbmi_ext->global_mvs)); +static void hybrid_intra_mode_search(AV1_COMP *cpi, MACROBLOCK *const x, + RD_STATS *rd_cost, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx) { + // TODO(jianj): Investigate the failure of ScalabilityTest in AOM_Q mode, + // which sets base_qindex to 0 on keyframe. + if (cpi->oxcf.rc_mode != AOM_CBR || !cpi->sf.rt_sf.hybrid_intra_pickmode || + bsize < BLOCK_16X16) + av1_rd_pick_intra_mode_sb(cpi, x, rd_cost, bsize, ctx, INT64_MAX); + else + av1_pick_intra_mode(cpi, x, rd_cost, bsize, ctx); } static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, @@ -748,9 +785,6 @@ static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, mbmi->skip = 0; // Reset skip mode flag. mbmi->skip_mode = 0; - x->skip_chroma_rd = - !is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y); if (is_cur_buf_hbd(xd)) { x->source_variance = av1_high_get_sby_perpixel_variance( @@ -760,15 +794,15 @@ static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, 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 }; + const FULLPEL_MV start_mv = kZeroFullMv; unsigned int var = 0; - av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full, 0, + av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, start_mv, 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) { + if (cpi->sf.inter_sf.disable_wedge_search_edge_thresh == 0) { x->edge_strength = UINT16_MAX; x->edge_strength_x = UINT16_MAX; x->edge_strength_y = UINT16_MAX; @@ -796,8 +830,15 @@ static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, #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.rdcost); + switch (pick_mode_type) { + case PICK_MODE_RD: + av1_rd_pick_intra_mode_sb(cpi, x, rd_cost, bsize, ctx, best_rd.rdcost); + break; + case PICK_MODE_NONRD: + hybrid_intra_mode_search(cpi, x, rd_cost, bsize, ctx); + break; + default: assert(0 && "Unknown pick mode type."); + } #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, av1_rd_pick_intra_mode_sb_time); #endif @@ -809,21 +850,15 @@ static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, av1_rd_pick_inter_mode_sb_seg_skip(cpi, tile_data, x, mi_row, mi_col, rd_cost, bsize, ctx, best_rd.rdcost); } else { - // TODO(kyslov): do the same for pick_intra_mode and - // pick_inter_mode_sb_seg_skip + // TODO(kyslov): do the same for pick_inter_mode_sb_seg_skip switch (pick_mode_type) { case PICK_MODE_RD: - av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost, - bsize, ctx, best_rd.rdcost); + av1_rd_pick_inter_mode_sb(cpi, tile_data, x, rd_cost, bsize, ctx, + best_rd.rdcost); break; case PICK_MODE_NONRD: - av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, - rd_cost, bsize, ctx, best_rd.rdcost); - break; - case PICK_MODE_FAST_NONRD: - av1_fast_nonrd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, - rd_cost, bsize, ctx, - best_rd.rdcost); + av1_nonrd_pick_inter_mode_sb(cpi, tile_data, x, rd_cost, bsize, ctx, + best_rd.rdcost); break; default: assert(0 && "Unknown pick mode type."); } @@ -834,11 +869,8 @@ static AOM_INLINE void pick_sb_modes(AV1_COMP *const cpi, } // Examine the resulting rate and for AQ mode 2 make a segment choice. - if ((rd_cost->rate != INT_MAX) && (aq_mode == COMPLEXITY_AQ) && - (bsize >= BLOCK_16X16) && - (cm->current_frame.frame_type == KEY_FRAME || - cpi->refresh_alt_ref_frame || cpi->refresh_bwd_ref_frame || - (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref))) { + if (rd_cost->rate != INT_MAX && aq_mode == COMPLEXITY_AQ && + bsize >= BLOCK_16X16) { av1_caq_select_segment(cpi, x, bsize, mi_row, mi_col, rd_cost->rate); } @@ -950,8 +982,7 @@ static AOM_INLINE void sum_intra_stats(const AV1_COMMON *const cm, const MB_MODE_INFO *const mbmi, const MB_MODE_INFO *above_mi, const MB_MODE_INFO *left_mi, - const int intraonly, const int mi_row, - const int mi_col) { + const int intraonly) { FRAME_CONTEXT *fc = xd->tile_ctx; const PREDICTION_MODE y_mode = mbmi->mode; (void)counts; @@ -1000,10 +1031,7 @@ static AOM_INLINE void sum_intra_stats(const AV1_COMMON *const cm, 2 * MAX_ANGLE_DELTA + 1); } - if (!is_chroma_reference(mi_row, mi_col, bsize, - xd->plane[AOM_PLANE_U].subsampling_x, - xd->plane[AOM_PLANE_U].subsampling_y)) - return; + if (!xd->is_chroma_ref) return; const UV_PREDICTION_MODE uv_mode = mbmi->uv_mode; const CFL_ALLOWED_TYPE cfl_allowed = is_cfl_allowed(xd); @@ -1047,13 +1075,13 @@ static AOM_INLINE void sum_intra_stats(const AV1_COMMON *const cm, mbmi->angle_delta[PLANE_TYPE_UV] + MAX_ANGLE_DELTA, 2 * MAX_ANGLE_DELTA + 1); } - if (av1_allow_palette(cm->allow_screen_content_tools, bsize)) { + if (av1_allow_palette(cm->features.allow_screen_content_tools, bsize)) { update_palette_cdf(xd, mbmi, counts); } } -static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, - int mi_row, int mi_col) { +static AOM_INLINE void update_stats(const AV1_COMMON *const cm, + ThreadData *td) { MACROBLOCK *x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; const MB_MODE_INFO *const mbmi = xd->mi[0]; @@ -1084,8 +1112,8 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, #if CONFIG_ENTROPY_STATS // delta quant applies to both intra and inter const int super_block_upper_left = - ((mi_row & (cm->seq_params.mib_size - 1)) == 0) && - ((mi_col & (cm->seq_params.mib_size - 1)) == 0); + ((xd->mi_row & (cm->seq_params.mib_size - 1)) == 0) && + ((xd->mi_col & (cm->seq_params.mib_size - 1)) == 0); const DeltaQInfo *const delta_q_info = &cm->delta_q_info; if (delta_q_info->delta_q_present_flag && (bsize != cm->seq_params.sb_size || !mbmi->skip) && @@ -1128,7 +1156,7 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, if (!is_inter_block(mbmi)) { sum_intra_stats(cm, td->counts, xd, mbmi, xd->above_mbmi, xd->left_mbmi, - frame_is_intra_only(cm), mi_row, mi_col); + frame_is_intra_only(cm)); } if (av1_allow_intrabc(cm)) { @@ -1294,7 +1322,7 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, #endif update_cdf(fc->interintra_mode_cdf[bsize_group], mbmi->interintra_mode, INTERINTRA_MODES); - if (is_interintra_wedge_used(bsize)) { + if (av1_is_wedge_used(bsize)) { #if CONFIG_ENTROPY_STATS counts->wedge_interintra[bsize][mbmi->use_wedge_interintra]++; #endif @@ -1317,9 +1345,9 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, } const MOTION_MODE motion_allowed = - cm->switchable_motion_mode + cm->features.switchable_motion_mode ? motion_mode_allowed(xd->global_motion, xd, mbmi, - cm->allow_warped_motion) + cm->features.allow_warped_motion) : SIMPLE_TRANSLATION; if (mbmi->ref_frame[1] != INTRA_FRAME) { if (motion_allowed == WARPED_CAUSAL) { @@ -1384,7 +1412,7 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, } } - if (inter_block && cm->interp_filter == SWITCHABLE && + if (inter_block && cm->features.interp_filter == SWITCHABLE && mbmi->motion_mode != WARPED_CAUSAL && !is_nontrans_global_motion(xd, mbmi)) { update_filter_type_cdf(xd, mbmi); @@ -1435,9 +1463,9 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, } } if (have_newmv_in_inter_mode(mbmi->mode)) { - const int allow_hp = cm->cur_frame_force_integer_mv + const int allow_hp = cm->features.cur_frame_force_integer_mv ? MV_SUBPEL_NONE - : cm->allow_high_precision_mv; + : cm->features.allow_high_precision_mv; if (new_mv) { for (int ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { const int_mv ref_mv = av1_get_ref_mv(x, ref); @@ -1459,45 +1487,33 @@ static AOM_INLINE void update_stats(const AV1_COMMON *const cm, ThreadData *td, } } -typedef struct { - ENTROPY_CONTEXT a[MAX_MIB_SIZE * MAX_MB_PLANE]; - ENTROPY_CONTEXT l[MAX_MIB_SIZE * MAX_MB_PLANE]; - PARTITION_CONTEXT sa[MAX_MIB_SIZE]; - PARTITION_CONTEXT sl[MAX_MIB_SIZE]; - TXFM_CONTEXT *p_ta; - TXFM_CONTEXT *p_tl; - TXFM_CONTEXT ta[MAX_MIB_SIZE]; - TXFM_CONTEXT tl[MAX_MIB_SIZE]; -} RD_SEARCH_MACROBLOCK_CONTEXT; - static AOM_INLINE void restore_context(MACROBLOCK *x, const RD_SEARCH_MACROBLOCK_CONTEXT *ctx, int mi_row, int mi_col, BLOCK_SIZE bsize, const int num_planes) { MACROBLOCKD *xd = &x->e_mbd; int p; - const int num_4x4_blocks_wide = - block_size_wide[bsize] >> tx_size_wide_log2[0]; - const int num_4x4_blocks_high = - block_size_high[bsize] >> tx_size_high_log2[0]; + const int num_4x4_blocks_wide = mi_size_wide[bsize]; + const int num_4x4_blocks_high = mi_size_high[bsize]; int mi_width = mi_size_wide[bsize]; int mi_height = mi_size_high[bsize]; for (p = 0; p < num_planes; p++) { int tx_col = mi_col; int tx_row = mi_row & MAX_MIB_MASK; - memcpy(xd->above_context[p] + (tx_col >> xd->plane[p].subsampling_x), - ctx->a + num_4x4_blocks_wide * p, - (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> - xd->plane[p].subsampling_x); - memcpy(xd->left_context[p] + (tx_row >> xd->plane[p].subsampling_y), + memcpy( + xd->above_entropy_context[p] + (tx_col >> xd->plane[p].subsampling_x), + ctx->a + num_4x4_blocks_wide * p, + (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> + xd->plane[p].subsampling_x); + memcpy(xd->left_entropy_context[p] + (tx_row >> xd->plane[p].subsampling_y), ctx->l + num_4x4_blocks_high * p, (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >> xd->plane[p].subsampling_y); } - memcpy(xd->above_seg_context + mi_col, ctx->sa, - sizeof(*xd->above_seg_context) * mi_width); - memcpy(xd->left_seg_context + (mi_row & MAX_MIB_MASK), ctx->sl, - sizeof(xd->left_seg_context[0]) * mi_height); + memcpy(xd->above_partition_context + mi_col, ctx->sa, + sizeof(*xd->above_partition_context) * mi_width); + memcpy(xd->left_partition_context + (mi_row & MAX_MIB_MASK), ctx->sl, + sizeof(xd->left_partition_context[0]) * mi_height); xd->above_txfm_context = ctx->p_ta; xd->left_txfm_context = ctx->p_tl; memcpy(xd->above_txfm_context, ctx->ta, @@ -1512,10 +1528,6 @@ static AOM_INLINE void save_context(const MACROBLOCK *x, const int num_planes) { const MACROBLOCKD *xd = &x->e_mbd; int p; - const int num_4x4_blocks_wide = - block_size_wide[bsize] >> tx_size_wide_log2[0]; - const int num_4x4_blocks_high = - block_size_high[bsize] >> tx_size_high_log2[0]; int mi_width = mi_size_wide[bsize]; int mi_height = mi_size_high[bsize]; @@ -1523,19 +1535,18 @@ static AOM_INLINE void save_context(const MACROBLOCK *x, for (p = 0; p < num_planes; ++p) { int tx_col = mi_col; int tx_row = mi_row & MAX_MIB_MASK; - memcpy(ctx->a + num_4x4_blocks_wide * p, - xd->above_context[p] + (tx_col >> xd->plane[p].subsampling_x), - (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> - xd->plane[p].subsampling_x); - memcpy(ctx->l + num_4x4_blocks_high * p, - xd->left_context[p] + (tx_row >> xd->plane[p].subsampling_y), - (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >> - xd->plane[p].subsampling_y); + memcpy( + ctx->a + mi_width * p, + xd->above_entropy_context[p] + (tx_col >> xd->plane[p].subsampling_x), + (sizeof(ENTROPY_CONTEXT) * mi_width) >> xd->plane[p].subsampling_x); + memcpy(ctx->l + mi_height * p, + xd->left_entropy_context[p] + (tx_row >> xd->plane[p].subsampling_y), + (sizeof(ENTROPY_CONTEXT) * mi_height) >> xd->plane[p].subsampling_y); } - memcpy(ctx->sa, xd->above_seg_context + mi_col, - sizeof(*xd->above_seg_context) * mi_width); - memcpy(ctx->sl, xd->left_seg_context + (mi_row & MAX_MIB_MASK), - sizeof(xd->left_seg_context[0]) * mi_height); + memcpy(ctx->sa, xd->above_partition_context + mi_col, + sizeof(*xd->above_partition_context) * mi_width); + memcpy(ctx->sl, xd->left_partition_context + (mi_row & MAX_MIB_MASK), + sizeof(xd->left_partition_context[0]) * mi_height); memcpy(ctx->ta, xd->above_txfm_context, sizeof(*xd->above_txfm_context) * mi_width); memcpy(ctx->tl, xd->left_txfm_context, @@ -1567,8 +1578,7 @@ static AOM_INLINE void encode_b(const AV1_COMP *const cpi, (1 << num_pels_log2_lookup[cpi->common.seq_params.sb_size])); } - encode_superblock(cpi, tile_data, td, tp, dry_run, mi_row, mi_col, bsize, - rate); + encode_superblock(cpi, tile_data, td, tp, dry_run, bsize, rate); if (!dry_run) { const AV1_COMMON *const cm = &cpi->common; @@ -1640,30 +1650,41 @@ static AOM_INLINE void encode_b(const AV1_COMP *const cpi, } } - if (tile_data->allow_update_cdf) { - update_stats(&cpi->common, td, mi_row, mi_col); - } + if (tile_data->allow_update_cdf) update_stats(&cpi->common, td); - // Gather obmc count to update the probability. - if (cpi->sf.prune_obmc_using_stats) { + // Gather obmc and warped motion count to update the probability. + if ((!cpi->sf.inter_sf.disable_obmc && + cpi->sf.inter_sf.prune_obmc_prob_thresh > 0) || + (cm->features.allow_warped_motion && + cpi->sf.inter_sf.prune_warped_prob_thresh > 0)) { const int inter_block = is_inter_block(mbmi); const int seg_ref_active = segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME); if (!seg_ref_active && inter_block) { const MOTION_MODE motion_allowed = - cm->switchable_motion_mode + cm->features.switchable_motion_mode ? motion_mode_allowed(xd->global_motion, xd, mbmi, - cm->allow_warped_motion) + cm->features.allow_warped_motion) : SIMPLE_TRANSLATION; - if (mbmi->ref_frame[1] != INTRA_FRAME && - motion_allowed == OBMC_CAUSAL) { - td->rd_counts.obmc_used[bsize][mbmi->motion_mode == OBMC_CAUSAL]++; + + if (mbmi->ref_frame[1] != INTRA_FRAME) { + if (motion_allowed >= OBMC_CAUSAL) { + td->rd_counts.obmc_used[bsize][mbmi->motion_mode == OBMC_CAUSAL]++; + } + if (motion_allowed == WARPED_CAUSAL) { + td->rd_counts.warped_used[mbmi->motion_mode == WARPED_CAUSAL]++; + } } } } } // TODO(Ravi/Remya): Move this copy function to a better logical place - copy_winner_ref_mode_from_mbmi_ext(x); + // This function will copy the best mode information from block + // level (x->mbmi_ext) to frame level (cpi->mbmi_ext_info.frame_base). This + // frame level buffer (cpi->mbmi_ext_info.frame_base) will be used during + // bitstream preparation. + av1_copy_mbmi_ext_to_mbmi_ext_frame(x->mbmi_ext_frame, x->mbmi_ext, + av1_ref_frame_type(xd->mi[0]->ref_frame)); x->rdmult = origin_mult; } @@ -1674,6 +1695,7 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, int *rate) { assert(bsize < BLOCK_SIZES_ALL); const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; MACROBLOCK *const x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; assert(bsize < BLOCK_SIZES_ALL); @@ -1688,11 +1710,11 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, int i; BLOCK_SIZE bsize2 = get_partition_subsize(bsize, PARTITION_SPLIT); - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; if (!dry_run && ctx >= 0) { - const int has_rows = (mi_row + hbs) < cm->mi_rows; - const int has_cols = (mi_col + hbs) < cm->mi_cols; + const int has_rows = (mi_row + hbs) < mi_params->mi_rows; + const int has_cols = (mi_col + hbs) < mi_params->mi_cols; if (has_rows && has_cols) { #if CONFIG_ENTROPY_STATS @@ -1715,7 +1737,7 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, case PARTITION_VERT: encode_b(cpi, tile_data, td, tp, mi_row, mi_col, dry_run, subsize, partition, &pc_tree->vertical[0], rate); - if (mi_col + hbs < cm->mi_cols) { + if (mi_col + hbs < mi_params->mi_cols) { encode_b(cpi, tile_data, td, tp, mi_row, mi_col + hbs, dry_run, subsize, partition, &pc_tree->vertical[1], rate); } @@ -1723,7 +1745,7 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, case PARTITION_HORZ: encode_b(cpi, tile_data, td, tp, mi_row, mi_col, dry_run, subsize, partition, &pc_tree->horizontal[0], rate); - if (mi_row + hbs < cm->mi_rows) { + if (mi_row + hbs < mi_params->mi_rows) { encode_b(cpi, tile_data, td, tp, mi_row + hbs, mi_col, dry_run, subsize, partition, &pc_tree->horizontal[1], rate); } @@ -1775,7 +1797,7 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, case PARTITION_HORZ_4: for (i = 0; i < 4; ++i) { int this_mi_row = mi_row + i * quarter_step; - if (i > 0 && this_mi_row >= cm->mi_rows) break; + if (i > 0 && this_mi_row >= mi_params->mi_rows) break; encode_b(cpi, tile_data, td, tp, this_mi_row, mi_col, dry_run, subsize, partition, &pc_tree->horizontal4[i], rate); @@ -1784,7 +1806,7 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, case PARTITION_VERT_4: for (i = 0; i < 4; ++i) { int this_mi_col = mi_col + i * quarter_step; - if (i > 0 && this_mi_col >= cm->mi_cols) break; + if (i > 0 && this_mi_col >= mi_params->mi_cols) break; encode_b(cpi, tile_data, td, tp, mi_row, this_mi_col, dry_run, subsize, partition, &pc_tree->vertical4[i], rate); } @@ -1795,7 +1817,6 @@ static AOM_INLINE void encode_sb(const AV1_COMP *const cpi, ThreadData *td, update_ext_partition_context(xd, mi_row, mi_col, subsize, bsize, partition); } -#if !CONFIG_REALTIME_ONLY static AOM_INLINE void set_partial_sb_partition( const AV1_COMMON *const cm, MB_MODE_INFO *mi, int bh_in, int bw_in, int mi_rows_remaining, int mi_cols_remaining, BLOCK_SIZE bsize, @@ -1805,9 +1826,10 @@ static AOM_INLINE void set_partial_sb_partition( for (r = 0; r < cm->seq_params.mib_size; r += bh) { int bw = bw_in; for (c = 0; c < cm->seq_params.mib_size; c += bw) { - const int index = r * cm->mi_stride + c; - mib[index] = mi + index; - mib[index]->sb_type = find_partition_size( + const int grid_index = get_mi_grid_idx(&cm->mi_params, r, c); + const int mi_index = get_alloc_mi_idx(&cm->mi_params, r, c); + mib[grid_index] = mi + mi_index; + mib[grid_index]->sb_type = find_partition_size( bsize, mi_rows_remaining - r, mi_cols_remaining - c, &bh, &bw); } } @@ -1823,26 +1845,27 @@ static AOM_INLINE void set_fixed_partitioning(AV1_COMP *cpi, MB_MODE_INFO **mib, int mi_row, int mi_col, BLOCK_SIZE bsize) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; const int mi_rows_remaining = tile->mi_row_end - mi_row; const int mi_cols_remaining = tile->mi_col_end - mi_col; - int block_row, block_col; MB_MODE_INFO *const mi_upper_left = - cm->mi + get_alloc_mi_idx(cm, mi_row, mi_col); + mi_params->mi_alloc + get_alloc_mi_idx(mi_params, mi_row, mi_col); int bh = mi_size_high[bsize]; int bw = mi_size_wide[bsize]; - assert(bsize >= cm->mi_alloc_bsize && - "Attempted to use bsize < cm->mi_alloc_bsize"); + assert(bsize >= mi_params->mi_alloc_bsize && + "Attempted to use bsize < mi_params->mi_alloc_bsize"); assert((mi_rows_remaining > 0) && (mi_cols_remaining > 0)); // Apply the requested partition size to the SB if it is all "in image" if ((mi_cols_remaining >= cm->seq_params.mib_size) && (mi_rows_remaining >= cm->seq_params.mib_size)) { - for (block_row = 0; block_row < cm->seq_params.mib_size; block_row += bh) { - for (block_col = 0; block_col < cm->seq_params.mib_size; + for (int block_row = 0; block_row < cm->seq_params.mib_size; + block_row += bh) { + for (int block_col = 0; block_col < cm->seq_params.mib_size; block_col += bw) { - const int grid_index = get_mi_grid_idx(cm, block_row, block_col); - const int mi_index = get_alloc_mi_idx(cm, block_row, block_col); + const int grid_index = get_mi_grid_idx(mi_params, block_row, block_col); + const int mi_index = get_alloc_mi_idx(mi_params, block_row, block_col); mib[grid_index] = mi_upper_left + mi_index; mib[grid_index]->sb_type = bsize; } @@ -1853,13 +1876,13 @@ static AOM_INLINE void set_fixed_partitioning(AV1_COMP *cpi, mi_cols_remaining, bsize, mib); } } -#endif // !CONFIG_REALTIME_ONLY static AOM_INLINE void rd_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 CommonModeInfoParams *const mi_params = &cm->mi_params; const int num_planes = av1_num_planes(cm); TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCK *const x = &td->mb; @@ -1879,10 +1902,9 @@ static AOM_INLINE void rd_use_partition( BLOCK_SIZE sub_subsize = BLOCK_4X4; int splits_below = 0; BLOCK_SIZE bs_type = mib[0]->sb_type; - int do_partition_search = 1; PICK_MODE_CONTEXT *ctx_none = &pc_tree->none; - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; assert(mi_size_wide[bsize] == mi_size_high[bsize]); @@ -1893,7 +1915,8 @@ static AOM_INLINE void rd_use_partition( pc_tree->partitioning = partition; - xd->above_txfm_context = cm->above_txfm_context[tile_info->tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[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); @@ -1907,16 +1930,18 @@ static AOM_INLINE void rd_use_partition( const int orig_rdmult = x->rdmult; setup_block_rdmult(cpi, x, mi_row, mi_col, bsize, NO_AQ, NULL); - if (do_partition_search && - cpi->sf.partition_search_type == SEARCH_PARTITION && - cpi->sf.adjust_partitioning_from_last_frame) { + if (cpi->sf.part_sf.partition_search_type == VAR_BASED_PARTITION && + (cpi->sf.part_sf.adjust_var_based_rd_partitioning == 2 || + (cpi->sf.part_sf.adjust_var_based_rd_partitioning == 1 && + cm->quant_params.base_qindex > 190 && bsize <= BLOCK_32X32 && + !frame_is_intra_only(cm)))) { // Check if any of the sub blocks are further split. if (partition == PARTITION_SPLIT && subsize > BLOCK_8X8) { sub_subsize = get_partition_subsize(subsize, PARTITION_SPLIT); splits_below = 1; for (i = 0; i < 4; i++) { int jj = i >> 1, ii = i & 0x01; - MB_MODE_INFO *this_mi = mib[jj * hbs * cm->mi_stride + ii * hbs]; + MB_MODE_INFO *this_mi = mib[jj * hbs * mi_params->mi_stride + ii * hbs]; if (this_mi && this_mi->sb_type >= sub_subsize) { splits_below = 0; } @@ -1926,7 +1951,8 @@ static AOM_INLINE void rd_use_partition( // If partition is not none try none unless each of the 4 splits are split // even further.. if (partition != PARTITION_NONE && !splits_below && - mi_row + hbs < cm->mi_rows && mi_col + hbs < cm->mi_cols) { + mi_row + hbs < mi_params->mi_rows && + mi_col + hbs < mi_params->mi_cols) { pc_tree->partitioning = PARTITION_NONE; pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc, PARTITION_NONE, bsize, ctx_none, invalid_rdc, PICK_MODE_RD); @@ -1952,13 +1978,13 @@ static AOM_INLINE void rd_use_partition( PARTITION_HORZ, subsize, &pc_tree->horizontal[0], invalid_rdc, PICK_MODE_RD); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && - mi_row + hbs < cm->mi_rows) { + mi_row + hbs < mi_params->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, 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); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, subsize, + NULL); pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &tmp_rdc, PARTITION_HORZ, subsize, &pc_tree->horizontal[1], invalid_rdc, PICK_MODE_RD); @@ -1976,13 +2002,13 @@ static AOM_INLINE void rd_use_partition( PARTITION_VERT, subsize, &pc_tree->vertical[0], invalid_rdc, PICK_MODE_RD); if (last_part_rdc.rate != INT_MAX && bsize >= BLOCK_8X8 && - mi_col + hbs < cm->mi_cols) { + mi_col + hbs < mi_params->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, 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); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, 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], invalid_rdc, @@ -1997,6 +2023,11 @@ static AOM_INLINE void rd_use_partition( } break; case PARTITION_SPLIT: + if (cpi->sf.part_sf.adjust_var_based_rd_partitioning == 1 && + none_rdc.rate < INT_MAX && none_rdc.skip == 1) { + av1_invalid_rd_stats(&last_part_rdc); + break; + } last_part_rdc.rate = 0; last_part_rdc.dist = 0; last_part_rdc.rdcost = 0; @@ -2005,12 +2036,13 @@ static AOM_INLINE void rd_use_partition( 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)) + if ((mi_row + y_idx >= mi_params->mi_rows) || + (mi_col + x_idx >= mi_params->mi_cols)) continue; av1_init_rd_stats(&tmp_rdc); rd_use_partition(cpi, td, tile_data, - mib + jj * hbs * cm->mi_stride + ii * hbs, tp, + mib + jj * hbs * mi_params->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) { @@ -2037,11 +2069,13 @@ static AOM_INLINE void rd_use_partition( RDCOST(x->rdmult, last_part_rdc.rate, last_part_rdc.dist); } - if (do_partition_search && cpi->sf.adjust_partitioning_from_last_frame && - cpi->sf.partition_search_type == SEARCH_PARTITION && + if ((cpi->sf.part_sf.partition_search_type == VAR_BASED_PARTITION && + cpi->sf.part_sf.adjust_var_based_rd_partitioning > 2) && partition != PARTITION_SPLIT && bsize > BLOCK_8X8 && - (mi_row + bs < cm->mi_rows || mi_row + hbs == cm->mi_rows) && - (mi_col + bs < cm->mi_cols || mi_col + hbs == cm->mi_cols)) { + (mi_row + bs < mi_params->mi_rows || + mi_row + hbs == mi_params->mi_rows) && + (mi_col + bs < mi_params->mi_cols || + mi_col + hbs == mi_params->mi_cols)) { BLOCK_SIZE split_subsize = get_partition_subsize(bsize, PARTITION_SPLIT); chosen_rdc.rate = 0; chosen_rdc.dist = 0; @@ -2055,7 +2089,8 @@ static AOM_INLINE void rd_use_partition( int y_idx = (i >> 1) * hbs; RD_STATS tmp_rdc; - if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols)) + if ((mi_row + y_idx >= mi_params->mi_rows) || + (mi_col + x_idx >= mi_params->mi_cols)) continue; save_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); @@ -2124,14 +2159,39 @@ static AOM_INLINE void rd_use_partition( x->rdmult = orig_rdmult; } +static int is_leaf_split_partition(AV1_COMMON *cm, int mi_row, int mi_col, + BLOCK_SIZE bsize) { + const int bs = mi_size_wide[bsize]; + const int hbs = bs / 2; + assert(bsize >= BLOCK_8X8); + const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT); + + for (int i = 0; i < 4; i++) { + int x_idx = (i & 1) * hbs; + int y_idx = (i >> 1) * hbs; + if ((mi_row + y_idx >= cm->mi_params.mi_rows) || + (mi_col + x_idx >= cm->mi_params.mi_cols)) + return 0; + if (get_partition(cm, mi_row + y_idx, mi_col + x_idx, subsize) != + PARTITION_NONE && + subsize != BLOCK_8X8) + return 0; + } + return 1; +} + +static AOM_INLINE int do_slipt_check(BLOCK_SIZE bsize) { + return (bsize == BLOCK_16X16 || bsize == BLOCK_32X32); +} + static AOM_INLINE 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, PC_TREE *pc_tree) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; TileInfo *const tile_info = &tile_data->tile_info; - const SPEED_FEATURES *const sf = &cpi->sf; MACROBLOCK *const x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; // Only square blocks from 8x8 to 128x128 are supported @@ -2141,44 +2201,110 @@ static AOM_INLINE void nonrd_use_partition(AV1_COMP *cpi, ThreadData *td, 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); + BLOCK_SIZE subsize = get_partition_subsize(bsize, partition); + assert(subsize <= BLOCK_LARGEST); + const int pl = (bsize >= BLOCK_8X8) + ? partition_plane_context(xd, mi_row, mi_col, bsize) + : 0; + RD_STATS dummy_cost; av1_invalid_rd_stats(&dummy_cost); RD_STATS invalid_rd; av1_invalid_rd_stats(&invalid_rd); - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; assert(mi_size_wide[bsize] == mi_size_high[bsize]); pc_tree->partitioning = partition; - xd->above_txfm_context = cm->above_txfm_context[tile_info->tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[tile_info->tile_row] + mi_col; xd->left_txfm_context = xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); switch (partition) { case PARTITION_NONE: - pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &dummy_cost, - PARTITION_NONE, bsize, &pc_tree->none, invalid_rd, - sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD - : PICK_MODE_NONRD); - encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, bsize, partition, - &pc_tree->none, NULL); + if (cpi->sf.rt_sf.nonrd_check_partition_split && do_slipt_check(bsize) && + !frame_is_intra_only(cm)) { + RD_STATS split_rdc, none_rdc, block_rdc; + RD_SEARCH_MACROBLOCK_CONTEXT x_ctx; + + av1_init_rd_stats(&split_rdc); + av1_invalid_rd_stats(&none_rdc); + + save_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + subsize = get_partition_subsize(bsize, PARTITION_SPLIT); + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc, + PARTITION_NONE, bsize, &pc_tree->none, invalid_rd, + PICK_MODE_NONRD); + none_rdc.rate += x->partition_cost[pl][PARTITION_NONE]; + none_rdc.rdcost = RDCOST(x->rdmult, none_rdc.rate, none_rdc.dist); + restore_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + + for (int i = 0; i < 4; i++) { + av1_invalid_rd_stats(&block_rdc); + const int x_idx = (i & 1) * hbs; + const int y_idx = (i >> 1) * hbs; + if (mi_row + y_idx >= mi_params->mi_rows || + mi_col + x_idx >= mi_params->mi_cols) + continue; + xd->above_txfm_context = + cm->above_contexts.txfm[tile_info->tile_row] + mi_col + x_idx; + xd->left_txfm_context = + xd->left_txfm_context_buffer + ((mi_row + y_idx) & MAX_MIB_MASK); + pc_tree->split[i]->partitioning = PARTITION_NONE; + pick_sb_modes(cpi, tile_data, x, mi_row + y_idx, mi_col + x_idx, + &block_rdc, PARTITION_NONE, subsize, + &pc_tree->split[i]->none, invalid_rd, PICK_MODE_NONRD); + split_rdc.rate += block_rdc.rate; + split_rdc.dist += block_rdc.dist; + + encode_b(cpi, tile_data, td, tp, mi_row + y_idx, mi_col + x_idx, 1, + subsize, PARTITION_NONE, &pc_tree->split[i]->none, NULL); + } + split_rdc.rate += x->partition_cost[pl][PARTITION_SPLIT]; + split_rdc.rdcost = RDCOST(x->rdmult, split_rdc.rate, split_rdc.dist); + restore_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + + if (none_rdc.rdcost < split_rdc.rdcost) { + mib[0]->sb_type = bsize; + pc_tree->partitioning = PARTITION_NONE; + encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, bsize, partition, + &pc_tree->none, NULL); + } else { + mib[0]->sb_type = subsize; + pc_tree->partitioning = PARTITION_SPLIT; + for (int i = 0; i < 4; i++) { + const int x_idx = (i & 1) * hbs; + const int y_idx = (i >> 1) * hbs; + if (mi_row + y_idx >= mi_params->mi_rows || + mi_col + x_idx >= mi_params->mi_cols) + continue; + + encode_b(cpi, tile_data, td, tp, mi_row + y_idx, mi_col + x_idx, 0, + subsize, PARTITION_NONE, &pc_tree->split[i]->none, NULL); + } + } + + } else { + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &dummy_cost, + PARTITION_NONE, bsize, &pc_tree->none, invalid_rd, + PICK_MODE_NONRD); + encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, bsize, partition, + &pc_tree->none, NULL); + } break; case PARTITION_VERT: pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &dummy_cost, PARTITION_VERT, subsize, &pc_tree->vertical[0], invalid_rd, - sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD - : PICK_MODE_NONRD); + PICK_MODE_NONRD); encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, subsize, PARTITION_VERT, &pc_tree->vertical[0], NULL); - if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) { + if (mi_col + hbs < mi_params->mi_cols && bsize > BLOCK_8X8) { pick_sb_modes(cpi, tile_data, x, mi_row, mi_col + hbs, &dummy_cost, PARTITION_VERT, subsize, &pc_tree->vertical[1], - invalid_rd, - sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD - : PICK_MODE_NONRD); + invalid_rd, PICK_MODE_NONRD); encode_b(cpi, tile_data, td, tp, mi_row, mi_col + hbs, 0, subsize, PARTITION_VERT, &pc_tree->vertical[1], NULL); } @@ -2186,32 +2312,100 @@ static AOM_INLINE void nonrd_use_partition(AV1_COMP *cpi, ThreadData *td, case PARTITION_HORZ: pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &dummy_cost, PARTITION_HORZ, subsize, &pc_tree->horizontal[0], - invalid_rd, - sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD - : PICK_MODE_NONRD); + invalid_rd, PICK_MODE_NONRD); encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, subsize, PARTITION_HORZ, &pc_tree->horizontal[0], NULL); - if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) { + if (mi_row + hbs < mi_params->mi_rows && bsize > BLOCK_8X8) { pick_sb_modes(cpi, tile_data, x, mi_row + hbs, mi_col, &dummy_cost, PARTITION_HORZ, subsize, &pc_tree->horizontal[1], - invalid_rd, - sf->use_fast_nonrd_pick_mode ? PICK_MODE_FAST_NONRD - : PICK_MODE_NONRD); + invalid_rd, PICK_MODE_NONRD); encode_b(cpi, tile_data, td, tp, mi_row + hbs, mi_col, 0, subsize, PARTITION_HORZ, &pc_tree->horizontal[1], NULL); } break; case PARTITION_SPLIT: - for (int i = 0; i < 4; i++) { - int x_idx = (i & 1) * hbs; - int y_idx = (i >> 1) * hbs; - int jj = i >> 1, ii = i & 0x01; - if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols)) - continue; - 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, pc_tree->split[i]); + if (cpi->sf.rt_sf.nonrd_check_partition_merge_mode && + is_leaf_split_partition(cm, mi_row, mi_col, bsize) && + !frame_is_intra_only(cm) && bsize <= BLOCK_32X32) { + RD_SEARCH_MACROBLOCK_CONTEXT x_ctx; + RD_STATS split_rdc, none_rdc; + av1_invalid_rd_stats(&split_rdc); + av1_invalid_rd_stats(&none_rdc); + save_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + xd->above_txfm_context = + cm->above_contexts.txfm[tile_info->tile_row] + mi_col; + xd->left_txfm_context = + xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + pc_tree->partitioning = PARTITION_NONE; + pick_sb_modes(cpi, tile_data, x, mi_row, mi_col, &none_rdc, + PARTITION_NONE, bsize, &pc_tree->none, invalid_rd, + PICK_MODE_NONRD); + none_rdc.rate += x->partition_cost[pl][PARTITION_NONE]; + none_rdc.rdcost = RDCOST(x->rdmult, none_rdc.rate, none_rdc.dist); + restore_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + if (cpi->sf.rt_sf.nonrd_check_partition_merge_mode != 2 || + none_rdc.skip != 1 || pc_tree->none.mic.mode == NEWMV) { + av1_init_rd_stats(&split_rdc); + for (int i = 0; i < 4; i++) { + RD_STATS block_rdc; + av1_invalid_rd_stats(&block_rdc); + int x_idx = (i & 1) * hbs; + int y_idx = (i >> 1) * hbs; + if ((mi_row + y_idx >= mi_params->mi_rows) || + (mi_col + x_idx >= mi_params->mi_cols)) + continue; + xd->above_txfm_context = + cm->above_contexts.txfm[tile_info->tile_row] + mi_col + x_idx; + xd->left_txfm_context = xd->left_txfm_context_buffer + + ((mi_row + y_idx) & MAX_MIB_MASK); + pc_tree->split[i]->partitioning = PARTITION_NONE; + pick_sb_modes(cpi, tile_data, x, mi_row + y_idx, mi_col + x_idx, + &block_rdc, PARTITION_NONE, subsize, + &pc_tree->split[i]->none, invalid_rd, + PICK_MODE_NONRD); + split_rdc.rate += block_rdc.rate; + split_rdc.dist += block_rdc.dist; + + encode_b(cpi, tile_data, td, tp, mi_row + y_idx, mi_col + x_idx, 1, + subsize, PARTITION_NONE, &pc_tree->split[i]->none, NULL); + } + restore_context(x, &x_ctx, mi_row, mi_col, bsize, 3); + split_rdc.rate += x->partition_cost[pl][PARTITION_SPLIT]; + split_rdc.rdcost = RDCOST(x->rdmult, split_rdc.rate, split_rdc.dist); + } + if (none_rdc.rdcost < split_rdc.rdcost) { + mib[0]->sb_type = bsize; + pc_tree->partitioning = PARTITION_NONE; + encode_b(cpi, tile_data, td, tp, mi_row, mi_col, 0, bsize, partition, + &pc_tree->none, NULL); + } else { + mib[0]->sb_type = subsize; + pc_tree->partitioning = PARTITION_SPLIT; + for (int i = 0; i < 4; i++) { + int x_idx = (i & 1) * hbs; + int y_idx = (i >> 1) * hbs; + if ((mi_row + y_idx >= mi_params->mi_rows) || + (mi_col + x_idx >= mi_params->mi_cols)) + continue; + + encode_b(cpi, tile_data, td, tp, mi_row + y_idx, mi_col + x_idx, 0, + subsize, PARTITION_NONE, &pc_tree->split[i]->none, NULL); + } + } + } else { + for (int i = 0; i < 4; i++) { + int x_idx = (i & 1) * hbs; + int y_idx = (i >> 1) * hbs; + int jj = i >> 1, ii = i & 0x01; + if ((mi_row + y_idx >= mi_params->mi_rows) || + (mi_col + x_idx >= mi_params->mi_cols)) + continue; + nonrd_use_partition(cpi, td, tile_data, + mib + jj * hbs * mi_params->mi_stride + ii * hbs, + tp, mi_row + y_idx, mi_col + x_idx, subsize, + pc_tree->split[i]); + } } break; case PARTITION_VERT_A: @@ -2223,29 +2417,28 @@ static AOM_INLINE void nonrd_use_partition(AV1_COMP *cpi, ThreadData *td, assert(0 && "Cannot handle extended partition types"); default: assert(0); break; } - if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) - update_partition_context(xd, mi_row, mi_col, subsize, bsize); } #if !CONFIG_REALTIME_ONLY static const FIRSTPASS_STATS *read_one_frame_stats(const TWO_PASS *p, int frm) { assert(frm >= 0); - if (frm < 0 || p->stats_in_start + frm > p->stats_in_end) { + if (frm < 0 || + p->stats_buf_ctx->stats_in_start + frm > p->stats_buf_ctx->stats_in_end) { return NULL; } - return &p->stats_in_start[frm]; + return &p->stats_buf_ctx->stats_in_start[frm]; } // Checks to see if a super block is on a horizontal image edge. // In most cases this is the "real" edge unless there are formatting // bars embedded in the stream. static int active_h_edge(const AV1_COMP *cpi, int mi_row, int mi_step) { int top_edge = 0; - int bottom_edge = cpi->common.mi_rows; + int bottom_edge = cpi->common.mi_params.mi_rows; int is_active_h_edge = 0; // For two pass account for any formatting bars detected. - if (cpi->oxcf.pass == 2) { + if (is_stat_consumption_stage_twopass(cpi)) { const AV1_COMMON *const cm = &cpi->common; const FIRSTPASS_STATS *const this_frame_stats = read_one_frame_stats( &cpi->twopass, cm->current_frame.display_order_hint); @@ -2271,11 +2464,11 @@ static int active_h_edge(const AV1_COMP *cpi, int mi_row, int mi_step) { // bars embedded in the stream. static int active_v_edge(const AV1_COMP *cpi, int mi_col, int mi_step) { int left_edge = 0; - int right_edge = cpi->common.mi_cols; + int right_edge = cpi->common.mi_params.mi_cols; int is_active_v_edge = 0; // For two pass account for any formatting bars detected. - if (cpi->oxcf.pass == 2) { + if (is_stat_consumption_stage_twopass(cpi)) { const AV1_COMMON *const cm = &cpi->common; const FIRSTPASS_STATS *const this_frame_stats = read_one_frame_stats( &cpi->twopass, cm->current_frame.display_order_hint); @@ -2322,7 +2515,7 @@ static int rd_try_subblock(AV1_COMP *const cpi, ThreadData *td, setup_block_rdmult(cpi, x, mi_row, mi_col, subsize, NO_AQ, NULL); av1_rd_cost_update(x->rdmult, &best_rdcost); - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, prev_ctx); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, prev_ctx); RD_STATS rdcost_remaining; av1_rd_stats_subtraction(x->rdmult, &best_rdcost, sum_rdc, &rdcost_remaining); @@ -2345,8 +2538,7 @@ static int rd_try_subblock(AV1_COMP *const cpi, ThreadData *td, if (!is_last) { update_state(cpi, td, this_ctx, mi_row, mi_col, subsize, 1); - encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, mi_col, - subsize, NULL); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, subsize, NULL); } x->rdmult = orig_mult; @@ -2420,16 +2612,75 @@ static AOM_INLINE void update_picked_ref_frames_mask(MACROBLOCK *const x, } } -// 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. +// Structure to keep win flags for HORZ and VERT partition evaluations +typedef struct { + bool horz_win; + bool vert_win; +} RD_RECT_PART_WIN_INFO; + +// Decide whether to evaluate the AB partition specified by part_type based on +// split and HORZ/VERT info +int evaluate_ab_partition_based_on_split( + PC_TREE *pc_tree, PARTITION_TYPE rect_part, + RD_RECT_PART_WIN_INFO *rect_part_win_info, int qindex, int split_idx1, + int split_idx2) { + int num_win = 0; + // Threshold for number of winners + // Conservative pruning for high quantizers + const int num_win_thresh = AOMMIN(3 * (2 * (MAXQ - qindex) / MAXQ), 3); + bool sub_part_win = (rect_part_win_info == NULL) + ? (pc_tree->partitioning == rect_part) + : (rect_part == PARTITION_HORZ) + ? rect_part_win_info->horz_win + : rect_part_win_info->vert_win; + num_win += (sub_part_win) ? 1 : 0; + num_win += + (pc_tree->split[split_idx1]->partitioning == PARTITION_NONE) ? 1 : 0; + num_win += + (pc_tree->split[split_idx2]->partitioning == PARTITION_NONE) ? 1 : 0; + if (num_win < num_win_thresh) { + return 0; + } + return 1; +} + +// Searches for the best partition pattern for a block based on the +// rate-distortion cost, and returns a bool value to indicate whether a valid +// partition pattern is found. The partition can recursively go down to +// the smallest block size. +// +// Inputs: +// cpi: the global compressor setting +// td: thread data +// tile_data: tile data +// tp: the pointer to the start token +// mi_row: row coordinate of the block in a step size of MI_SIZE +// mi_col: column coordinate of the block in a step size of MI_SIZE +// bsize: block size +// max_sq_part: the largest square block size for prediction blocks +// min_sq_part: the smallest square block size for prediction blocks +// rd_cost: the pointer to the final rd cost of the current block +// best_rdc: the upper bound of rd cost for a valid partition +// pc_tree: the pointer to the PC_TREE node storing the picked partitions +// and mode info for the current block +// none_rd: the pointer to the rd cost in the case of not splitting the +// current block +// multi_pass_mode: SB_SINGLE_PASS/SB_DRY_PASS/SB_WET_PASS +// rect_part_win_info: the pointer to a struct storing whether horz/vert +// partition outperforms previously tested partitions +// +// Output: +// a bool value indicating whether a valid partition is found static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, TileDataEnc *tile_data, TOKENEXTRA **tp, int mi_row, int mi_col, BLOCK_SIZE bsize, BLOCK_SIZE max_sq_part, BLOCK_SIZE min_sq_part, RD_STATS *rd_cost, RD_STATS best_rdc, - PC_TREE *pc_tree, int64_t *none_rd) { + PC_TREE *pc_tree, int64_t *none_rd, + SB_MULTI_PASS_MODE multi_pass_mode, + RD_RECT_PART_WIN_INFO *rect_part_win_info) { const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; const int num_planes = av1_num_planes(cm); TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCK *const x = &td->mb; @@ -2461,6 +2712,10 @@ static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, int horz_ctx_is_ready = 0; int vert_ctx_is_ready = 0; BLOCK_SIZE bsize2 = get_partition_subsize(bsize, PARTITION_SPLIT); + // Initialise HORZ and VERT win flags as true for all split partitions + RD_RECT_PART_WIN_INFO split_part_rect_win[4] = { + { true, true }, { true, true }, { true, true }, { true, true } + }; bool found_best_partition = false; if (best_rdc.rdcost < 0) { @@ -2476,8 +2731,8 @@ static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, if (bsize == cm->seq_params.sb_size) x->must_find_valid_partition = 0; // Override skipping rectangular partition operations for edge blocks - const int has_rows = (mi_row + mi_step < cm->mi_rows); - const int has_cols = (mi_col + mi_step < cm->mi_cols); + const int has_rows = (mi_row + mi_step < mi_params->mi_rows); + const int has_cols = (mi_col + mi_step < mi_params->mi_cols); const int xss = x->e_mbd.plane[1].subsampling_x; const int yss = x->e_mbd.plane[1].subsampling_y; @@ -2556,21 +2811,24 @@ static bool 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 (bsize > cpi->sf.use_square_partition_only_threshold) { + if (bsize > cpi->sf.part_sf.use_square_partition_only_threshold) { partition_horz_allowed &= !has_rows; partition_vert_allowed &= !has_cols; } - xd->above_txfm_context = cm->above_txfm_context[tile_info->tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[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); const int try_intra_cnn_split = - frame_is_intra_only(cm) && cpi->sf.intra_cnn_split && + !cpi->is_screen_content_type && frame_is_intra_only(cm) && + cpi->sf.part_sf.intra_cnn_split && cm->seq_params.sb_size >= BLOCK_64X64 && bsize <= BLOCK_64X64 && - bsize >= BLOCK_8X8 && mi_row + mi_size_high[bsize] <= cm->mi_rows && - mi_col + mi_size_wide[bsize] <= cm->mi_cols; + bsize >= BLOCK_8X8 && + mi_row + mi_size_high[bsize] <= mi_params->mi_rows && + mi_col + mi_size_wide[bsize] <= mi_params->mi_cols; if (try_intra_cnn_split) { av1_intra_mode_cnn_partition( @@ -2582,10 +2840,12 @@ static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, // 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 = - cpi->sf.simple_motion_search_split && do_square_split && - bsize >= BLOCK_8X8 && mi_row + mi_size_high[bsize] <= cm->mi_rows && - mi_col + mi_size_wide[bsize] <= cm->mi_cols && !frame_is_intra_only(cm) && - !av1_superres_scaled(cm); + !cpi->is_screen_content_type && + cpi->sf.part_sf.simple_motion_search_split && do_square_split && + bsize >= BLOCK_8X8 && + mi_row + mi_size_high[bsize] <= mi_params->mi_rows && + mi_col + mi_size_wide[bsize] <= mi_params->mi_cols && + !frame_is_intra_only(cm) && !av1_superres_scaled(cm); if (try_split_only) { av1_simple_motion_search_based_split( @@ -2595,8 +2855,9 @@ static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, } const int try_prune_rect = - cpi->sf.simple_motion_search_prune_rect && !frame_is_intra_only(cm) && - do_rectangular_split && + !cpi->is_screen_content_type && + cpi->sf.part_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; @@ -2640,14 +2901,17 @@ static bool rd_pick_partition(AV1_COMP *const cpi, ThreadData *td, BEGIN_PARTITION_SEARCH: if (x->must_find_valid_partition) { - do_square_split = bsize_at_least_8x8; - partition_none_allowed = has_rows && has_cols; + do_square_split = bsize_at_least_8x8 && (blksize > min_partition_size); + partition_none_allowed = + has_rows && has_cols && (blksize >= min_partition_size); partition_horz_allowed = has_cols && bsize_at_least_8x8 && cpi->oxcf.enable_rect_partitions && + (blksize > min_partition_size) && get_plane_block_size(get_partition_subsize(bsize, PARTITION_HORZ), xss, yss) != BLOCK_INVALID; partition_vert_allowed = has_rows && bsize_at_least_8x8 && cpi->oxcf.enable_rect_partitions && + (blksize > min_partition_size) && get_plane_block_size(get_partition_subsize(bsize, PARTITION_VERT), xss, yss) != BLOCK_INVALID; terminate_partition_search = 0; @@ -2661,20 +2925,13 @@ BEGIN_PARTITION_SEARCH: 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; - if (block_size_wide[bsize] <= 8) partition_vert_allowed = 0; - if (block_size_high[bsize] <= 8 || block_size_wide[bsize] <= 8) - do_square_split = 0; - } -#endif - // PARTITION_NONE if (is_le_min_sq_part && has_rows && has_cols) partition_none_allowed = 1; + assert(terminate_partition_search == 0); int64_t part_none_rd = INT64_MAX; - if (!terminate_partition_search && partition_none_allowed && - !is_gt_max_sq_part) { + if (cpi->is_screen_content_type) + partition_none_allowed = has_rows && has_cols; + if (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 @@ -2711,7 +2968,7 @@ BEGIN_PARTITION_SEARCH: 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) { + if (cpi->sf.inter_sf.prune_ref_frame_for_rect_partitions) { const int ref_type = av1_ref_frame_type(ctx_none->mic.ref_frame); update_picked_ref_frames_mask(x, ref_type, bsize, cm->seq_params.mib_size, mi_row, mi_col); @@ -2725,11 +2982,11 @@ BEGIN_PARTITION_SEARCH: if (this_rdc.rdcost < best_rdc.rdcost) { // Adjust dist breakout threshold according to the partition size. const int64_t dist_breakout_thr = - cpi->sf.partition_search_breakout_dist_thr >> + cpi->sf.part_sf.partition_search_breakout_dist_thr >> ((2 * (MAX_SB_SIZE_LOG2 - 2)) - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize])); const int rate_breakout_thr = - cpi->sf.partition_search_breakout_rate_thr * + cpi->sf.part_sf.partition_search_breakout_rate_thr * num_pels_log2_lookup[bsize]; best_rdc = this_rdc; @@ -2740,7 +2997,7 @@ BEGIN_PARTITION_SEARCH: (do_square_split || do_rectangular_split) && !x->e_mbd.lossless[xd->mi[0]->segment_id] && ctx_none->skippable) { const int use_ml_based_breakout = - bsize <= cpi->sf.use_square_partition_only_threshold && + bsize <= cpi->sf.part_sf.use_square_partition_only_threshold && bsize > BLOCK_4X4 && xd->bd == 8; if (use_ml_based_breakout) { if (av1_ml_predict_breakout(cpi, bsize, x, &this_rdc, @@ -2762,9 +3019,10 @@ BEGIN_PARTITION_SEARCH: } } - 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 && + if (cpi->sf.part_sf.simple_motion_search_early_term_none && + cm->show_frame && !frame_is_intra_only(cm) && + bsize >= BLOCK_16X16 && mi_row + mi_step < mi_params->mi_rows && + mi_col + mi_step < mi_params->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)) { @@ -2779,7 +3037,7 @@ BEGIN_PARTITION_SEARCH: } // store estimated motion vector - if (cpi->sf.adaptive_motion_search) store_pred_mv(x, ctx_none); + if (cpi->sf.mv_sf.adaptive_motion_search) store_pred_mv(x, ctx_none); // PARTITION_SPLIT int64_t part_split_rd = INT64_MAX; @@ -2801,10 +3059,11 @@ BEGIN_PARTITION_SEARCH: const int x_idx = (idx & 1) * mi_step; const int y_idx = (idx >> 1) * mi_step; - if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols) + if (mi_row + y_idx >= mi_params->mi_rows || + mi_col + x_idx >= mi_params->mi_cols) continue; - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx_none); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, ctx_none); pc_tree->split[idx]->index = idx; int64_t *p_split_rd = &split_rd[idx]; @@ -2821,7 +3080,8 @@ BEGIN_PARTITION_SEARCH: if (!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)) { + p_split_rd, multi_pass_mode, + &split_part_rect_win[idx])) { av1_invalid_rd_stats(&sum_rdc); break; } @@ -2860,10 +3120,10 @@ BEGIN_PARTITION_SEARCH: found_best_partition = true; pc_tree->partitioning = PARTITION_SPLIT; } - } else if (cpi->sf.less_rectangular_check_level > 0) { + } else if (cpi->sf.part_sf.less_rectangular_check_level > 0) { // Skip rectangular partition test when partition type none gives better // rd than partition type split. - if (cpi->sf.less_rectangular_check_level == 2 || idx <= 2) { + if (cpi->sf.part_sf.less_rectangular_check_level == 2 || idx <= 2) { const int partition_none_valid = cur_none_rd > 0; const int partition_none_better = cur_none_rd < sum_rdc.rdcost; do_rectangular_split &= @@ -2874,7 +3134,7 @@ BEGIN_PARTITION_SEARCH: restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } // if (do_split) - if (cpi->sf.ml_early_term_after_part_split_level && + if (cpi->sf.part_sf.ml_early_term_after_part_split_level && !frame_is_intra_only(cm) && !terminate_partition_search && do_rectangular_split && (partition_horz_allowed || partition_vert_allowed)) { @@ -2883,8 +3143,8 @@ BEGIN_PARTITION_SEARCH: mi_col, &terminate_partition_search); } - if (!cpi->sf.ml_early_term_after_part_split_level && - cpi->sf.ml_prune_rect_partition && !frame_is_intra_only(cm) && + if (!cpi->sf.part_sf.ml_early_term_after_part_split_level && + cpi->sf.part_sf.ml_prune_rect_partition && !frame_is_intra_only(cm) && (partition_horz_allowed || partition_vert_allowed) && !(prune_horz || prune_vert) && !terminate_partition_search) { av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, bsize); @@ -2899,7 +3159,7 @@ BEGIN_PARTITION_SEARCH: !is_gt_max_sq_part) { av1_init_rd_stats(&sum_rdc); subsize = get_partition_subsize(bsize, PARTITION_HORZ); - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx_none); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, ctx_none); sum_rdc.rate = partition_cost[PARTITION_HORZ]; sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, 0); RD_STATS best_remain_rdcost; @@ -2935,10 +3195,9 @@ BEGIN_PARTITION_SEARCH: if (mbmi->uv_mode != UV_CFL_PRED) horz_ctx_is_ready = 1; } update_state(cpi, 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); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, subsize, NULL); - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx_h); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, ctx_h); av1_rd_stats_subtraction(x->rdmult, &best_rdc, &sum_rdc, &best_remain_rdcost); @@ -2973,6 +3232,11 @@ BEGIN_PARTITION_SEARCH: found_best_partition = true; pc_tree->partitioning = PARTITION_HORZ; } + } else { + // Update HORZ win flag + if (rect_part_win_info != NULL) { + rect_part_win_info->horz_win = false; + } } restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); @@ -2986,7 +3250,7 @@ BEGIN_PARTITION_SEARCH: av1_init_rd_stats(&sum_rdc); subsize = get_partition_subsize(bsize, PARTITION_VERT); - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx_none); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, ctx_none); sum_rdc.rate = partition_cost[PARTITION_VERT]; sum_rdc.rdcost = RDCOST(x->rdmult, sum_rdc.rate, 0); @@ -3021,10 +3285,9 @@ BEGIN_PARTITION_SEARCH: if (mbmi->uv_mode != UV_CFL_PRED) vert_ctx_is_ready = 1; } update_state(cpi, td, &pc_tree->vertical[0], mi_row, mi_col, subsize, 1); - encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, mi_row, mi_col, - subsize, NULL); + encode_superblock(cpi, tile_data, td, tp, DRY_RUN_NORMAL, subsize, NULL); - if (cpi->sf.adaptive_motion_search) load_pred_mv(x, ctx_none); + if (cpi->sf.mv_sf.adaptive_motion_search) load_pred_mv(x, ctx_none); av1_rd_stats_subtraction(x->rdmult, &best_rdc, &sum_rdc, &best_remain_rdcost); @@ -3056,6 +3319,11 @@ BEGIN_PARTITION_SEARCH: best_rdc = sum_rdc; found_best_partition = true; pc_tree->partitioning = PARTITION_VERT; + } else { + // Update VERT win flag + if (rect_part_win_info != NULL) { + rect_part_win_info->vert_win = false; + } } restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); @@ -3074,17 +3342,18 @@ 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 }; + const FULLPEL_MV start_mv = kZeroFullMv; unsigned int var = 0; - av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full, 0, + av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, start_mv, 0, &pb_simple_motion_pred_sse, &var); } assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !do_rectangular_split)); const int ext_partition_allowed = - do_rectangular_split && bsize > BLOCK_8X8 && has_rows && has_cols; + do_rectangular_split && + bsize > cpi->sf.part_sf.ext_partition_eval_thresh && has_rows && has_cols; // The standard AB partitions are allowed whenever ext-partition-types are // allowed @@ -3093,17 +3362,8 @@ BEGIN_PARTITION_SEARCH: int vertab_partition_allowed = ext_partition_allowed & cpi->oxcf.enable_ab_partitions; -#if CONFIG_DIST_8X8 - if (x->using_dist_8x8) { - if (block_size_high[bsize] <= 8 || block_size_wide[bsize] <= 8) { - horzab_partition_allowed = 0; - vertab_partition_allowed = 0; - } - } -#endif - - if (cpi->sf.prune_ext_partition_types_search_level) { - if (cpi->sf.prune_ext_partition_types_search_level == 1) { + if (cpi->sf.part_sf.prune_ext_partition_types_search_level) { + if (cpi->sf.part_sf.prune_ext_partition_types_search_level == 1) { // TODO(debargha,huisu@google.com): may need to tune the threshold for // pb_source_variance. horzab_partition_allowed &= (pc_tree->partitioning == PARTITION_HORZ || @@ -3131,10 +3391,10 @@ BEGIN_PARTITION_SEARCH: } int horza_partition_allowed = horzab_partition_allowed; int horzb_partition_allowed = horzab_partition_allowed; - if (cpi->sf.prune_ext_partition_types_search_level) { + if (cpi->sf.part_sf.prune_ext_partition_types_search_level) { const int64_t horz_a_rd = horz_rd[1] + split_rd[0] + split_rd[1]; const int64_t horz_b_rd = horz_rd[0] + split_rd[2] + split_rd[3]; - switch (cpi->sf.prune_ext_partition_types_search_level) { + switch (cpi->sf.part_sf.prune_ext_partition_types_search_level) { case 1: horza_partition_allowed &= (horz_a_rd / 16 * 14 < best_rdc.rdcost); horzb_partition_allowed &= (horz_b_rd / 16 * 14 < best_rdc.rdcost); @@ -3149,10 +3409,10 @@ BEGIN_PARTITION_SEARCH: int verta_partition_allowed = vertab_partition_allowed; int vertb_partition_allowed = vertab_partition_allowed; - if (cpi->sf.prune_ext_partition_types_search_level) { + if (cpi->sf.part_sf.prune_ext_partition_types_search_level) { const int64_t vert_a_rd = vert_rd[1] + split_rd[0] + split_rd[2]; const int64_t vert_b_rd = vert_rd[0] + split_rd[1] + split_rd[3]; - switch (cpi->sf.prune_ext_partition_types_search_level) { + switch (cpi->sf.part_sf.prune_ext_partition_types_search_level) { case 1: verta_partition_allowed &= (vert_a_rd / 16 * 14 < best_rdc.rdcost); vertb_partition_allowed &= (vert_b_rd / 16 * 14 < best_rdc.rdcost); @@ -3165,7 +3425,7 @@ BEGIN_PARTITION_SEARCH: } } - if (cpi->sf.ml_prune_ab_partition && ext_partition_allowed && + if (cpi->sf.part_sf.ml_prune_ab_partition && ext_partition_allowed && partition_horz_allowed && partition_vert_allowed) { // TODO(huisu@google.com): x->source_variance may not be the current // block's variance. The correct one to use is pb_source_variance. Need to @@ -3182,6 +3442,12 @@ BEGIN_PARTITION_SEARCH: verta_partition_allowed &= cpi->oxcf.enable_ab_partitions; vertb_partition_allowed &= cpi->oxcf.enable_ab_partitions; + if (cpi->sf.part_sf.prune_ab_partition_using_split_info && + horza_partition_allowed) { + horza_partition_allowed &= evaluate_ab_partition_based_on_split( + pc_tree, PARTITION_HORZ, rect_part_win_info, x->qindex, 0, 1); + } + // PARTITION_HORZ_A if (!terminate_partition_search && partition_horz_allowed && horza_partition_allowed && !is_gt_max_sq_part) { @@ -3228,6 +3494,13 @@ BEGIN_PARTITION_SEARCH: #endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } + + if (cpi->sf.part_sf.prune_ab_partition_using_split_info && + horzb_partition_allowed) { + horzb_partition_allowed &= evaluate_ab_partition_based_on_split( + pc_tree, PARTITION_HORZ, rect_part_win_info, x->qindex, 2, 3); + } + // PARTITION_HORZ_B if (!terminate_partition_search && partition_horz_allowed && horzb_partition_allowed && !is_gt_max_sq_part) { @@ -3270,6 +3543,12 @@ BEGIN_PARTITION_SEARCH: restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } + if (cpi->sf.part_sf.prune_ab_partition_using_split_info && + verta_partition_allowed) { + verta_partition_allowed &= evaluate_ab_partition_based_on_split( + pc_tree, PARTITION_VERT, rect_part_win_info, x->qindex, 0, 2); + } + // PARTITION_VERT_A if (!terminate_partition_search && partition_vert_allowed && verta_partition_allowed && !is_gt_max_sq_part) { @@ -3310,6 +3589,13 @@ BEGIN_PARTITION_SEARCH: #endif restore_context(x, &x_ctx, mi_row, mi_col, bsize, num_planes); } + + if (cpi->sf.part_sf.prune_ab_partition_using_split_info && + vertb_partition_allowed) { + vertb_partition_allowed &= evaluate_ab_partition_based_on_split( + pc_tree, PARTITION_VERT, rect_part_win_info, x->qindex, 1, 3); + } + // PARTITION_VERT_B if (!terminate_partition_search && partition_vert_allowed && vertb_partition_allowed && !is_gt_max_sq_part) { @@ -3368,7 +3654,7 @@ BEGIN_PARTITION_SEARCH: partition4_allowed && partition_vert_allowed && get_plane_block_size(get_partition_subsize(bsize, PARTITION_VERT_4), xss, yss) != BLOCK_INVALID; - if (cpi->sf.prune_ext_partition_types_search_level == 2) { + if (cpi->sf.part_sf.prune_ext_partition_types_search_level == 2) { partition_horz4_allowed &= (pc_tree->partitioning == PARTITION_HORZ || pc_tree->partitioning == PARTITION_HORZ_A || pc_tree->partitioning == PARTITION_HORZ_B || @@ -3380,7 +3666,7 @@ BEGIN_PARTITION_SEARCH: pc_tree->partitioning == PARTITION_SPLIT || pc_tree->partitioning == PARTITION_NONE); } - if (cpi->sf.ml_prune_4_partition && partition4_allowed && + if (cpi->sf.part_sf.ml_prune_4_partition && partition4_allowed && partition_horz_allowed && partition_vert_allowed) { av1_ml_prune_4_partition(cpi, x, bsize, pc_tree->partitioning, best_rdc.rdcost, horz_rd, vert_rd, split_rd, @@ -3388,20 +3674,32 @@ BEGIN_PARTITION_SEARCH: pb_source_variance, mi_row, mi_col); } -#if CONFIG_DIST_8X8 - if (x->using_dist_8x8) { - if (block_size_high[bsize] <= 16 || block_size_wide[bsize] <= 16) { - partition_horz4_allowed = 0; - partition_vert4_allowed = 0; - } - } -#endif - if (blksize < (min_partition_size << 2)) { partition_horz4_allowed = 0; partition_vert4_allowed = 0; } + if (cpi->sf.part_sf.prune_4_partition_using_split_info && + (partition_horz4_allowed || partition_vert4_allowed)) { + // Count of child blocks in which HORZ or VERT partition has won + int num_child_horz_win = 0, num_child_vert_win = 0; + for (int idx = 0; idx < 4; idx++) { + num_child_horz_win += (split_part_rect_win[idx].horz_win) ? 1 : 0; + num_child_vert_win += (split_part_rect_win[idx].vert_win) ? 1 : 0; + } + + // Prune HORZ4/VERT4 partitions based on number of HORZ/VERT winners of + // split partiitons. + // Conservative pruning for high quantizers + const int num_win_thresh = AOMMIN(3 * (MAXQ - x->qindex) / MAXQ + 1, 3); + if (num_child_horz_win < num_win_thresh) { + partition_horz4_allowed = 0; + } + if (num_child_vert_win < num_win_thresh) { + partition_vert4_allowed = 0; + } + } + // PARTITION_HORZ_4 assert(IMPLIES(!cpi->oxcf.enable_rect_partitions, !partition_horz4_allowed)); if (!terminate_partition_search && partition_horz4_allowed && has_rows && @@ -3425,7 +3723,7 @@ BEGIN_PARTITION_SEARCH: for (int i = 0; i < 4; ++i) { const int this_mi_row = mi_row + i * quarter_step; - if (i > 0 && this_mi_row >= cm->mi_rows) break; + if (i > 0 && this_mi_row >= mi_params->mi_rows) break; PICK_MODE_CONTEXT *ctx_this = &pc_tree->horizontal4[i]; @@ -3481,7 +3779,7 @@ BEGIN_PARTITION_SEARCH: for (int i = 0; i < 4; ++i) { const int this_mi_col = mi_col + i * quarter_step; - if (i > 0 && this_mi_col >= cm->mi_cols) break; + if (i > 0 && this_mi_col >= mi_params->mi_cols) break; PICK_MODE_CONTEXT *ctx_this = &pc_tree->vertical4[i]; @@ -3565,8 +3863,11 @@ BEGIN_PARTITION_SEARCH: if (found_best_partition && pc_tree->index != 3) { if (bsize == cm->seq_params.sb_size) { + const int emit_output = multi_pass_mode != SB_DRY_PASS; + const RUN_TYPE run_type = emit_output ? OUTPUT_ENABLED : DRY_RUN_NORMAL; + x->cb_offset = 0; - encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, OUTPUT_ENABLED, bsize, + encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, run_type, bsize, pc_tree, NULL); } else { encode_sb(cpi, td, tile_data, tp, mi_row, mi_col, DRY_RUN_NORMAL, bsize, @@ -3588,9 +3889,6 @@ BEGIN_PARTITION_SEARCH: #undef NUM_SIMPLE_MOTION_FEATURES #if !CONFIG_REALTIME_ONLY -static INLINE int coded_to_superres_mi(int mi_col, int denom) { - return (mi_col * denom + SCALE_NUMERATOR / 2) / SCALE_NUMERATOR; -} static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, int mi_row, int mi_col, int orig_rdmult) { @@ -3598,8 +3896,10 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int tpl_idx = cpi->gf_group.index; - TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_idx]; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx]; TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; int tpl_stride = tpl_frame->stride; int64_t intra_cost = 0; int64_t mc_dep_cost = 0; @@ -3612,30 +3912,26 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, if (cpi->gf_group.index >= MAX_LAG_BUFFERS) return orig_rdmult; -#if !USE_TPL_CLASSIC_MODEL int64_t mc_count = 0, mc_saved = 0; -#endif // !USE_TPL_CLASSIC_MODEL int mi_count = 0; const int mi_col_sr = coded_to_superres_mi(mi_col, cm->superres_scale_denominator); const int mi_col_end_sr = coded_to_superres_mi(mi_col + mi_wide, cm->superres_scale_denominator); const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << block_mis_log2; for (int row = mi_row; row < mi_row + mi_high; row += step) { for (int col = mi_col_sr; col < mi_col_end_sr; col += step) { - if (row >= cm->mi_rows || col >= mi_cols_sr) continue; + if (row >= cm->mi_params.mi_rows || col >= mi_cols_sr) continue; TplDepStats *this_stats = - &tpl_stats[av1_tpl_ptr_pos(cpi, row, col, tpl_stride)]; + &tpl_stats[av1_tpl_ptr_pos(row, col, tpl_stride, block_mis_log2)]; int64_t mc_dep_delta = RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate, this_stats->mc_dep_dist); intra_cost += this_stats->recrf_dist << RDDIV_BITS; mc_dep_cost += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta; -#if !USE_TPL_CLASSIC_MODEL mc_count += this_stats->mc_count; mc_saved += this_stats->mc_saved; -#endif // !USE_TPL_CLASSIC_MODEL mi_count++; } } @@ -3649,7 +3945,6 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, const double rk = (double)intra_cost / mc_dep_cost; beta = (r0 / rk); } -#if !USE_TPL_CLASSIC_MODEL } else if (analysis_type == 1) { const double mc_count_base = (mi_count * cpi->rd.mc_count_base); beta = (mc_count + 1.0) / (mc_count_base + 1.0); @@ -3658,7 +3953,6 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, const double mc_saved_base = (mi_count * cpi->rd.mc_saved_base); beta = (mc_saved + 1.0) / (mc_saved_base + 1.0); beta = pow(beta, 0.5); -#endif // !USE_TPL_CLASSIC_MODEL } int rdmult = av1_get_adaptive_rdmult(cpi, beta); @@ -3675,13 +3969,10 @@ static int get_rdmult_delta(AV1_COMP *cpi, BLOCK_SIZE bsize, int analysis_type, static int get_tpl_stats_b(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, int64_t *intra_cost_b, - int64_t *inter_cost_b, int *stride) { + int64_t *inter_cost_b, + int_mv mv_b[][INTER_REFS_PER_FRAME], int *stride) { if (!cpi->oxcf.enable_tpl_model) return 0; - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - return 0; - } - if (cpi->oxcf.superres_mode != SUPERRES_NONE) return 0; + if (cpi->superres_mode != SUPERRES_NONE) return 0; if (cpi->common.current_frame.frame_type == KEY_FRAME) return 0; const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); if (update_type == INTNL_OVERLAY_UPDATE || update_type == OVERLAY_UPDATE) @@ -3691,7 +3982,8 @@ static int get_tpl_stats_b(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, AV1_COMMON *const cm = &cpi->common; const int gf_group_index = cpi->gf_group.index; - TplDepFrame *tpl_frame = &cpi->tpl_frame[gf_group_index]; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_group_index]; TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; int tpl_stride = tpl_frame->stride; const int mi_wide = mi_size_wide[bsize]; @@ -3701,10 +3993,12 @@ static int get_tpl_stats_b(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, if (gf_group_index >= MAX_LAG_BUFFERS) return 0; int mi_count = 0; + int count = 0; const int mi_col_sr = coded_to_superres_mi(mi_col, cm->superres_scale_denominator); const int mi_col_end_sr = coded_to_superres_mi(mi_col + mi_wide, cm->superres_scale_denominator); + // mi_cols_sr is mi_cols at superres case. const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); // TPL store unit size is not the same as the motion estimation unit size. @@ -3714,16 +4008,30 @@ static int get_tpl_stats_b(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, const int step = mi_size_wide[tpl_bsize]; assert(mi_size_wide[tpl_bsize] == mi_size_high[tpl_bsize]); + // Stride is only based on SB size, and we fill in values for every 16x16 + // block in a SB. *stride = (mi_col_end_sr - mi_col_sr) / step; for (int row = mi_row; row < mi_row + mi_high; row += step) { for (int col = mi_col_sr; col < mi_col_end_sr; col += step) { - if (row >= cm->mi_rows || col >= mi_cols_sr) continue; - TplDepStats *this_stats = - &tpl_stats[av1_tpl_ptr_pos(cpi, row, col, tpl_stride)]; - inter_cost_b[mi_count] = this_stats->inter_cost; - intra_cost_b[mi_count] = this_stats->intra_cost; + // Handle partial SB, so that no invalid values are used later. + if (row >= cm->mi_params.mi_rows || col >= mi_cols_sr) { + inter_cost_b[count] = INT64_MAX; + intra_cost_b[count] = INT64_MAX; + for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { + mv_b[count][i].as_int = INVALID_MV; + } + count++; + continue; + } + + TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos( + row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)]; + inter_cost_b[count] = this_stats->inter_cost; + intra_cost_b[count] = this_stats->intra_cost; + memcpy(mv_b[count], this_stats->mv, sizeof(this_stats->mv)); mi_count++; + count++; } } @@ -3735,55 +4043,48 @@ static int get_tpl_stats_b(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, // analysis_type 2: Use cost reduction from intra to inter for best inter // predictor chosen static int get_q_for_deltaq_objective(AV1_COMP *const cpi, BLOCK_SIZE bsize, - int analysis_type, int mi_row, - int mi_col) { + int mi_row, int mi_col) { AV1_COMMON *const cm = &cpi->common; assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int tpl_idx = cpi->gf_group.index; - TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_idx]; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx]; TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; int tpl_stride = tpl_frame->stride; int64_t intra_cost = 0; int64_t mc_dep_cost = 0; const int mi_wide = mi_size_wide[bsize]; const int mi_high = mi_size_high[bsize]; + const int base_qindex = cm->quant_params.base_qindex; - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - return cm->base_qindex; - } + if (tpl_frame->is_valid == 0) return base_qindex; - if (tpl_frame->is_valid == 0) return cm->base_qindex; + if (!is_frame_tpl_eligible(cpi)) return base_qindex; - if (!is_frame_tpl_eligible(cpi)) return cm->base_qindex; + if (cpi->gf_group.index >= MAX_LAG_BUFFERS) return base_qindex; - if (cpi->gf_group.index >= MAX_LAG_BUFFERS) return cm->base_qindex; - -#if !USE_TPL_CLASSIC_MODEL int64_t mc_count = 0, mc_saved = 0; -#endif // !USE_TPL_CLASSIC_MODEL int mi_count = 0; const int mi_col_sr = coded_to_superres_mi(mi_col, cm->superres_scale_denominator); const int mi_col_end_sr = coded_to_superres_mi(mi_col + mi_wide, cm->superres_scale_denominator); const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << block_mis_log2; for (int row = mi_row; row < mi_row + mi_high; row += step) { for (int col = mi_col_sr; col < mi_col_end_sr; col += step) { - if (row >= cm->mi_rows || col >= mi_cols_sr) continue; + if (row >= cm->mi_params.mi_rows || col >= mi_cols_sr) continue; TplDepStats *this_stats = - &tpl_stats[av1_tpl_ptr_pos(cpi, row, col, tpl_stride)]; + &tpl_stats[av1_tpl_ptr_pos(row, col, tpl_stride, block_mis_log2)]; int64_t mc_dep_delta = RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate, this_stats->mc_dep_dist); intra_cost += this_stats->recrf_dist << RDDIV_BITS; mc_dep_cost += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta; -#if !USE_TPL_CLASSIC_MODEL mc_count += this_stats->mc_count; mc_saved += this_stats->mc_saved; -#endif // !USE_TPL_CLASSIC_MODEL mi_count++; } } @@ -3792,34 +4093,19 @@ static int get_q_for_deltaq_objective(AV1_COMP *const cpi, BLOCK_SIZE bsize, int offset = 0; double beta = 1.0; - if (analysis_type == 0) { - if (mc_dep_cost > 0 && intra_cost > 0) { - const double r0 = cpi->rd.r0; - const double rk = (double)intra_cost / mc_dep_cost; - beta = (r0 / rk); - assert(beta > 0.0); - } -#if !USE_TPL_CLASSIC_MODEL - } else if (analysis_type == 1) { - const double mc_count_base = (mi_count * cpi->rd.mc_count_base); - beta = (mc_count + 1.0) / (mc_count_base + 1.0); - beta = pow(beta, 0.5); - } else if (analysis_type == 2) { - const double mc_saved_base = (mi_count * cpi->rd.mc_saved_base); - beta = (mc_saved + 1.0) / (mc_saved_base + 1.0); - beta = pow(beta, 0.5); -#endif // !USE_TPL_CLASSIC_MODEL + if (mc_dep_cost > 0 && intra_cost > 0) { + const double r0 = cpi->rd.r0; + const double rk = (double)intra_cost / mc_dep_cost; + beta = (r0 / rk); + assert(beta > 0.0); } - offset = (7 * av1_get_deltaq_offset(cpi, cm->base_qindex, beta)) / 8; - // printf("[%d/%d]: beta %g offset %d\n", pyr_lev_from_top, - // cpi->gf_group.pyramid_height, beta, offset); - + offset = av1_get_deltaq_offset(cpi, base_qindex, beta); aom_clear_system_state(); const DeltaQInfo *const delta_q_info = &cm->delta_q_info; offset = AOMMIN(offset, delta_q_info->delta_q_res * 9 - 1); offset = AOMMAX(offset, -delta_q_info->delta_q_res * 9 + 1); - int qindex = cm->base_qindex + offset; + int qindex = cm->quant_params.base_qindex + offset; qindex = AOMMIN(qindex, MAXQ); qindex = AOMMAX(qindex, MINQ); @@ -3831,6 +4117,7 @@ static AOM_INLINE void setup_delta_q(AV1_COMP *const cpi, ThreadData *td, const TileInfo *const tile_info, int mi_row, int mi_col, int num_planes) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; const DeltaQInfo *const delta_q_info = &cm->delta_q_info; assert(delta_q_info->delta_q_present_flag); @@ -3838,7 +4125,7 @@ static AOM_INLINE void setup_delta_q(AV1_COMP *const cpi, ThreadData *td, // Delta-q modulation based on variance av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size); - int current_qindex = cm->base_qindex; + int current_qindex = cm->quant_params.base_qindex; if (cpi->oxcf.deltaq_mode == DELTA_Q_PERCEPTUAL) { if (DELTA_Q_PERCEPTUAL_MODULATION == 1) { const int block_wavelet_energy_level = @@ -3852,16 +4139,21 @@ static AOM_INLINE void setup_delta_q(AV1_COMP *const cpi, ThreadData *td, current_qindex = av1_compute_q_from_energy_level_deltaq_mode(cpi, block_var_level); } - } else if (cpi->oxcf.deltaq_mode == DELTA_Q_OBJECTIVE) { - assert(cpi->oxcf.enable_tpl_model); + } else if (cpi->oxcf.deltaq_mode == DELTA_Q_OBJECTIVE && + cpi->oxcf.enable_tpl_model) { // Setup deltaq based on tpl stats - current_qindex = - get_q_for_deltaq_objective(cpi, sb_size, 0, mi_row, mi_col); + current_qindex = get_q_for_deltaq_objective(cpi, sb_size, mi_row, mi_col); } const int delta_q_res = delta_q_info->delta_q_res; - current_qindex = - clamp(current_qindex, delta_q_res, 256 - delta_q_info->delta_q_res); + // Right now aq only works with tpl model. So if tpl is disabled, we set the + // current_qindex to base_qindex. + if (cpi->oxcf.enable_tpl_model && cpi->oxcf.deltaq_mode != NO_DELTA_Q) { + current_qindex = + clamp(current_qindex, delta_q_res, 256 - delta_q_info->delta_q_res); + } else { + current_qindex = cm->quant_params.base_qindex; + } MACROBLOCKD *const xd = &x->e_mbd; const int sign_deltaq_index = @@ -3874,7 +4166,7 @@ static AOM_INLINE void setup_delta_q(AV1_COMP *const cpi, ThreadData *td, current_qindex = AOMMAX(current_qindex, MINQ + 1); assert(current_qindex > 0); - xd->delta_qindex = current_qindex - cm->base_qindex; + xd->delta_qindex = current_qindex - cm->quant_params.base_qindex; set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); xd->mi[0]->current_qindex = current_qindex; av1_init_plane_quantizers(cpi, x, xd->mi[0]->segment_id); @@ -3895,12 +4187,12 @@ static AOM_INLINE void setup_delta_q(AV1_COMP *const cpi, ThreadData *td, // pre-set the delta lf for loop filter. Note that this value is set // before mi is assigned for each block in current superblock - for (int j = 0; j < AOMMIN(mib_size, cm->mi_rows - mi_row); j++) { - for (int k = 0; k < AOMMIN(mib_size, cm->mi_cols - mi_col); k++) { - const int mi_idx = get_alloc_mi_idx(cm, mi_row + j, mi_col + k); - cm->mi[mi_idx].delta_lf_from_base = delta_lf; + for (int j = 0; j < AOMMIN(mib_size, mi_params->mi_rows - mi_row); j++) { + for (int k = 0; k < AOMMIN(mib_size, mi_params->mi_cols - mi_col); k++) { + const int grid_idx = get_mi_grid_idx(mi_params, mi_row + j, mi_col + k); + mi_params->mi_grid_base[grid_idx]->delta_lf_from_base = delta_lf; for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id) { - cm->mi[mi_idx].delta_lf[lf_id] = delta_lf; + mi_params->mi_grid_base[grid_idx]->delta_lf[lf_id] = delta_lf; } } } @@ -4092,12 +4384,6 @@ static AOM_INLINE void adjust_rdmult_tpl_model(AV1_COMP *cpi, MACROBLOCK *x, const BLOCK_SIZE sb_size = cpi->common.seq_params.sb_size; const int orig_rdmult = cpi->rd.RDMULT; - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - x->rdmult = orig_rdmult; - return; - } - assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int gf_group_index = cpi->gf_group.index; @@ -4111,30 +4397,498 @@ static AOM_INLINE void adjust_rdmult_tpl_model(AV1_COMP *cpi, MACROBLOCK *x, } #endif -static INLINE void reset_thresh_freq_fact(MACROBLOCK *const x) { - int i, j; - for (i = 0; i < BLOCK_SIZES_ALL; ++i) { - for (j = 0; j < MAX_MODES; ++j) { - x->thresh_freq_fact[i][j] = 32; +static void source_content_sb(AV1_COMP *cpi, MACROBLOCK *x, int shift) { + unsigned int tmp_sse; + unsigned int tmp_variance; + const BLOCK_SIZE bsize = BLOCK_64X64; + uint8_t *src_y = cpi->source->y_buffer; + int src_ystride = cpi->source->y_stride; + uint8_t *last_src_y = cpi->last_source->y_buffer; + int last_src_ystride = cpi->last_source->y_stride; + uint64_t avg_source_sse_threshold = 100000; // ~5*5*(64*64) + uint64_t avg_source_sse_threshold_high = 1000000; // ~15*15*(64*64) + uint64_t sum_sq_thresh = 10000; // sum = sqrt(thresh / 64*64)) ~1.5 +#if CONFIG_AV1_HIGHBITDEPTH + MACROBLOCKD *xd = &x->e_mbd; + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) return; +#endif + src_y += shift; + last_src_y += shift; + tmp_variance = cpi->fn_ptr[bsize].vf(src_y, src_ystride, last_src_y, + last_src_ystride, &tmp_sse); + // Note: tmp_sse - tmp_variance = ((sum * sum) >> 12) + // Detect large lighting change. + if (tmp_variance < (tmp_sse >> 1) && (tmp_sse - tmp_variance) > sum_sq_thresh) + x->content_state_sb = kLowVarHighSumdiff; + else if (tmp_sse < avg_source_sse_threshold) + x->content_state_sb = kLowSad; + else if (tmp_sse > avg_source_sse_threshold_high) + x->content_state_sb = kHighSad; +} + +static AOM_INLINE void encode_nonrd_sb(AV1_COMP *cpi, ThreadData *td, + TileDataEnc *tile_data, + PC_TREE *const pc_root, TOKENEXTRA **tp, + const int mi_row, const int mi_col, + const int seg_skip) { + AV1_COMMON *const cm = &cpi->common; + MACROBLOCK *const x = &td->mb; + const SPEED_FEATURES *const sf = &cpi->sf; + const TileInfo *const tile_info = &tile_data->tile_info; + MB_MODE_INFO **mi = cm->mi_params.mi_grid_base + + get_mi_grid_idx(&cm->mi_params, mi_row, mi_col); + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + if (sf->rt_sf.source_metrics_sb_nonrd && sb_size == BLOCK_64X64 && + cpi->svc.number_spatial_layers <= 1 && + cm->current_frame.frame_type != KEY_FRAME) { + int shift = cpi->source->y_stride * (mi_row << 2) + (mi_col << 2); + source_content_sb(cpi, x, shift); + } + if (sf->part_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->part_sf.always_this_block_size; + set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize); + } else if (cpi->partition_search_skippable_frame) { + set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); + const BLOCK_SIZE bsize = + get_rd_var_based_fixed_partition(cpi, x, mi_row, mi_col); + set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize); + } else if (sf->part_sf.partition_search_type == VAR_BASED_PARTITION) { + set_offsets_without_segment_id(cpi, tile_info, x, mi_row, mi_col, sb_size); + av1_choose_var_based_partitioning(cpi, tile_info, td, x, mi_row, mi_col); + } + assert(sf->part_sf.partition_search_type == FIXED_PARTITION || seg_skip || + cpi->partition_search_skippable_frame || + sf->part_sf.partition_search_type == VAR_BASED_PARTITION); + td->mb.cb_offset = 0; + nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, + pc_root); +} + +// Memset the mbmis at the current superblock to 0 +static INLINE void reset_mbmi(CommonModeInfoParams *const mi_params, + BLOCK_SIZE sb_size, int mi_row, int mi_col) { + // size of sb in unit of mi (BLOCK_4X4) + const int sb_size_mi = mi_size_wide[sb_size]; + const int mi_alloc_size_1d = mi_size_wide[mi_params->mi_alloc_bsize]; + // size of sb in unit of allocated mi size + const int sb_size_alloc_mi = mi_size_wide[sb_size] / mi_alloc_size_1d; + assert(mi_params->mi_alloc_stride % sb_size_alloc_mi == 0 && + "mi is not allocated as a multiple of sb!"); + assert(mi_params->mi_stride % sb_size_mi == 0 && + "mi_grid_base is not allocated as a multiple of sb!"); + + const int mi_rows = mi_size_high[sb_size]; + for (int cur_mi_row = 0; cur_mi_row < mi_rows; cur_mi_row++) { + assert(get_mi_grid_idx(mi_params, 0, mi_col + mi_alloc_size_1d) < + mi_params->mi_stride); + const int mi_grid_idx = + get_mi_grid_idx(mi_params, mi_row + cur_mi_row, mi_col); + const int alloc_mi_idx = + get_alloc_mi_idx(mi_params, mi_row + cur_mi_row, mi_col); + memset(&mi_params->mi_grid_base[mi_grid_idx], 0, + sb_size_mi * sizeof(*mi_params->mi_grid_base)); + memset(&mi_params->tx_type_map[mi_grid_idx], 0, + sb_size_mi * sizeof(*mi_params->tx_type_map)); + if (cur_mi_row % mi_alloc_size_1d == 0) { + memset(&mi_params->mi_alloc[alloc_mi_idx], 0, + sb_size_alloc_mi * sizeof(*mi_params->mi_alloc)); } } } +static INLINE void backup_sb_state(SB_FIRST_PASS_STATS *sb_fp_stats, + const AV1_COMP *cpi, ThreadData *td, + const TileDataEnc *tile_data, int mi_row, + int mi_col) { + MACROBLOCK *x = &td->mb; + MACROBLOCKD *xd = &x->e_mbd; + const TileInfo *tile_info = &tile_data->tile_info; + + const AV1_COMMON *cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + + xd->above_txfm_context = + cm->above_contexts.txfm[tile_info->tile_row] + mi_col; + xd->left_txfm_context = + xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + save_context(x, &sb_fp_stats->x_ctx, mi_row, mi_col, sb_size, num_planes); + + sb_fp_stats->rd_count = cpi->td.rd_counts; + sb_fp_stats->split_count = cpi->td.mb.txb_split_count; + + sb_fp_stats->fc = *td->counts; + + memcpy(sb_fp_stats->inter_mode_rd_models, tile_data->inter_mode_rd_models, + sizeof(sb_fp_stats->inter_mode_rd_models)); + + memcpy(sb_fp_stats->thresh_freq_fact, x->thresh_freq_fact, + sizeof(sb_fp_stats->thresh_freq_fact)); + + const int alloc_mi_idx = get_alloc_mi_idx(&cm->mi_params, mi_row, mi_col); + sb_fp_stats->current_qindex = + cm->mi_params.mi_alloc[alloc_mi_idx].current_qindex; + +#if CONFIG_INTERNAL_STATS + memcpy(sb_fp_stats->mode_chosen_counts, cpi->mode_chosen_counts, + sizeof(sb_fp_stats->mode_chosen_counts)); +#endif // CONFIG_INTERNAL_STATS +} + +static INLINE void restore_sb_state(const SB_FIRST_PASS_STATS *sb_fp_stats, + AV1_COMP *cpi, ThreadData *td, + TileDataEnc *tile_data, int mi_row, + int mi_col) { + MACROBLOCK *x = &td->mb; + + const AV1_COMMON *cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + + restore_context(x, &sb_fp_stats->x_ctx, mi_row, mi_col, sb_size, num_planes); + + cpi->td.rd_counts = sb_fp_stats->rd_count; + cpi->td.mb.txb_split_count = sb_fp_stats->split_count; + + *td->counts = sb_fp_stats->fc; + + memcpy(tile_data->inter_mode_rd_models, sb_fp_stats->inter_mode_rd_models, + sizeof(sb_fp_stats->inter_mode_rd_models)); + memcpy(x->thresh_freq_fact, sb_fp_stats->thresh_freq_fact, + sizeof(sb_fp_stats->thresh_freq_fact)); + + const int alloc_mi_idx = get_alloc_mi_idx(&cm->mi_params, mi_row, mi_col); + cm->mi_params.mi_alloc[alloc_mi_idx].current_qindex = + sb_fp_stats->current_qindex; + +#if CONFIG_INTERNAL_STATS + memcpy(cpi->mode_chosen_counts, sb_fp_stats->mode_chosen_counts, + sizeof(sb_fp_stats->mode_chosen_counts)); +#endif // CONFIG_INTERNAL_STATS +} + +#if !CONFIG_REALTIME_ONLY +static void init_ref_frame_space(AV1_COMP *cpi, ThreadData *td, int mi_row, + int mi_col) { + const AV1_COMMON *cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + MACROBLOCK *x = &td->mb; + const int frame_idx = cpi->gf_group.index; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[frame_idx]; + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; + + av1_zero(x->search_ref_frame); + + if (tpl_frame->is_valid == 0) return; + if (!is_frame_tpl_eligible(cpi)) return; + if (frame_idx >= MAX_LAG_BUFFERS) return; + if (cpi->superres_mode != SUPERRES_NONE) return; + if (cpi->oxcf.aq_mode != NO_AQ) return; + + const int is_overlay = cpi->gf_group.update_type[frame_idx] == OVERLAY_UPDATE; + if (is_overlay) { + memset(x->search_ref_frame, 1, sizeof(x->search_ref_frame)); + return; + } + + TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; + const int tpl_stride = tpl_frame->stride; + int64_t inter_cost[INTER_REFS_PER_FRAME] = { 0 }; + const int step = 1 << block_mis_log2; + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + const int mi_row_end = + AOMMIN(mi_size_high[sb_size] + mi_row, mi_params->mi_rows); + const int mi_col_end = + AOMMIN(mi_size_wide[sb_size] + mi_col, mi_params->mi_cols); + + for (int row = mi_row; row < mi_row_end; row += step) { + for (int col = mi_col; col < mi_col_end; col += step) { + const TplDepStats *this_stats = + &tpl_stats[av1_tpl_ptr_pos(row, col, tpl_stride, block_mis_log2)]; + int64_t tpl_pred_error[INTER_REFS_PER_FRAME] = { 0 }; + // Find the winner ref frame idx for the current block + int64_t best_inter_cost = this_stats->pred_error[0]; + int best_rf_idx = 0; + for (int idx = 1; idx < INTER_REFS_PER_FRAME; ++idx) { + if ((this_stats->pred_error[idx] < best_inter_cost) && + (this_stats->pred_error[idx] != 0)) { + best_inter_cost = this_stats->pred_error[idx]; + best_rf_idx = idx; + } + } + // tpl_pred_error is the pred_error reduction of best_ref w.r.t. + // LAST_FRAME. + tpl_pred_error[best_rf_idx] = this_stats->pred_error[best_rf_idx] - + this_stats->pred_error[LAST_FRAME - 1]; + + for (int rf_idx = 1; rf_idx < INTER_REFS_PER_FRAME; ++rf_idx) + inter_cost[rf_idx] += tpl_pred_error[rf_idx]; + } + } + + int rank_index[INTER_REFS_PER_FRAME - 1]; + for (int idx = 0; idx < INTER_REFS_PER_FRAME - 1; ++idx) { + rank_index[idx] = idx + 1; + for (int i = idx; i > 0; --i) { + if (inter_cost[rank_index[i - 1]] > inter_cost[rank_index[i]]) { + const int tmp = rank_index[i - 1]; + rank_index[i - 1] = rank_index[i]; + rank_index[i] = tmp; + } + } + } + + x->search_ref_frame[INTRA_FRAME] = 1; + x->search_ref_frame[LAST_FRAME] = 1; + + int cutoff_ref = 0; + for (int idx = 0; idx < INTER_REFS_PER_FRAME - 1; ++idx) { + x->search_ref_frame[rank_index[idx] + LAST_FRAME] = 1; + if (idx > 2) { + if (!cutoff_ref) { + // If the predictive coding gains are smaller than the previous more + // relevant frame over certain amount, discard this frame and all the + // frames afterwards. + if (llabs(inter_cost[rank_index[idx]]) < + llabs(inter_cost[rank_index[idx - 1]]) / 8 || + inter_cost[rank_index[idx]] == 0) + cutoff_ref = 1; + } + + if (cutoff_ref) x->search_ref_frame[rank_index[idx] + LAST_FRAME] = 0; + } + } +} +#endif // !CONFIG_REALTIME_ONLY + +// This function initializes the stats for encode_rd_sb. +static INLINE void init_encode_rd_sb(AV1_COMP *cpi, ThreadData *td, + const TileDataEnc *tile_data, + PC_TREE *pc_root, RD_STATS *rd_cost, + int mi_row, int mi_col, + int gather_tpl_data) { + const AV1_COMMON *cm = &cpi->common; + const TileInfo *tile_info = &tile_data->tile_info; + MACROBLOCK *x = &td->mb; + + const SPEED_FEATURES *sf = &cpi->sf; + const int use_simple_motion_search = + (sf->part_sf.simple_motion_search_split || + sf->part_sf.simple_motion_search_prune_rect || + sf->part_sf.simple_motion_search_early_term_none || + sf->part_sf.ml_early_term_after_part_split_level) && + !frame_is_intra_only(cm); + if (use_simple_motion_search) { + init_simple_motion_search_mvs(pc_root); + } + +#if !CONFIG_REALTIME_ONLY + init_ref_frame_space(cpi, td, mi_row, mi_col); + x->sb_energy_level = 0; + x->cnn_output_valid = 0; + if (gather_tpl_data) { + if (cm->delta_q_info.delta_q_present_flag) { + const int num_planes = av1_num_planes(cm); + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + setup_delta_q(cpi, td, x, tile_info, mi_row, mi_col, num_planes); + av1_tpl_rdmult_setup_sb(cpi, x, sb_size, mi_row, mi_col); + } + if (cpi->oxcf.enable_tpl_model) { + adjust_rdmult_tpl_model(cpi, x, mi_row, mi_col); + } + } +#else + (void)tile_info; + (void)mi_row; + (void)mi_col; + (void)gather_tpl_data; +#endif + + // Reset hash state for transform/mode rd hash information + reset_hash_records(x, cpi->sf.tx_sf.use_inter_txb_hash); + av1_zero(x->picked_ref_frames_mask); + av1_zero(x->pred_mv); + av1_invalid_rd_stats(rd_cost); +} + +static AOM_INLINE void encode_rd_sb(AV1_COMP *cpi, ThreadData *td, + TileDataEnc *tile_data, + PC_TREE *const pc_root, TOKENEXTRA **tp, + const int mi_row, const int mi_col, + const int seg_skip) { + AV1_COMMON *const cm = &cpi->common; + MACROBLOCK *const x = &td->mb; + const SPEED_FEATURES *const sf = &cpi->sf; + const TileInfo *const tile_info = &tile_data->tile_info; + MB_MODE_INFO **mi = cm->mi_params.mi_grid_base + + get_mi_grid_idx(&cm->mi_params, mi_row, mi_col); + const BLOCK_SIZE sb_size = cm->seq_params.sb_size; + int dummy_rate; + int64_t dummy_dist; + RD_STATS dummy_rdc; + +#if CONFIG_REALTIME_ONLY + (void)seg_skip; +#endif // CONFIG_REALTIME_ONLY + + init_encode_rd_sb(cpi, td, tile_data, pc_root, &dummy_rdc, mi_row, mi_col, 1); + + if (sf->part_sf.partition_search_type == VAR_BASED_PARTITION) { + set_offsets_without_segment_id(cpi, tile_info, x, mi_row, mi_col, sb_size); + av1_choose_var_based_partitioning(cpi, tile_info, td, x, mi_row, mi_col); + rd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, + &dummy_rate, &dummy_dist, 1, pc_root); + } +#if !CONFIG_REALTIME_ONLY + else if (sf->part_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->part_sf.always_this_block_size; + 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 (cpi->partition_search_skippable_frame) { + set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); + const BLOCK_SIZE bsize = + get_rd_var_based_fixed_partition(cpi, x, mi_row, mi_col); + 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 { + // No stats for overlay frames. Exclude key frame. + x->valid_cost_b = + get_tpl_stats_b(cpi, sb_size, mi_row, mi_col, x->intra_cost_b, + x->inter_cost_b, x->mv_b, &x->cost_stride); + + reset_partition(pc_root, sb_size); + +#if CONFIG_COLLECT_COMPONENT_TIMING + start_timing(cpi, rd_pick_partition_time); +#endif + BLOCK_SIZE max_sq_size = x->max_partition_size; + BLOCK_SIZE min_sq_size = x->min_partition_size; + + 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 = AOMMAX( + AOMMIN(av1_predict_max_partition(cpi, x, features), max_sq_size), + min_sq_size); + } + + const int num_passes = cpi->oxcf.sb_multipass_unit_test ? 2 : 1; + + if (num_passes == 1) { + rd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, sb_size, + max_sq_size, min_sq_size, &dummy_rdc, dummy_rdc, + pc_root, NULL, SB_SINGLE_PASS, NULL); + } else { + // First pass + SB_FIRST_PASS_STATS sb_fp_stats; + backup_sb_state(&sb_fp_stats, cpi, td, tile_data, mi_row, mi_col); + rd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, sb_size, + max_sq_size, min_sq_size, &dummy_rdc, dummy_rdc, + pc_root, NULL, SB_DRY_PASS, NULL); + + // Second pass + init_encode_rd_sb(cpi, td, tile_data, pc_root, &dummy_rdc, mi_row, mi_col, + 0); + reset_mbmi(&cm->mi_params, sb_size, mi_row, mi_col); + reset_partition(pc_root, sb_size); + + restore_sb_state(&sb_fp_stats, cpi, td, tile_data, mi_row, mi_col); + + rd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, sb_size, + max_sq_size, min_sq_size, &dummy_rdc, dummy_rdc, + pc_root, NULL, SB_WET_PASS, NULL); + } + // Reset to 0 so that it wouldn't be used elsewhere mistakenly. + x->valid_cost_b = 0; +#if CONFIG_COLLECT_COMPONENT_TIMING + end_timing(cpi, rd_pick_partition_time); +#endif + } +#endif // !CONFIG_REALTIME_ONLY + + // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile. + if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 && + cm->tiles.cols == 1 && cm->tiles.rows == 1) { + av1_inter_mode_data_fit(tile_data, x->rdmult); + } +} + +static AOM_INLINE void set_cost_upd_freq(AV1_COMP *cpi, ThreadData *td, + const TileInfo *const tile_info, + const int mi_row, const int mi_col) { + AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + MACROBLOCK *const x = &td->mb; + MACROBLOCKD *const xd = &x->e_mbd; + + 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 + if (cpi->sf.inter_sf.disable_sb_level_coeff_cost_upd && + mi_col != tile_info->mi_col_start) + break; + 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); + } + switch (cpi->oxcf.mv_cost_upd_freq) { + case COST_UPD_OFF: break; + 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 + if (cpi->sf.inter_sf.disable_sb_level_mv_cost_upd && + mi_col != tile_info->mi_col_start) + break; + av1_fill_mv_costs(xd->tile_ctx, cm->features.cur_frame_force_integer_mv, + cm->features.allow_high_precision_mv, x); + break; + default: assert(0); + } +} + static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, TileDataEnc *tile_data, int mi_row, - TOKENEXTRA **tp, int use_nonrd_mode) { + TOKENEXTRA **tp) { AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); const TileInfo *const tile_info = &tile_data->tile_info; MACROBLOCK *const x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; - const SPEED_FEATURES *const sf = &cpi->sf; const int sb_cols_in_tile = av1_get_sb_cols_in_tile(cm, tile_data->tile_info); const BLOCK_SIZE sb_size = cm->seq_params.sb_size; const int mib_size = cm->seq_params.mib_size; 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; - int sb_mi_size = av1_get_sb_mi_size(cm); + const int use_nonrd_mode = cpi->sf.rt_sf.use_nonrd_pick_mode; #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, encode_sb_time); @@ -4146,7 +4900,7 @@ static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, // Reset delta for every tile if (mi_row == tile_info->mi_row_start || cpi->row_mt) { if (cm->delta_q_info.delta_q_present_flag) - xd->current_qindex = cm->base_qindex; + xd->current_qindex = cm->quant_params.base_qindex; if (cm->delta_q_info.delta_lf_present_flag) { av1_reset_loop_filter_delta(xd, av1_num_planes(cm)); } @@ -4156,8 +4910,6 @@ static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, // Code each SB in the row for (int mi_col = tile_info->mi_col_start, sb_col_in_tile = 0; mi_col < tile_info->mi_col_end; mi_col += mib_size, sb_col_in_tile++) { - if (!cpi->sf.use_real_time_ref_set) - memset(x->mbmi_ext, 0, sb_mi_size * sizeof(*x->mbmi_ext)); (*(cpi->row_mt_sync_read_ptr))(&tile_data->row_mt_sync, sb_row, sb_col_in_tile); if (tile_data->allow_update_cdf && (cpi->row_mt == 1) && @@ -4177,182 +4929,38 @@ static AOM_INLINE void encode_sb_row(AV1_COMP *cpi, ThreadData *td, } } - 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 - if (cpi->sf.disable_sb_level_coeff_cost_upd && - mi_col != tile_info->mi_col_start) - break; - av1_fill_coeff_costs(&td->mb, xd->tile_ctx, num_planes); - break; - default: assert(0); - } + set_cost_upd_freq(cpi, td, tile_info, mi_row, mi_col); - 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); - } - switch (cpi->oxcf.mv_cost_upd_freq) { - case COST_UPD_OFF: break; - 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 - if (cpi->sf.disable_sb_level_mv_cost_upd && - mi_col != tile_info->mi_col_start) - break; - av1_fill_mv_costs(xd->tile_ctx, cm->cur_frame_force_integer_mv, - cm->allow_high_precision_mv, x); - break; - default: assert(0); - } - x->mb_rd_record.num = x->mb_rd_record.index_start = 0; x->color_sensitivity[0] = 0; x->color_sensitivity[1] = 0; + x->content_state_sb = 0; - if (cpi->sf.use_inter_txb_hash) { - 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->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_TREE *const pc_root = td->pc_root; pc_root->index = 0; - if ((sf->simple_motion_search_split || - sf->simple_motion_search_prune_rect || - sf->simple_motion_search_early_term_none || - sf->ml_early_term_after_part_split_level) && - !frame_is_intra_only(cm) && !use_nonrd_mode) { - init_simple_motion_search_mvs(pc_root); - } -#if !CONFIG_REALTIME_ONLY - td->mb.cnn_output_valid = 0; -#endif - - xd->cur_frame_force_integer_mv = cm->cur_frame_force_integer_mv; - - x->sb_energy_level = 0; -#if !CONFIG_REALTIME_ONLY - if (cm->delta_q_info.delta_q_present_flag) { - setup_delta_q(cpi, td, x, tile_info, mi_row, mi_col, num_planes); - av1_tpl_rdmult_setup_sb(cpi, x, sb_size, mi_row, mi_col); - } -#endif + xd->cur_frame_force_integer_mv = cm->features.cur_frame_force_integer_mv; td->mb.cb_coef_buff = av1_get_cb_coeff_buffer(cpi, mi_row, mi_col); - - MB_MODE_INFO **mi = cm->mi_grid_base + get_mi_grid_idx(cm, mi_row, mi_col); x->source_variance = UINT_MAX; x->simple_motion_pred_sse = UINT_MAX; + const struct segmentation *const seg = &cm->seg; int seg_skip = 0; if (seg->enabled) { const uint8_t *const map = - seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; + seg->update_map ? cpi->enc_seg.map : cm->last_frame_seg_map; const int segment_id = - map ? get_segment_id(cm, map, sb_size, mi_row, mi_col) : 0; + map ? get_segment_id(&cm->mi_params, map, sb_size, mi_row, mi_col) + : 0; seg_skip = segfeature_active(seg, segment_id, SEG_LVL_SKIP); } - // Realtime non-rd path. - if (!(sf->partition_search_type == FIXED_PARTITION || seg_skip) && - !cpi->partition_search_skippable_frame && - sf->partition_search_type == VAR_BASED_PARTITION) { - set_offsets_without_segment_id(cpi, tile_info, x, mi_row, mi_col, - sb_size); - av1_choose_var_based_partitioning(cpi, tile_info, x, mi_row, mi_col); - td->mb.cb_offset = 0; - if (use_nonrd_mode) { - nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, - pc_root); - } else { - int dummy_rate; - int64_t dummy_dist; - rd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size, - &dummy_rate, &dummy_dist, 1, pc_root); - } + if (use_nonrd_mode) { + encode_nonrd_sb(cpi, td, tile_data, pc_root, tp, mi_row, mi_col, + seg_skip); } else { -#if !CONFIG_REALTIME_ONLY - int dummy_rate; - int64_t dummy_dist; - RD_STATS dummy_rdc; - av1_invalid_rd_stats(&dummy_rdc); - adjust_rdmult_tpl_model(cpi, x, mi_row, mi_col); - 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; - 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 (cpi->partition_search_skippable_frame) { - set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size); - const BLOCK_SIZE bsize = - get_rd_var_based_fixed_partition(cpi, x, mi_row, mi_col); - 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 { - x->valid_cost_b = 0; - // No stats for overlay frames. Exclude key frame. - x->valid_cost_b = - get_tpl_stats_b(cpi, cm->seq_params.sb_size, mi_row, mi_col, - x->intra_cost_b, x->inter_cost_b, &x->cost_stride); - - reset_partition(pc_root, sb_size); - -#if CONFIG_COLLECT_COMPONENT_TIMING - start_timing(cpi, rd_pick_partition_time); -#endif - BLOCK_SIZE max_sq_size = x->max_partition_size; - BLOCK_SIZE min_sq_size = x->min_partition_size; - - 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, - max_sq_size, min_sq_size, &dummy_rdc, dummy_rdc, - pc_root, NULL); -#if CONFIG_COLLECT_COMPONENT_TIMING - end_timing(cpi, rd_pick_partition_time); -#endif - } -#endif // !CONFIG_REALTIME_ONLY + encode_rd_sb(cpi, td, tile_data, pc_root, tp, mi_row, mi_col, seg_skip); } - // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile. - if (!use_nonrd_mode && cpi->sf.inter_mode_rd_model_estimation == 1 && - cm->tile_cols == 1 && cm->tile_rows == 1) { - av1_inter_mode_data_fit(tile_data, x->rdmult); - } if (tile_data->allow_update_cdf && (cpi->row_mt == 1) && (tile_info->mi_row_end > (mi_row + mib_size))) { if (sb_cols_in_tile == 1) @@ -4385,21 +4993,22 @@ static AOM_INLINE void init_encode_frame_mb_context(AV1_COMP *cpi) { void av1_alloc_tile_data(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; if (cpi->tile_data != NULL) aom_free(cpi->tile_data); CHECK_MEM_ERROR( cm, cpi->tile_data, aom_memalign(32, tile_cols * tile_rows * sizeof(*cpi->tile_data))); + cpi->allocated_tiles = tile_cols * tile_rows; } void av1_init_tile_data(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int tile_col, tile_row; TOKENEXTRA *pre_tok = cpi->tile_tok[0][0]; TOKENLIST *tplist = cpi->tplist[0][0]; @@ -4420,9 +5029,9 @@ void av1_init_tile_data(AV1_COMP *cpi) { cpi->tplist[tile_row][tile_col] = tplist + tplist_count; tplist = cpi->tplist[tile_row][tile_col]; tplist_count = av1_get_sb_rows_in_tile(cm, tile_data->tile_info); - tile_data->allow_update_cdf = !cm->large_scale_tile; + tile_data->allow_update_cdf = !cm->tiles.large_scale; tile_data->allow_update_cdf = - tile_data->allow_update_cdf && !cm->disable_cdf_update; + tile_data->allow_update_cdf && !cm->features.disable_cdf_update; tile_data->tctx = *cm->fc; } } @@ -4432,7 +5041,7 @@ void av1_encode_sb_row(AV1_COMP *cpi, ThreadData *td, int tile_row, int tile_col, int mi_row) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - const int tile_cols = cm->tile_cols; + const int tile_cols = cm->tiles.cols; TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col]; const TileInfo *const tile_info = &this_tile->tile_info; TOKENEXTRA *tok = NULL; @@ -4447,7 +5056,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_sb_row(cpi, td, this_tile, mi_row, &tok, cpi->sf.use_nonrd_pick_mode); + encode_sb_row(cpi, td, this_tile, mi_row, &tok); cpi->tplist[tile_row][tile_col][sb_row_in_tile].stop = tok; cpi->tplist[tile_row][tile_col][sb_row_in_tile].count = @@ -4468,27 +5077,21 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row, int tile_col) { AV1_COMMON *const cm = &cpi->common; TileDataEnc *const this_tile = - &cpi->tile_data[tile_row * cm->tile_cols + tile_col]; + &cpi->tile_data[tile_row * cm->tiles.cols + tile_col]; const TileInfo *const tile_info = &this_tile->tile_info; - int mi_row; - if (!cpi->sf.use_fast_nonrd_pick_mode) av1_inter_mode_data_init(this_tile); + if (!cpi->sf.rt_sf.use_nonrd_pick_mode) av1_inter_mode_data_init(this_tile); av1_zero_above_context(cm, &td->mb.e_mbd, tile_info->mi_col_start, tile_info->mi_col_end, tile_row); - av1_init_above_context(cm, &td->mb.e_mbd, tile_row); - - // Set up pointers to per thread motion search counters. - this_tile->m_search_count = 0; // Count of motion search hits. - this_tile->ex_search_count = 0; // Exhaustive mesh search hits. - td->mb.m_search_count_ptr = &this_tile->m_search_count; - td->mb.ex_search_count_ptr = &this_tile->ex_search_count; + av1_init_above_context(&cm->above_contexts, av1_num_planes(cm), tile_row, + &td->mb.e_mbd); if (cpi->oxcf.enable_cfl_intra) cfl_init(&td->mb.e_mbd.cfl, &cm->seq_params); av1_crc32c_calculator_init(&td->mb.mb_rd_record.crc_calculator); - for (mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end; + for (int mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end; mi_row += cm->seq_params.mib_size) { av1_encode_sb_row(cpi, td, tile_row, tile_col, mi_row); } @@ -4496,8 +5099,8 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row, static AOM_INLINE void encode_tiles(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int tile_col, tile_row; if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) @@ -4508,7 +5111,7 @@ static AOM_INLINE void encode_tiles(AV1_COMP *cpi) { for (tile_row = 0; tile_row < tile_rows; ++tile_row) { for (tile_col = 0; tile_col < tile_cols; ++tile_col) { TileDataEnc *const this_tile = - &cpi->tile_data[tile_row * cm->tile_cols + tile_col]; + &cpi->tile_data[tile_row * cm->tiles.cols + tile_col]; cpi->td.intrabc_used = 0; cpi->td.deltaq_used = 0; cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx; @@ -4572,7 +5175,7 @@ static int gm_get_params_cost(const WarpedMotionParams *gm, static int do_gm_search_logic(SPEED_FEATURES *const sf, int frame) { (void)frame; - switch (sf->gm_search_type) { + switch (sf->gm_sf.gm_search_type) { case GM_FULL_SEARCH: return 1; case GM_REDUCED_REF_SEARCH_SKIP_L2_L3: return !(frame == LAST2_FRAME || frame == LAST3_FRAME); @@ -4615,40 +5218,7 @@ static AOM_INLINE void set_rel_frame_dist(AV1_COMP *cpi) { } } -// Enforce the number of references for each arbitrary frame based on user -// options and speed. -static AOM_INLINE void enforce_max_ref_frames(AV1_COMP *cpi) { - 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 & av1_ref_frame_flag_list[ref_frame]) { - total_valid_refs++; - } - } - - const int max_allowed_refs = get_max_allowed_ref_frames(cpi); - - for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) { - const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i]; - - if (!(cpi->ref_frame_flags & - av1_ref_frame_flag_list[ref_frame_to_disable])) { - continue; - } - - switch (ref_frame_to_disable) { - case LAST3_FRAME: cpi->ref_frame_flags &= ~AOM_LAST3_FLAG; break; - case LAST2_FRAME: cpi->ref_frame_flags &= ~AOM_LAST2_FLAG; break; - case ALTREF2_FRAME: cpi->ref_frame_flags &= ~AOM_ALT2_FLAG; 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) { +static INLINE int refs_are_one_sided(const AV1_COMMON *cm) { assert(!frame_is_intra_only(cm)); int one_sided_refs = 1; @@ -4735,19 +5305,20 @@ static INLINE int skip_gm_frame(AV1_COMMON *const cm, int ref_frame) { return 0; } -static AOM_INLINE void set_default_interp_skip_flags(AV1_COMP *cpi) { - const int num_planes = av1_num_planes(&cpi->common); - cpi->default_interp_skip_flags = (num_planes == 1) - ? INTERP_SKIP_LUMA_EVAL_CHROMA - : INTERP_SKIP_LUMA_SKIP_CHROMA; +static AOM_INLINE void set_default_interp_skip_flags( + const AV1_COMMON *cm, InterpSearchFlags *interp_search_flags) { + const int num_planes = av1_num_planes(cm); + interp_search_flags->default_interp_skip_flags = + (num_planes == 1) ? INTERP_SKIP_LUMA_EVAL_CHROMA + : INTERP_SKIP_LUMA_SKIP_CHROMA; } // TODO(Remya): Can include erroradv_prod_tr[] for threshold calculation static INLINE int64_t calc_erroradv_threshold(AV1_COMP *cpi, int64_t ref_frame_error) { - if (!cpi->sf.disable_adaptive_warp_error_thresh) - return (int64_t)(ref_frame_error * erroradv_tr[cpi->sf.gm_erroradv_type] + - 0.5); + if (!cpi->sf.gm_sf.disable_adaptive_warp_error_thresh) + return (int64_t)( + ref_frame_error * erroradv_tr[cpi->sf.gm_sf.gm_erroradv_type] + 0.5); else return INT64_MAX; } @@ -4852,11 +5423,11 @@ static void compute_global_motion_for_ref_frame( if (cm->global_motion[frame].wmtype == TRANSLATION) { cm->global_motion[frame].wmmat[0] = - convert_to_trans_prec(cm->allow_high_precision_mv, + convert_to_trans_prec(cm->features.allow_high_precision_mv, cm->global_motion[frame].wmmat[0]) * GM_TRANS_ONLY_DECODE_FACTOR; cm->global_motion[frame].wmmat[1] = - convert_to_trans_prec(cm->allow_high_precision_mv, + convert_to_trans_prec(cm->features.allow_high_precision_mv, cm->global_motion[frame].wmmat[1]) * GM_TRANS_ONLY_DECODE_FACTOR; } @@ -4870,8 +5441,8 @@ static void compute_global_motion_for_ref_frame( if (!av1_is_enough_erroradvantage( (double)best_warp_error / ref_frame_error, gm_get_params_cost(&cm->global_motion[frame], ref_params, - cm->allow_high_precision_mv), - cpi->sf.gm_erroradv_type)) { + cm->features.allow_high_precision_mv), + cpi->sf.gm_sf.gm_erroradv_type)) { cm->global_motion[frame] = default_warp_params; } @@ -4901,8 +5472,8 @@ static INLINE void update_valid_ref_frames_for_gm( cm->global_motion[frame] = default_warp_params; // Skip global motion estimation for invalid ref frames if (buf == NULL || - (ref_disabled && cpi->sf.recode_loop != DISALLOW_RECODE)) { - cpi->gmparams_cost[frame] = 0; + (ref_disabled && cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE)) { + cpi->gm_info.params_cost[frame] = 0; continue; } else { ref_buf[frame] = &buf->buf; @@ -4912,9 +5483,8 @@ static INLINE void update_valid_ref_frames_for_gm( ref_buf[frame]->y_crop_height == cpi->source->y_crop_height && do_gm_search_logic(&cpi->sf, frame) && !prune_ref_by_selective_ref_frame( - cpi, ref_frame, cm->cur_frame->ref_display_order_hint, - cm->current_frame.display_order_hint) && - !(cpi->sf.selective_ref_gm && skip_gm_frame(cm, frame))) { + cpi, NULL, ref_frame, cm->cur_frame->ref_display_order_hint) && + !(cpi->sf.gm_sf.selective_ref_gm && skip_gm_frame(cm, frame))) { assert(ref_buf[frame] != NULL); int relative_frame_dist = av1_encoder_get_relative_dist( order_hint_info, buf->display_order_hint, @@ -4941,6 +5511,7 @@ static INLINE void compute_gm_for_valid_ref_frames( MotionModel *params_by_motion, uint8_t *segment_map, const int segment_map_w, const int segment_map_h) { AV1_COMMON *const cm = &cpi->common; + GlobalMotionInfo *const gm_info = &cpi->gm_info; const WarpedMotionParams *ref_params = cm->prev_frame ? &cm->prev_frame->global_motion[frame] : &default_warp_params; @@ -4949,11 +5520,11 @@ static INLINE void compute_gm_for_valid_ref_frames( cpi, ref_buf, frame, num_frm_corners, frm_corners, frm_buffer, params_by_motion, segment_map, segment_map_w, segment_map_h, ref_params); - cpi->gmparams_cost[frame] = + gm_info->params_cost[frame] = gm_get_params_cost(&cm->global_motion[frame], ref_params, - cm->allow_high_precision_mv) + - cpi->gmtype_cost[cm->global_motion[frame].wmtype] - - cpi->gmtype_cost[IDENTITY]; + cm->features.allow_high_precision_mv) + + gm_info->type_cost[cm->global_motion[frame].wmtype] - + gm_info->type_cost[IDENTITY]; } static int compare_distance(const void *a, const void *b) { @@ -4985,51 +5556,122 @@ static INLINE void compute_global_motion_for_references( // the remaining ref frames in that direction. The below exit is disabled // when ref frame distance w.r.t. current frame is zero. E.g.: // source_alt_ref_frame w.r.t. ARF frames - if (cpi->sf.prune_ref_frame_for_gm_search && + if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search && reference_frame[frame].distance != 0 && cm->global_motion[ref_frame].wmtype != ROTZOOM) break; } } +static AOM_INLINE void setup_prune_ref_frame_mask(AV1_COMP *cpi) { + if (!cpi->sf.rt_sf.use_nonrd_pick_mode && + cpi->sf.inter_sf.selective_ref_frame >= 2) { + AV1_COMMON *const cm = &cpi->common; + const OrderHintInfo *const order_hint_info = + &cm->seq_params.order_hint_info; + const int cur_frame_display_order_hint = + cm->current_frame.display_order_hint; + unsigned int *ref_display_order_hint = + cm->cur_frame->ref_display_order_hint; + const int arf2_dist = av1_encoder_get_relative_dist( + order_hint_info, ref_display_order_hint[ALTREF2_FRAME - LAST_FRAME], + cur_frame_display_order_hint); + const int bwd_dist = av1_encoder_get_relative_dist( + order_hint_info, ref_display_order_hint[BWDREF_FRAME - LAST_FRAME], + cur_frame_display_order_hint); + + for (int ref_idx = REF_FRAMES; ref_idx < MODE_CTX_REF_FRAMES; ++ref_idx) { + MV_REFERENCE_FRAME rf[2]; + av1_set_ref_frame(rf, ref_idx); + if (!(cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[0]]) || + !(cpi->ref_frame_flags & av1_ref_frame_flag_list[rf[1]])) { + continue; + } + + if (!cpi->all_one_sided_refs) { + int ref_dist[2]; + for (int i = 0; i < 2; ++i) { + ref_dist[i] = av1_encoder_get_relative_dist( + order_hint_info, ref_display_order_hint[rf[i] - LAST_FRAME], + cur_frame_display_order_hint); + } + + // One-sided compound is used only when all reference frames are + // one-sided. + if ((ref_dist[0] > 0) == (ref_dist[1] > 0)) { + cpi->prune_ref_frame_mask |= 1 << ref_idx; + } + } + + if (cpi->sf.inter_sf.selective_ref_frame >= 4 && + (rf[0] == ALTREF2_FRAME || rf[1] == ALTREF2_FRAME) && + (cpi->ref_frame_flags & av1_ref_frame_flag_list[BWDREF_FRAME])) { + // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references. + if (arf2_dist > 0 && bwd_dist > 0 && bwd_dist <= arf2_dist) { + // Drop ALTREF2_FRAME as a reference if BWDREF_FRAME is a closer + // reference to the current frame than ALTREF2_FRAME + cpi->prune_ref_frame_mask |= 1 << ref_idx; + } + } + } + } +} + +#define CHECK_PRECOMPUTED_REF_FRAME_MAP 0 + static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { ThreadData *const td = &cpi->td; MACROBLOCK *const x = &td->mb; AV1_COMMON *const cm = &cpi->common; + CommonModeInfoParams *const mi_params = &cm->mi_params; + FeatureFlags *const features = &cm->features; MACROBLOCKD *const xd = &x->e_mbd; RD_COUNTS *const rdc = &cpi->td.rd_counts; + GlobalMotionInfo *const gm_info = &cpi->gm_info; + FrameProbInfo *const frame_probs = &cpi->frame_probs; + IntraBCHashInfo *const intrabc_hash_info = &x->intrabc_hash_info; int i; -#if CONFIG_DIST_8X8 - x->using_dist_8x8 = cpi->oxcf.using_dist_8x8; - x->tune_metric = cpi->oxcf.tuning; -#endif - - if (!cpi->sf.use_nonrd_pick_mode) { - cm->setup_mi(cm); + if (!cpi->sf.rt_sf.use_nonrd_pick_mode) { + mi_params->setup_mi(mi_params); } - xd->mi = cm->mi_grid_base; - xd->mi[0] = cm->mi; - xd->tx_type_map = cm->tx_type_map; - xd->tx_type_map_stride = cm->mi_stride; + set_mi_offsets(mi_params, xd, 0, 0); + +#if CONFIG_AV1_HIGHBITDEPTH + x->fwd_txfm4x4 = aom_fdct4x4; +#else + x->fwd_txfm4x4 = aom_fdct4x4_lp; +#endif av1_zero(*td->counts); av1_zero(rdc->comp_pred_diff); av1_zero(rdc->tx_type_used); av1_zero(rdc->obmc_used); + av1_zero(rdc->warped_used); // Reset the flag. cpi->intrabc_used = 0; // Need to disable intrabc when superres is selected if (av1_superres_scaled(cm)) { - cm->allow_intrabc = 0; + features->allow_intrabc = 0; } - cm->allow_intrabc &= (cpi->oxcf.enable_intrabc); + features->allow_intrabc &= (cpi->oxcf.enable_intrabc); - if (cpi->oxcf.pass != 1 && av1_use_hash_me(cm) && - !cpi->sf.use_nonrd_pick_mode) { + if (features->allow_warped_motion && + cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { + const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); + if (frame_probs->warped_probs[update_type] < + cpi->sf.inter_sf.prune_warped_prob_thresh) + features->allow_warped_motion = 0; + } + + int hash_table_created = 0; + if (!is_stat_generation_stage(cpi) && av1_use_hash_me(cpi) && + !cpi->sf.rt_sf.use_nonrd_pick_mode) { + // TODO(any): move this outside of the recoding loop to avoid recalculating + // the hash table. // add to hash table const int pic_width = cpi->source->y_crop_width; const int pic_height = cpi->source->y_crop_height; @@ -5049,33 +5691,25 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { } } -#if CONFIG_DEBUG - cm->cur_frame->hash_table.has_content++; -#endif - av1_hash_table_create(&cm->cur_frame->hash_table); - av1_generate_block_2x2_hash_value(cpi->source, block_hash_values[0], - is_block_same[0], &cpi->td.mb); - // Hash data generated for screen contents is used for the following: - // 1. intraBC ME - // 2. Calculation of cm->cur_frame_force_integer_mv - // As the calculation of cm->cur_frame_force_integer_mv is limited to 8x8 - // block size, for non-intra frames, max_size for hash calculation can be - // limited to 8x8 - // TODO(any): Adjust max_size based on superblock size for intra frames - const int max_size = - frame_is_intra_only(cm) ? 128 : FORCE_INT_MV_DECISION_BLOCK_SIZE; - const int min_size = 4; - const int min_alloc_size = block_size_wide[cm->mi_alloc_bsize]; + av1_hash_table_init(intrabc_hash_info); + av1_hash_table_create(&intrabc_hash_info->intrabc_hash_table); + hash_table_created = 1; + av1_generate_block_2x2_hash_value(intrabc_hash_info, cpi->source, + block_hash_values[0], is_block_same[0]); + // Hash data generated for screen contents is used for intraBC ME + const int min_alloc_size = block_size_wide[mi_params->mi_alloc_bsize]; + const int max_sb_size = + (1 << (cm->seq_params.mib_size_log2 + MI_SIZE_LOG2)); int src_idx = 0; - for (int size = min_size; size <= max_size; size *= 2, src_idx = !src_idx) { + for (int size = 4; size <= max_sb_size; size *= 2, src_idx = !src_idx) { const int dst_idx = !src_idx; av1_generate_block_hash_value( - cpi->source, size, block_hash_values[src_idx], + intrabc_hash_info, cpi->source, size, block_hash_values[src_idx], block_hash_values[dst_idx], is_block_same[src_idx], - is_block_same[dst_idx], &cpi->td.mb); + is_block_same[dst_idx]); if (size >= min_alloc_size) { av1_add_to_hash_map_by_row_with_precal_data( - &cm->cur_frame->hash_table, block_hash_values[dst_idx], + &intrabc_hash_info->intrabc_hash_table, block_hash_values[dst_idx], is_block_same[dst_idx][2], pic_width, pic_height, size); } } @@ -5091,25 +5725,25 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { } } + const CommonQuantParams *quant_params = &cm->quant_params; for (i = 0; i < MAX_SEGMENTS; ++i) { - const int qindex = cm->seg.enabled - ? av1_get_qindex(&cm->seg, i, cm->base_qindex) - : cm->base_qindex; - xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 && - cm->u_dc_delta_q == 0 && cm->u_ac_delta_q == 0 && - cm->v_dc_delta_q == 0 && cm->v_ac_delta_q == 0; - if (xd->lossless[i]) cpi->has_lossless_segment = 1; + const int qindex = + cm->seg.enabled ? av1_get_qindex(&cm->seg, i, quant_params->base_qindex) + : quant_params->base_qindex; + xd->lossless[i] = + qindex == 0 && quant_params->y_dc_delta_q == 0 && + quant_params->u_dc_delta_q == 0 && quant_params->u_ac_delta_q == 0 && + quant_params->v_dc_delta_q == 0 && quant_params->v_ac_delta_q == 0; + if (xd->lossless[i]) cpi->enc_seg.has_lossless_segment = 1; xd->qindex[i] = qindex; if (xd->lossless[i]) { - cpi->optimize_seg_arr[i] = 0; + cpi->optimize_seg_arr[i] = NO_TRELLIS_OPT; } else { - cpi->optimize_seg_arr[i] = cpi->sf.optimize_coefficients; + cpi->optimize_seg_arr[i] = cpi->sf.rd_sf.optimize_coefficients; } } - cm->coded_lossless = is_coded_lossless(cm, xd); - cm->all_lossless = cm->coded_lossless && !av1_superres_scaled(cm); - - cm->tx_mode = get_eval_tx_mode(cpi, DEFAULT_EVAL); + features->coded_lossless = is_coded_lossless(cm, xd); + features->all_lossless = features->coded_lossless && !av1_superres_scaled(cm); // Fix delta q resolution for the moment cm->delta_q_info.delta_q_res = 0; @@ -5140,20 +5774,20 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { // update delta_q_present_flag and delta_lf_present_flag based on // base_qindex - cm->delta_q_info.delta_q_present_flag &= cm->base_qindex > 0; - cm->delta_q_info.delta_lf_present_flag &= cm->base_qindex > 0; + cm->delta_q_info.delta_q_present_flag &= quant_params->base_qindex > 0; + cm->delta_q_info.delta_lf_present_flag &= quant_params->base_qindex > 0; av1_frame_init_quantizer(cpi); av1_initialize_rd_consts(cpi); - av1_initialize_me_consts(cpi, x, cm->base_qindex); + av1_initialize_me_consts(cpi, x, quant_params->base_qindex); init_encode_frame_mb_context(cpi); - set_default_interp_skip_flags(cpi); + set_default_interp_skip_flags(cm, &cpi->interp_search_flags); if (cm->prev_frame && cm->prev_frame->seg.enabled) cm->last_frame_seg_map = cm->prev_frame->seg_map; else cm->last_frame_seg_map = NULL; - if (cm->allow_intrabc || cm->coded_lossless) { + if (features->allow_intrabc || features->coded_lossless) { av1_set_default_ref_deltas(cm->lf.ref_deltas); av1_set_default_mode_deltas(cm->lf.mode_deltas); } else if (cm->prev_frame) { @@ -5163,6 +5797,13 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { memcpy(cm->cur_frame->ref_deltas, cm->lf.ref_deltas, REF_FRAMES); memcpy(cm->cur_frame->mode_deltas, cm->lf.mode_deltas, MAX_MODE_LF_DELTAS); + cpi->all_one_sided_refs = + frame_is_intra_only(cm) ? 0 : refs_are_one_sided(cm); + + cpi->prune_ref_frame_mask = 0; + // Figure out which ref frames can be skipped at frame level. + setup_prune_ref_frame_mask(cpi); + x->txb_split_count = 0; #if CONFIG_SPEED_STATS x->tx_search_count = 0; @@ -5172,9 +5813,9 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { start_timing(cpi, av1_compute_global_motion_time); #endif av1_zero(rdc->global_motion_used); - av1_zero(cpi->gmparams_cost); + av1_zero(gm_info->params_cost); if (cpi->common.current_frame.frame_type == INTER_FRAME && cpi->source && - cpi->oxcf.enable_global_motion && !cpi->global_motion_search_done) { + cpi->oxcf.enable_global_motion && !gm_info->search_done) { YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES]; MotionModel params_by_motion[RANSAC_NUM_MOTIONS]; for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { @@ -5242,7 +5883,7 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { aom_free(segment_map); - cpi->global_motion_search_done = 1; + gm_info->search_done = 1; for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { aom_free(params_by_motion[m].inliers); } @@ -5256,14 +5897,11 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, av1_setup_motion_field_time); #endif - if (cm->allow_ref_frame_mvs) av1_setup_motion_field(cm); + if (features->allow_ref_frame_mvs) 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); - cm->current_frame.skip_mode_info.skip_mode_flag = check_skip_mode_enabled(cpi); @@ -5277,24 +5915,35 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { cpi->row_mt_sync_write_ptr = av1_row_mt_sync_write; av1_encode_tiles_row_mt(cpi); } else { - if (AOMMIN(cpi->oxcf.max_threads, cm->tile_cols * cm->tile_rows) > 1) + if (AOMMIN(cpi->oxcf.max_threads, cm->tiles.cols * cm->tiles.rows) > 1) av1_encode_tiles_mt(cpi); else encode_tiles(cpi); } // If intrabc is allowed but never selected, reset the allow_intrabc flag. - if (cm->allow_intrabc && !cpi->intrabc_used) cm->allow_intrabc = 0; - if (cm->allow_intrabc) cm->delta_q_info.delta_lf_present_flag = 0; + if (features->allow_intrabc && !cpi->intrabc_used) { + features->allow_intrabc = 0; + } + if (features->allow_intrabc) { + cm->delta_q_info.delta_lf_present_flag = 0; + } if (cm->delta_q_info.delta_q_present_flag && cpi->deltaq_used == 0) { cm->delta_q_info.delta_q_present_flag = 0; } // Set the transform size appropriately before bitstream creation - cm->tx_mode = get_eval_tx_mode(cpi, WINNER_MODE_EVAL); + const MODE_EVAL_TYPE eval_type = + cpi->sf.winner_mode_sf.enable_winner_mode_for_tx_size_srch + ? WINNER_MODE_EVAL + : DEFAULT_EVAL; + const TX_SIZE_SEARCH_METHOD tx_search_type = + cpi->winner_mode_params.tx_size_search_methods[eval_type]; + assert(cpi->oxcf.enable_tx64 || tx_search_type != USE_LARGESTALL); + features->tx_mode = select_tx_mode(cm, tx_search_type); - if (cpi->sf.tx_type_search.prune_tx_type_using_stats) { + if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) { const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); for (i = 0; i < TX_SIZES_ALL; i++) { @@ -5303,50 +5952,96 @@ static AOM_INLINE void encode_frame_internal(AV1_COMP *cpi) { int left = 1024; for (j = 0; j < TX_TYPES; j++) - sum += cpi->td.rd_counts.tx_type_used[update_type][i][j]; + sum += cpi->td.rd_counts.tx_type_used[i][j]; for (j = TX_TYPES - 1; j >= 0; j--) { - int new_prob = - sum ? 1024 * cpi->td.rd_counts.tx_type_used[update_type][i][j] / sum + const int new_prob = + sum ? 1024 * cpi->td.rd_counts.tx_type_used[i][j] / sum : (j ? 0 : 1024); - int prob = (cpi->tx_type_probs[update_type][i][j] + new_prob) >> 1; + int prob = + (frame_probs->tx_type_probs[update_type][i][j] + new_prob) >> 1; left -= prob; if (j == 0) prob += left; - cpi->tx_type_probs[update_type][i][j] = prob; + frame_probs->tx_type_probs[update_type][i][j] = prob; } } } - if (cpi->sf.prune_obmc_using_stats) { + if (!cpi->sf.inter_sf.disable_obmc && + cpi->sf.inter_sf.prune_obmc_prob_thresh > 0) { const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); for (i = 0; i < BLOCK_SIZES_ALL; i++) { int sum = 0; for (int j = 0; j < 2; j++) sum += cpi->td.rd_counts.obmc_used[i][j]; - int new_prob = sum ? 128 * cpi->td.rd_counts.obmc_used[i][1] / sum : 0; - cpi->obmc_probs[update_type][i] = - (cpi->obmc_probs[update_type][i] + new_prob) >> 1; + const int new_prob = + sum ? 128 * cpi->td.rd_counts.obmc_used[i][1] / sum : 0; + frame_probs->obmc_probs[update_type][i] = + (frame_probs->obmc_probs[update_type][i] + new_prob) >> 1; } } -} -#define CHECK_PRECOMPUTED_REF_FRAME_MAP 0 + if (features->allow_warped_motion && + cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { + const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); + int sum = 0; + for (i = 0; i < 2; i++) sum += cpi->td.rd_counts.warped_used[i]; + const int new_prob = sum ? 128 * cpi->td.rd_counts.warped_used[1] / sum : 0; + frame_probs->warped_probs[update_type] = + (frame_probs->warped_probs[update_type] + new_prob) >> 1; + } + + if (cm->current_frame.frame_type != KEY_FRAME && + cpi->sf.interp_sf.adaptive_interp_filter_search == 2 && + features->interp_filter == SWITCHABLE) { + const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); + + for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) { + int sum = 0; + int j; + int left = 1536; + + for (j = 0; j < SWITCHABLE_FILTERS; j++) { + sum += cpi->td.counts->switchable_interp[i][j]; + } + + for (j = SWITCHABLE_FILTERS - 1; j >= 0; j--) { + const int new_prob = + sum ? 1536 * cpi->td.counts->switchable_interp[i][j] / sum + : (j ? 0 : 1536); + int prob = (frame_probs->switchable_interp_probs[update_type][i][j] + + new_prob) >> + 1; + left -= prob; + if (j == 0) prob += left; + frame_probs->switchable_interp_probs[update_type][i][j] = prob; + } + } + } + + if ((!is_stat_generation_stage(cpi) && av1_use_hash_me(cpi) && + !cpi->sf.rt_sf.use_nonrd_pick_mode) || + hash_table_created) { + av1_hash_table_destroy(&intrabc_hash_info->intrabc_hash_table); + } +} void av1_encode_frame(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; CurrentFrame *const current_frame = &cm->current_frame; + FeatureFlags *const features = &cm->features; const int num_planes = av1_num_planes(cm); // Indicates whether or not to use a default reduced set for ext-tx // rather than the potential full set of 16 transforms - cm->reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set; + features->reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set; // Make sure segment_id is no larger than last_active_segid. if (cm->seg.enabled && cm->seg.update_map) { - const int mi_rows = cm->mi_rows; - const int mi_cols = cm->mi_cols; + const int mi_rows = cm->mi_params.mi_rows; + const int mi_cols = cm->mi_params.mi_cols; const int last_active_segid = cm->seg.last_active_segid; - uint8_t *map = cpi->segmentation_map; + uint8_t *map = cpi->enc_seg.map; for (int mi_row = 0; mi_row < mi_rows; ++mi_row) { for (int mi_col = 0; mi_col < mi_cols; ++mi_col) { map[mi_col] = AOMMIN(map[mi_col], last_active_segid); @@ -5356,7 +6051,7 @@ void av1_encode_frame(AV1_COMP *cpi) { } av1_setup_frame_buf_refs(cm); - enforce_max_ref_frames(cpi); + enforce_max_ref_frames(cpi, &cpi->ref_frame_flags); set_rel_frame_dist(cpi); av1_setup_frame_sign_bias(cm); @@ -5403,7 +6098,7 @@ void av1_encode_frame(AV1_COMP *cpi) { (void)num_planes; #endif - if (cpi->sf.frame_parameter_update) { + if (cpi->sf.hl_sf.frame_parameter_update) { RD_COUNTS *const rdc = &cpi->td.rd_counts; if (frame_is_intra_only(cm)) @@ -5411,10 +6106,10 @@ void av1_encode_frame(AV1_COMP *cpi) { else current_frame->reference_mode = REFERENCE_MODE_SELECT; - cm->interp_filter = SWITCHABLE; - if (cm->large_scale_tile) cm->interp_filter = EIGHTTAP_REGULAR; + features->interp_filter = SWITCHABLE; + if (cm->tiles.large_scale) features->interp_filter = EIGHTTAP_REGULAR; - cm->switchable_motion_mode = 1; + features->switchable_motion_mode = 1; rdc->compound_ref_used_flag = 0; rdc->skip_mode_used_flag = 0; @@ -5441,9 +6136,10 @@ void av1_encode_frame(AV1_COMP *cpi) { if (skip_mode_info->skip_mode_flag && rdc->skip_mode_used_flag == 0) skip_mode_info->skip_mode_flag = 0; - if (!cm->large_scale_tile) { - if (cm->tx_mode == TX_MODE_SELECT && cpi->td.mb.txb_split_count == 0) - cm->tx_mode = TX_MODE_LARGEST; + if (!cm->tiles.large_scale) { + if (features->tx_mode == TX_MODE_SELECT && + cpi->td.mb.txb_split_count == 0) + features->tx_mode = TX_MODE_LARGEST; } } else { encode_frame_internal(cpi); @@ -5516,25 +6212,29 @@ static AOM_INLINE void update_txfm_count(MACROBLOCK *x, MACROBLOCKD *xd, } } -static AOM_INLINE void tx_partition_count_update( - const AV1_COMMON *const cm, MACROBLOCK *x, BLOCK_SIZE plane_bsize, - int mi_row, int mi_col, FRAME_COUNTS *td_counts, uint8_t allow_update_cdf) { +static AOM_INLINE void tx_partition_count_update(const AV1_COMMON *const cm, + MACROBLOCK *x, + BLOCK_SIZE plane_bsize, + FRAME_COUNTS *td_counts, + uint8_t allow_update_cdf) { MACROBLOCKD *xd = &x->e_mbd; - const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int mi_height = block_size_high[plane_bsize] >> tx_size_high_log2[0]; + const int mi_width = mi_size_wide[plane_bsize]; + const int mi_height = mi_size_high[plane_bsize]; const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, 0); const int bh = tx_size_high_unit[max_tx_size]; const int bw = tx_size_wide_unit[max_tx_size]; - int idx, idy; - xd->above_txfm_context = cm->above_txfm_context[xd->tile.tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[xd->tile.tile_row] + xd->mi_col; xd->left_txfm_context = - xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + xd->left_txfm_context_buffer + (xd->mi_row & MAX_MIB_MASK); - for (idy = 0; idy < mi_height; idy += bh) - for (idx = 0; idx < mi_width; idx += bw) + for (int idy = 0; idy < mi_height; idy += bh) { + for (int idx = 0; idx < mi_width; idx += bw) { update_txfm_count(x, xd, td_counts, max_tx_size, 0, idy, idx, allow_update_cdf); + } + } } static AOM_INLINE void set_txfm_context(MACROBLOCKD *xd, TX_SIZE tx_size, @@ -5577,28 +6277,28 @@ static AOM_INLINE void set_txfm_context(MACROBLOCKD *xd, TX_SIZE tx_size, static AOM_INLINE void tx_partition_set_contexts(const AV1_COMMON *const cm, MACROBLOCKD *xd, - BLOCK_SIZE plane_bsize, - int mi_row, int mi_col) { - const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int mi_height = block_size_high[plane_bsize] >> tx_size_high_log2[0]; + BLOCK_SIZE plane_bsize) { + const int mi_width = mi_size_wide[plane_bsize]; + const int mi_height = mi_size_high[plane_bsize]; const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, 0); const int bh = tx_size_high_unit[max_tx_size]; const int bw = tx_size_wide_unit[max_tx_size]; - int idx, idy; - xd->above_txfm_context = cm->above_txfm_context[xd->tile.tile_row] + mi_col; + xd->above_txfm_context = + cm->above_contexts.txfm[xd->tile.tile_row] + xd->mi_col; xd->left_txfm_context = - xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); + xd->left_txfm_context_buffer + (xd->mi_row & MAX_MIB_MASK); - for (idy = 0; idy < mi_height; idy += bh) - for (idx = 0; idx < mi_width; idx += bw) + for (int idy = 0; idy < mi_height; idy += bh) { + for (int idx = 0; idx < mi_width; idx += bw) { set_txfm_context(xd, max_tx_size, idy, idx); + } + } } static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, TileDataEnc *tile_data, ThreadData *td, TOKENEXTRA **t, RUN_TYPE dry_run, - int mi_row, int mi_col, BLOCK_SIZE bsize, int *rate) { const AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); @@ -5608,35 +6308,35 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, MB_MODE_INFO *mbmi = mi_4x4[0]; const int seg_skip = segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP); - const int mis = cm->mi_stride; + const int mis = cm->mi_params.mi_stride; const int mi_width = mi_size_wide[bsize]; const int mi_height = mi_size_high[bsize]; const int is_inter = is_inter_block(mbmi); // Initialize tx_mode and tx_size_search_method - set_tx_size_search_method(cpi, x, cpi->sf.enable_winner_mode_for_tx_size_srch, - 1); + set_tx_size_search_method( + cm, &cpi->winner_mode_params, x, + cpi->sf.winner_mode_sf.enable_winner_mode_for_tx_size_srch, 1); + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (!is_inter) { - xd->cfl.is_chroma_reference = - is_chroma_reference(mi_row, mi_col, bsize, cm->seq_params.subsampling_x, - cm->seq_params.subsampling_y); xd->cfl.store_y = store_cfl_required(cm, xd); mbmi->skip = 1; for (int plane = 0; plane < num_planes; ++plane) { - av1_encode_intra_block_plane(cpi, x, bsize, plane, - cpi->optimize_seg_arr[mbmi->segment_id], - mi_row, mi_col); + av1_encode_intra_block_plane(cpi, x, bsize, plane, dry_run, + cpi->optimize_seg_arr[mbmi->segment_id]); } // If there is at least one lossless segment, force the skip for intra // block to be 0, in order to avoid the segment_id to be changed by in // write_segment_id(). if (!cpi->common.seg.segid_preskip && cpi->common.seg.update_map && - cpi->has_lossless_segment) + cpi->enc_seg.has_lossless_segment) mbmi->skip = 0; xd->cfl.store_y = 0; - if (av1_allow_palette(cm->allow_screen_content_tools, bsize)) { + if (av1_allow_palette(cm->features.allow_screen_content_tools, bsize)) { for (int plane = 0; plane < AOMMIN(2, num_planes); ++plane) { if (mbmi->palette_mode_info.palette_size[plane] > 0) { if (!dry_run) { @@ -5651,7 +6351,7 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, } } - av1_update_txb_context(cpi, td, dry_run, bsize, rate, mi_row, mi_col, + av1_update_txb_context(cpi, td, dry_run, bsize, tile_data->allow_update_cdf); } else { int ref; @@ -5665,12 +6365,12 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, xd->block_ref_scale_factors[ref], num_planes); } - int start_plane = (cpi->sf.reuse_inter_pred_nonrd) ? 1 : 0; + int start_plane = (cpi->sf.rt_sf.reuse_inter_pred_nonrd) ? 1 : 0; av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, start_plane, av1_num_planes(cm) - 1); if (mbmi->motion_mode == OBMC_CAUSAL) { assert(cpi->oxcf.enable_obmc == 1); - av1_build_obmc_inter_predictors_sb(cm, xd, mi_row, mi_col); + av1_build_obmc_inter_predictors_sb(cm, xd); } #if CONFIG_MISMATCH_DEBUG @@ -5693,17 +6393,18 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, (void)num_planes; #endif - av1_encode_sb(cpi, x, bsize, mi_row, mi_col, dry_run); - av1_tokenize_sb_vartx(cpi, td, dry_run, mi_row, mi_col, bsize, rate, + av1_encode_sb(cpi, x, bsize, dry_run); + av1_tokenize_sb_vartx(cpi, td, dry_run, bsize, rate, tile_data->allow_update_cdf); } if (!dry_run) { if (av1_allow_intrabc(cm) && is_intrabc_block(mbmi)) td->intrabc_used = 1; - if (x->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id] && - mbmi->sb_type > BLOCK_4X4 && !(is_inter && (mbmi->skip || seg_skip))) { + if (x->tx_mode_search_type == TX_MODE_SELECT && + !xd->lossless[mbmi->segment_id] && mbmi->sb_type > BLOCK_4X4 && + !(is_inter && (mbmi->skip || seg_skip))) { if (is_inter) { - tx_partition_count_update(cm, x, bsize, mi_row, mi_col, td->counts, + tx_partition_count_update(cm, x, bsize, td->counts, tile_data->allow_update_cdf); } else { if (mbmi->tx_size != max_txsize_rect_lookup[bsize]) @@ -5731,7 +6432,7 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, if (xd->lossless[mbmi->segment_id]) { intra_tx_size = TX_4X4; } else { - intra_tx_size = tx_size_from_tx_mode(bsize, x->tx_mode); + intra_tx_size = tx_size_from_tx_mode(bsize, x->tx_mode_search_type); } } else { intra_tx_size = mbmi->tx_size; @@ -5739,17 +6440,18 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, for (j = 0; j < mi_height; j++) for (i = 0; i < mi_width; i++) - if (mi_col + i < cm->mi_cols && mi_row + j < cm->mi_rows) + if (mi_col + i < cm->mi_params.mi_cols && + mi_row + j < cm->mi_params.mi_rows) mi_4x4[mis * j + i]->tx_size = intra_tx_size; if (intra_tx_size != max_txsize_rect_lookup[bsize]) ++x->txb_split_count; } } - if (x->tx_mode == TX_MODE_SELECT && block_signals_txsize(mbmi->sb_type) && - is_inter && !(mbmi->skip || seg_skip) && - !xd->lossless[mbmi->segment_id]) { - if (dry_run) tx_partition_set_contexts(cm, xd, bsize, mi_row, mi_col); + if (x->tx_mode_search_type == TX_MODE_SELECT && + block_signals_txsize(mbmi->sb_type) && is_inter && + !(mbmi->skip || seg_skip) && !xd->lossless[mbmi->segment_id]) { + if (dry_run) tx_partition_set_contexts(cm, xd, bsize); } else { TX_SIZE tx_size = mbmi->tx_size; // The new intra coding scheme requires no change of transform size @@ -5757,20 +6459,17 @@ static AOM_INLINE void encode_superblock(const AV1_COMP *const cpi, if (xd->lossless[mbmi->segment_id]) { tx_size = TX_4X4; } else { - tx_size = tx_size_from_tx_mode(bsize, x->tx_mode); + tx_size = tx_size_from_tx_mode(bsize, x->tx_mode_search_type); } } else { tx_size = (bsize > BLOCK_4X4) ? tx_size : TX_4X4; } mbmi->tx_size = tx_size; - set_txfm_ctxs(tx_size, xd->n4_w, xd->n4_h, + set_txfm_ctxs(tx_size, xd->width, xd->height, (mbmi->skip || seg_skip) && is_inter_block(mbmi), xd); } - CFL_CTX *const cfl = &xd->cfl; - if (is_inter_block(mbmi) && - !is_chroma_reference(mi_row, mi_col, bsize, cfl->subsampling_x, - cfl->subsampling_y) && - is_cfl_allowed(xd)) { + + if (is_inter_block(mbmi) && !xd->is_chroma_ref && is_cfl_allowed(xd)) { cfl_store_block(xd, mbmi->sb_type, mbmi->tx_size); } } diff --git a/media/libaom/src/av1/encoder/encodemb.c b/media/libaom/src/av1/encoder/encodemb.c index e528842a9a..ec33362290 100644 --- a/media/libaom/src/av1/encoder/encodemb.c +++ b/media/libaom/src/av1/encoder/encodemb.c @@ -35,10 +35,10 @@ #include "av1/encoder/rd.h" #include "av1/encoder/rdopt.h" -static void subtract_block(const MACROBLOCKD *xd, int rows, int cols, - int16_t *diff, ptrdiff_t diff_stride, - const uint8_t *src8, ptrdiff_t src_stride, - const uint8_t *pred8, ptrdiff_t pred_stride) { +void av1_subtract_block(const MACROBLOCKD *xd, int rows, int cols, + int16_t *diff, ptrdiff_t diff_stride, + const uint8_t *src8, ptrdiff_t src_stride, + const uint8_t *pred8, ptrdiff_t pred_stride) { assert(rows >= 4 && cols >= 4); #if CONFIG_AV1_HIGHBITDEPTH if (is_cur_buf_hbd(xd)) { @@ -62,49 +62,186 @@ void av1_subtract_txb(MACROBLOCK *x, int plane, BLOCK_SIZE plane_bsize, const int dst_stride = pd->dst.stride; const int tx1d_width = tx_size_wide[tx_size]; const int tx1d_height = tx_size_high[tx_size]; - uint8_t *dst = - &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]]; - uint8_t *src = - &p->src.buf[(blk_row * src_stride + blk_col) << tx_size_wide_log2[0]]; + uint8_t *dst = &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2]; + uint8_t *src = &p->src.buf[(blk_row * src_stride + blk_col) << MI_SIZE_LOG2]; int16_t *src_diff = - &p->src_diff[(blk_row * diff_stride + blk_col) << tx_size_wide_log2[0]]; - subtract_block(xd, tx1d_height, tx1d_width, src_diff, diff_stride, src, - src_stride, dst, dst_stride); + &p->src_diff[(blk_row * diff_stride + blk_col) << MI_SIZE_LOG2]; + av1_subtract_block(xd, tx1d_height, tx1d_width, src_diff, diff_stride, src, + src_stride, dst, dst_stride); } -void av1_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane) { +void av1_subtract_plane(MACROBLOCK *x, BLOCK_SIZE plane_bsize, int plane) { struct macroblock_plane *const p = &x->plane[plane]; const struct macroblockd_plane *const pd = &x->e_mbd.plane[plane]; - assert(bsize < BLOCK_SIZES_ALL); - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + assert(plane_bsize < BLOCK_SIZES_ALL); const int bw = block_size_wide[plane_bsize]; const int bh = block_size_high[plane_bsize]; const MACROBLOCKD *xd = &x->e_mbd; - subtract_block(xd, bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, - pd->dst.buf, pd->dst.stride); + av1_subtract_block(xd, bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, + pd->dst.buf, pd->dst.stride); } -int av1_optimize_b(const struct AV1_COMP *cpi, MACROBLOCK *mb, int plane, +int av1_optimize_b(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 fast_mode, int *rate_cost) { - MACROBLOCKD *const xd = &mb->e_mbd; - struct macroblock_plane *const p = &mb->plane[plane]; + MACROBLOCKD *const xd = &x->e_mbd; + struct macroblock_plane *const p = &x->plane[plane]; const int eob = p->eobs[block]; const int segment_id = xd->mi[0]->segment_id; if (eob == 0 || !cpi->optimize_seg_arr[segment_id] || xd->lossless[segment_id]) { - *rate_cost = av1_cost_skip_txb(mb, txb_ctx, plane, tx_size); + *rate_cost = av1_cost_skip_txb(x, txb_ctx, plane, tx_size); return eob; } - return av1_optimize_txb_new(cpi, mb, plane, block, tx_size, tx_type, txb_ctx, + return av1_optimize_txb_new(cpi, x, plane, block, tx_size, tx_type, txb_ctx, rate_cost, cpi->oxcf.sharpness, fast_mode); } +// Hyper-parameters for dropout optimization, based on following logics. +// TODO(yjshen): These settings are tuned by experiments. They may still be +// optimized for better performance. +// (1) Coefficients which are large enough will ALWAYS be kept. +const tran_low_t DROPOUT_COEFF_MAX = 2; // Max dropout-able coefficient. +// (2) Continuous coefficients will ALWAYS be kept. Here rigorous continuity is +// NOT required. For example, `5 0 0 0 7` is treated as two continuous +// coefficients if three zeros do not fulfill the dropout condition. +const int DROPOUT_CONTINUITY_MAX = 2; // Max dropout-able continuous coeff. +// (3) Dropout operation is NOT applicable to blocks with large or small +// quantization index. +const int DROPOUT_Q_MAX = 128; +const int DROPOUT_Q_MIN = 16; +// (4) Recall that dropout optimization will forcibly set some quantized +// coefficients to zero. The key logic on determining whether a coefficient +// should be dropped is to check the number of continuous zeros before AND +// after this coefficient. The exact number of zeros for judgement depends +// on block size and quantization index. More concretely, block size +// determines the base number of zeros, while quantization index determines +// the multiplier. Intuitively, larger block requires more zeros and larger +// quantization index also requires more zeros (more information is lost +// when using larger quantization index). +const int DROPOUT_BEFORE_BASE_MAX = 32; // Max base number for leading zeros. +const int DROPOUT_BEFORE_BASE_MIN = 16; // Min base number for leading zeros. +const int DROPOUT_AFTER_BASE_MAX = 32; // Max base number for trailing zeros. +const int DROPOUT_AFTER_BASE_MIN = 16; // Min base number for trailing zeros. +const int DROPOUT_MULTIPLIER_MAX = 8; // Max multiplier on number of zeros. +const int DROPOUT_MULTIPLIER_MIN = 2; // Min multiplier on number of zeros. +const int DROPOUT_MULTIPLIER_Q_BASE = 32; // Base Q to compute multiplier. + +void av1_dropout_qcoeff(MACROBLOCK *mb, int plane, int block, TX_SIZE tx_size, + TX_TYPE tx_type, int qindex) { + MACROBLOCKD *const xd = &mb->e_mbd; + const struct macroblock_plane *const p = &mb->plane[plane]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + tran_low_t *const qcoeff = p->qcoeff + BLOCK_OFFSET(block); + tran_low_t *const dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); + const int tx_width = tx_size_wide[tx_size]; + const int tx_height = tx_size_high[tx_size]; + const int max_eob = av1_get_max_eob(tx_size); + const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type); + + // Early return if `qindex` is out of range. + if (qindex > DROPOUT_Q_MAX || qindex < DROPOUT_Q_MIN) { + return; + } + + // Compute number of zeros used for dropout judgement. + const int base_size = AOMMAX(tx_width, tx_height); + const int multiplier = CLIP(qindex / DROPOUT_MULTIPLIER_Q_BASE, + DROPOUT_MULTIPLIER_MIN, DROPOUT_MULTIPLIER_MAX); + const int dropout_num_before = + multiplier * + CLIP(base_size, DROPOUT_BEFORE_BASE_MIN, DROPOUT_BEFORE_BASE_MAX); + const int dropout_num_after = + multiplier * + CLIP(base_size, DROPOUT_AFTER_BASE_MIN, DROPOUT_AFTER_BASE_MAX); + + // Early return if there are not enough non-zero coefficients. + if (p->eobs[block] == 0 || p->eobs[block] <= dropout_num_before) { + return; + } + + int count_zeros_before = 0; + int count_zeros_after = 0; + int count_nonzeros = 0; + // Index of the first non-zero coefficient after sufficient number of + // continuous zeros. If equals to `-1`, it means number of leading zeros + // hasn't reach `dropout_num_before`. + int idx = -1; + int eob = 0; // New end of block. + + for (int i = 0; i < p->eobs[block]; ++i) { + const int scan_idx = scan_order->scan[i]; + if (qcoeff[scan_idx] > DROPOUT_COEFF_MAX) { // Keep large coefficients. + count_zeros_before = 0; + count_zeros_after = 0; + idx = -1; + eob = i + 1; + } else if (qcoeff[scan_idx] == 0) { // Count zeros. + if (idx == -1) { + ++count_zeros_before; + } else { + ++count_zeros_after; + } + } else { // Count non-zeros. + if (count_zeros_before >= dropout_num_before) { + idx = (idx == -1) ? i : idx; + ++count_nonzeros; + } else { + count_zeros_before = 0; + eob = i + 1; + } + } + + // Handle continuity. + if (count_nonzeros > DROPOUT_CONTINUITY_MAX) { + count_zeros_before = 0; + count_zeros_after = 0; + idx = -1; + eob = i + 1; + } + + // Handle the trailing zeros after original end of block. + if (idx != -1 && i == p->eobs[block] - 1) { + count_zeros_after += (max_eob - p->eobs[block]); + } + + // Set redundant coefficients to zeros if needed. + if (count_zeros_after >= dropout_num_after) { + for (int j = idx; j <= i; ++j) { + qcoeff[scan_order->scan[j]] = 0; + dqcoeff[scan_order->scan[j]] = 0; + } + count_zeros_before += (i - idx + 1); + count_zeros_after = 0; + count_nonzeros = 0; + } else if (i == p->eobs[block] - 1) { + eob = i + 1; + } + } + + if (eob != p->eobs[block]) { + p->eobs[block] = eob; + p->txb_entropy_ctx[block] = + (uint8_t)av1_get_txb_entropy_context(qcoeff, scan_order, eob); + } +} + +// Settings for optimization type. NOTE: To set optimization type for all intra +// frames, both `KEY_BLOCK_OPT_TYPE` and `INTRA_BLOCK_OPT_TYPE` should be set. +// TODO(yjshen): These settings are hard-coded and look okay for now. They +// should be made configurable later. +// Blocks of key frames ONLY. +const OPT_TYPE KEY_BLOCK_OPT_TYPE = TRELLIS_DROPOUT_OPT; +// Blocks of intra frames (key frames EXCLUSIVE). +const OPT_TYPE INTRA_BLOCK_OPT_TYPE = TRELLIS_DROPOUT_OPT; +// Blocks of inter frames. (NOTE: Dropout optimization is DISABLED by default +// if trellis optimization is on for inter frames.) +const OPT_TYPE INTER_BLOCK_OPT_TYPE = TRELLIS_DROPOUT_OPT; + enum { QUANT_FUNC_LOWBD = 0, QUANT_FUNC_HIGHBD = 1, @@ -125,88 +262,97 @@ static AV1_QUANT_FACADE quant_func_list[AV1_XFORM_QUANT_TYPES] = { }; #endif -void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block, - int blk_row, int blk_col, BLOCK_SIZE plane_bsize, - TX_SIZE tx_size, TX_TYPE tx_type, - AV1_XFORM_QUANT xform_quant_idx) { +void av1_xform_quant(MACROBLOCK *x, int plane, int block, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, TxfmParam *txfm_param, + QUANT_PARAM *qparam) { MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; const struct macroblock_plane *const p = &x->plane[plane]; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type); + const SCAN_ORDER *const scan_order = + get_scan(txfm_param->tx_size, txfm_param->tx_type); const int block_offset = BLOCK_OFFSET(block); tran_low_t *const coeff = p->coeff + block_offset; tran_low_t *const qcoeff = p->qcoeff + block_offset; tran_low_t *const dqcoeff = pd->dqcoeff + block_offset; uint16_t *const eob = &p->eobs[block]; const int diff_stride = block_size_wide[plane_bsize]; - int seg_id = mbmi->segment_id; - const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); - // Use a flat matrix (i.e. no weighting) for 1D and Identity transforms - const qm_val_t *qmatrix = - IS_2D_TRANSFORM(tx_type) ? pd->seg_qmatrix[seg_id][qm_tx_size] - : cm->gqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; - const qm_val_t *iqmatrix = - IS_2D_TRANSFORM(tx_type) - ? pd->seg_iqmatrix[seg_id][qm_tx_size] - : cm->giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; const int src_offset = (blk_row * diff_stride + blk_col); - const int16_t *src_diff = &p->src_diff[src_offset << tx_size_wide_log2[0]]; - QUANT_PARAM qparam; - qparam.log_scale = av1_get_tx_scale(tx_size); - qparam.tx_size = tx_size; - qparam.qmatrix = qmatrix; - qparam.iqmatrix = iqmatrix; - qparam.use_quant_b_adapt = cm->use_quant_b_adapt; - TxfmParam txfm_param; - txfm_param.tx_type = tx_type; - txfm_param.tx_size = tx_size; - txfm_param.lossless = xd->lossless[mbmi->segment_id]; - txfm_param.tx_set_type = av1_get_ext_tx_set_type( - txfm_param.tx_size, is_inter_block(mbmi), cm->reduced_tx_set_used); + const int16_t *src_diff = &p->src_diff[src_offset << MI_SIZE_LOG2]; - txfm_param.bd = xd->bd; - txfm_param.is_hbd = is_cur_buf_hbd(xd); + av1_fwd_txfm(src_diff, coeff, diff_stride, txfm_param); - av1_fwd_txfm(src_diff, coeff, diff_stride, &txfm_param); - - if (xform_quant_idx != AV1_XFORM_QUANT_SKIP_QUANT) { - const int n_coeffs = av1_get_max_eob(tx_size); + if (qparam->xform_quant_idx != AV1_XFORM_QUANT_SKIP_QUANT) { + const int n_coeffs = av1_get_max_eob(txfm_param->tx_size); if (LIKELY(!x->skip_block)) { #if CONFIG_AV1_HIGHBITDEPTH - quant_func_list[xform_quant_idx][txfm_param.is_hbd]( - coeff, n_coeffs, p, qcoeff, dqcoeff, eob, scan_order, &qparam); + quant_func_list[qparam->xform_quant_idx][txfm_param->is_hbd]( + coeff, n_coeffs, p, qcoeff, dqcoeff, eob, scan_order, qparam); #else - quant_func_list[xform_quant_idx](coeff, n_coeffs, p, qcoeff, dqcoeff, eob, - scan_order, &qparam); + quant_func_list[qparam->xform_quant_idx]( + coeff, n_coeffs, p, qcoeff, dqcoeff, eob, scan_order, qparam); #endif } else { av1_quantize_skip(n_coeffs, qcoeff, dqcoeff, eob); } } - // 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 = - (xform_quant_idx != AV1_XFORM_QUANT_FP) || (txfm_param.lossless); - if (optimize_b_following) { + // use_optimize_b is true means av1_optimze_b will be called, + // thus cannot update entropy ctx now (performed in optimize_b) + if (qparam->use_optimize_b) { + p->txb_entropy_ctx[block] = 0; + } else { p->txb_entropy_ctx[block] = (uint8_t)av1_get_txb_entropy_context(qcoeff, scan_order, *eob); - } else { - p->txb_entropy_ctx[block] = 0; } return; } +void av1_setup_xform(const AV1_COMMON *cm, MACROBLOCK *x, TX_SIZE tx_size, + TX_TYPE tx_type, TxfmParam *txfm_param) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + + txfm_param->tx_type = tx_type; + txfm_param->tx_size = tx_size; + txfm_param->lossless = xd->lossless[mbmi->segment_id]; + txfm_param->tx_set_type = av1_get_ext_tx_set_type( + tx_size, is_inter_block(mbmi), cm->features.reduced_tx_set_used); + + txfm_param->bd = xd->bd; + txfm_param->is_hbd = is_cur_buf_hbd(xd); +} +void av1_setup_quant(TX_SIZE tx_size, int use_optimize_b, int xform_quant_idx, + int use_quant_b_adapt, QUANT_PARAM *qparam) { + qparam->log_scale = av1_get_tx_scale(tx_size); + qparam->tx_size = tx_size; + + qparam->use_quant_b_adapt = use_quant_b_adapt; + + // TODO(bohanli): optimize_b and quantization idx has relationship, + // but is kind of buried and complicated in different encoding stages. + // Should have a unified function to derive quant_idx, rather than + // determine and pass in the quant_idx + qparam->use_optimize_b = use_optimize_b; + qparam->xform_quant_idx = xform_quant_idx; + + qparam->qmatrix = NULL; + qparam->iqmatrix = NULL; +} +void av1_setup_qmatrix(const CommonQuantParams *quant_params, + const MACROBLOCKD *xd, int plane, TX_SIZE tx_size, + TX_TYPE tx_type, QUANT_PARAM *qparam) { + qparam->qmatrix = av1_get_qmatrix(quant_params, xd, plane, tx_size, tx_type); + qparam->iqmatrix = + av1_get_iqmatrix(quant_params, xd, plane, tx_size, tx_type); +} + static void encode_block(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg, - int mi_row, int mi_col, RUN_TYPE dry_run) { - (void)mi_row; - (void)mi_col; + RUN_TYPE dry_run) { (void)dry_run; struct encode_b_args *const args = arg; - const AV1_COMMON *const cm = &args->cpi->common; + const AV1_COMP *const cpi = args->cpi; + const AV1_COMMON *const cm = &cpi->common; MACROBLOCK *const x = args->x; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *mbmi = xd->mi[0]; @@ -217,9 +363,8 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, ENTROPY_CONTEXT *a, *l; int dummy_rate_cost = 0; - const int bw = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - dst = &pd->dst - .buf[(blk_row * pd->dst.stride + blk_col) << tx_size_wide_log2[0]]; + const int bw = mi_size_wide[plane_bsize]; + dst = &pd->dst.buf[(blk_row * pd->dst.stride + blk_col) << MI_SIZE_LOG2]; a = &args->ta[blk_col]; l = &args->tl[blk_row]; @@ -227,22 +372,39 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, TX_TYPE tx_type = DCT_DCT; if (!is_blk_skip(x, plane, blk_row * bw + blk_col) && !mbmi->skip_mode) { tx_type = av1_get_tx_type(xd, pd->plane_type, 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, - USE_B_QUANT_NO_TRELLIS && - (args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT) - ? AV1_XFORM_QUANT_B - : AV1_XFORM_QUANT_FP); + cm->features.reduced_tx_set_used); + TxfmParam txfm_param; + QUANT_PARAM quant_param; + const int use_trellis = is_trellis_used(args->enable_optimize_b, dry_run); + int quant_idx; + if (use_trellis) + quant_idx = AV1_XFORM_QUANT_FP; + else + quant_idx = + USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP; + av1_setup_xform(cm, x, tx_size, tx_type, &txfm_param); + av1_setup_quant(tx_size, use_trellis, quant_idx, cpi->oxcf.quant_b_adapt, + &quant_param); + av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type, + &quant_param); + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + + // Whether trellis or dropout optimization is required for inter frames. + const bool do_trellis = INTER_BLOCK_OPT_TYPE == TRELLIS_OPT || + INTER_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT; + const bool do_dropout = INTER_BLOCK_OPT_TYPE == DROPOUT_OPT || + INTER_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT; + + if (quant_param.use_optimize_b && do_trellis) { 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, - 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, - USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP); + args->cpi->sf.rd_sf.trellis_eob_fast, &dummy_rate_cost); + } + if (!quant_param.use_optimize_b && do_dropout) { + av1_dropout_qcoeff(x, plane, block, tx_size, tx_type, + cm->quant_params.base_qindex); } } else { p->eobs[block] = 0; @@ -255,7 +417,7 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, *(args->skip) = 0; av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, dst, pd->dst.stride, p->eobs[block], - cm->reduced_tx_set_used); + cm->features.reduced_tx_set_used); } // TODO(debargha, jingning): Temporarily disable txk_type check for eob=0 @@ -285,8 +447,8 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE bsize = txsize_to_bsize[tx_size]; int blk_w = block_size_wide[bsize]; int blk_h = block_size_high[bsize]; - mi_to_pixel_loc(&pixel_c, &pixel_r, mi_col, mi_row, blk_col, blk_row, - pd->subsampling_x, pd->subsampling_y); + mi_to_pixel_loc(&pixel_c, &pixel_r, xd->mi_col, xd->mi_row, blk_col, + blk_row, pd->subsampling_x, pd->subsampling_y); mismatch_record_block_tx(dst, pd->dst.stride, cm->current_frame.order_hint, plane, pixel_c, pixel_r, blk_w, blk_h, xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH); @@ -296,10 +458,7 @@ static void encode_block(int plane, int block, int blk_row, int blk_col, static void encode_block_inter(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - void *arg, int mi_row, int mi_col, - RUN_TYPE dry_run) { - (void)mi_row; - (void)mi_col; + void *arg, RUN_TYPE dry_run) { struct encode_b_args *const args = arg; MACROBLOCK *const x = args->x; MACROBLOCKD *const xd = &x->e_mbd; @@ -322,7 +481,7 @@ static void encode_block_inter(int plane, int block, int blk_row, int blk_col, if (tx_size == plane_tx_size || plane) { encode_block(plane, block, blk_row, blk_col, plane_bsize, tx_size, arg, - mi_row, mi_col, dry_run); + dry_run); } else { assert(tx_size < TX_SIZES_ALL); const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; @@ -342,7 +501,7 @@ static void encode_block_inter(int plane, int block, int blk_row, int blk_col, if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; encode_block_inter(plane, block, offsetr, offsetc, plane_bsize, sub_txs, - arg, mi_row, mi_col, dry_run); + arg, dry_run); block += step; } } @@ -350,44 +509,39 @@ static void encode_block_inter(int plane, int block, int blk_row, int blk_col, } void av1_foreach_transformed_block_in_plane( - const MACROBLOCKD *const xd, BLOCK_SIZE bsize, int plane, + const MACROBLOCKD *const xd, BLOCK_SIZE plane_bsize, int plane, foreach_transformed_block_visitor visit, void *arg) { const struct macroblockd_plane *const pd = &xd->plane[plane]; // block and transform sizes, in number of 4x4 blocks log 2 ("*_b") // 4x4=0, 8x8=2, 16x16=4, 32x32=6, 64x64=8 // transform size varies per plane, look it up in a common way. const TX_SIZE tx_size = av1_get_tx_size(plane, xd); - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); const uint8_t txw_unit = tx_size_wide_unit[tx_size]; const uint8_t txh_unit = tx_size_high_unit[tx_size]; const int step = txw_unit * txh_unit; - int i = 0, r, c; // If mb_to_right_edge is < 0 we are in a situation in which // the current block size extends into the UMV and we won't // visit the sub blocks that are wholly within the UMV. const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane); const int max_blocks_high = max_block_high(xd, plane_bsize, plane); - - int blk_row, blk_col; - const BLOCK_SIZE max_unit_bsize = get_plane_block_size(BLOCK_64X64, pd->subsampling_x, pd->subsampling_y); - int mu_blocks_wide = block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; - mu_blocks_wide = AOMMIN(max_blocks_wide, mu_blocks_wide); - mu_blocks_high = AOMMIN(max_blocks_high, mu_blocks_high); + const int mu_blocks_wide = + AOMMIN(mi_size_wide[max_unit_bsize], max_blocks_wide); + const int mu_blocks_high = + AOMMIN(mi_size_high[max_unit_bsize], max_blocks_high); // Keep track of the row and column of the blocks we use so that we know // if we are in the unrestricted motion border. - for (r = 0; r < max_blocks_high; r += mu_blocks_high) { + int i = 0; + for (int r = 0; r < max_blocks_high; r += mu_blocks_high) { const int unit_height = AOMMIN(mu_blocks_high + r, max_blocks_high); // Skip visiting the sub blocks that are wholly within the UMV. - for (c = 0; c < max_blocks_wide; c += mu_blocks_wide) { + for (int c = 0; c < max_blocks_wide; c += mu_blocks_wide) { const int unit_width = AOMMIN(mu_blocks_wide + c, max_blocks_wide); - for (blk_row = r; blk_row < unit_height; blk_row += txh_unit) { - for (blk_col = c; blk_col < unit_width; blk_col += txw_unit) { + for (int blk_row = r; blk_row < unit_height; blk_row += txh_unit) { + for (int blk_col = c; blk_col < unit_width; blk_col += txw_unit) { visit(plane, i, blk_row, blk_col, plane_bsize, tx_size, arg); i += step; } @@ -396,21 +550,8 @@ void av1_foreach_transformed_block_in_plane( } } -void av1_foreach_transformed_block(const MACROBLOCKD *const xd, - BLOCK_SIZE bsize, int mi_row, int mi_col, - foreach_transformed_block_visitor visit, - void *arg, const int num_planes) { - for (int plane = 0; plane < num_planes; ++plane) { - if (!is_chroma_reference(mi_row, mi_col, bsize, - xd->plane[plane].subsampling_x, - xd->plane[plane].subsampling_y)) - continue; - av1_foreach_transformed_block_in_plane(xd, bsize, plane, visit, arg); - } -} - typedef struct encode_block_pass1_args { - AV1_COMMON *cm; + AV1_COMP *cpi; MACROBLOCK *x; } encode_block_pass1_args; @@ -418,28 +559,31 @@ static void encode_block_pass1(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) { encode_block_pass1_args *args = (encode_block_pass1_args *)arg; - AV1_COMMON *cm = args->cm; + AV1_COMP *cpi = args->cpi; + AV1_COMMON *cm = &cpi->common; MACROBLOCK *const x = args->x; MACROBLOCKD *const xd = &x->e_mbd; struct macroblock_plane *const p = &x->plane[plane]; struct macroblockd_plane *const pd = &xd->plane[plane]; tran_low_t *const dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); - TxfmParam txfm_param; + uint8_t *dst; - dst = &pd->dst - .buf[(blk_row * pd->dst.stride + blk_col) << tx_size_wide_log2[0]]; - av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, - DCT_DCT, AV1_XFORM_QUANT_B); + dst = &pd->dst.buf[(blk_row * pd->dst.stride + blk_col) << MI_SIZE_LOG2]; + + TxfmParam txfm_param; + QUANT_PARAM quant_param; + + av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); + av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + &quant_param); + av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, DCT_DCT, + &quant_param); + + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); if (p->eobs[block] > 0) { - txfm_param.bd = xd->bd; - txfm_param.is_hbd = is_cur_buf_hbd(xd); - txfm_param.tx_type = DCT_DCT; - txfm_param.tx_size = tx_size; txfm_param.eob = p->eobs[block]; - txfm_param.lossless = xd->lossless[xd->mi[0]->segment_id]; - txfm_param.tx_set_type = av1_get_ext_tx_set_type( - txfm_param.tx_size, is_inter_block(xd->mi[0]), cm->reduced_tx_set_used); if (txfm_param.is_hbd) { av1_highbd_inv_txfm_add(dqcoeff, dst, pd->dst.stride, &txfm_param); return; @@ -448,87 +592,65 @@ static void encode_block_pass1(int plane, int block, int blk_row, int blk_col, } } -void av1_encode_sby_pass1(AV1_COMMON *cm, MACROBLOCK *x, BLOCK_SIZE bsize) { - encode_block_pass1_args args = { cm, x }; +void av1_encode_sby_pass1(AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize) { + encode_block_pass1_args args = { cpi, x }; av1_subtract_plane(x, bsize, 0); av1_foreach_transformed_block_in_plane(&x->e_mbd, bsize, 0, encode_block_pass1, &args); } void av1_encode_sb(const struct AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, - int mi_row, int mi_col, RUN_TYPE dry_run) { - (void)dry_run; + RUN_TYPE dry_run) { + assert(bsize < BLOCK_SIZES_ALL); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + mbmi->skip = 1; + if (x->force_skip) return; + + struct optimize_ctx ctx; + struct encode_b_args arg = { + cpi, x, &ctx, &mbmi->skip, + NULL, NULL, dry_run, cpi->optimize_seg_arr[mbmi->segment_id] + }; const AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - MACROBLOCKD *const xd = &x->e_mbd; - struct optimize_ctx ctx; - MB_MODE_INFO *mbmi = xd->mi[0]; - struct encode_b_args arg = { cpi, - x, - &ctx, - &mbmi->skip, - NULL, - NULL, - cpi->optimize_seg_arr[mbmi->segment_id] }; - int plane; - - mbmi->skip = 1; - - if (x->skip) return; - - assert(bsize < BLOCK_SIZES_ALL); - - for (plane = 0; plane < num_planes; ++plane) { - const int subsampling_x = xd->plane[plane].subsampling_x; - const int subsampling_y = xd->plane[plane].subsampling_y; - if (!is_chroma_reference(mi_row, mi_col, bsize, subsampling_x, - subsampling_y)) - continue; - - const BLOCK_SIZE bsizec = - scale_chroma_bsize(bsize, subsampling_x, subsampling_y); - - // TODO(jingning): Clean this up. + for (int plane = 0; plane < num_planes; ++plane) { const struct macroblockd_plane *const pd = &xd->plane[plane]; + const int subsampling_x = pd->subsampling_x; + const int subsampling_y = pd->subsampling_y; + if (plane && !xd->is_chroma_ref) break; const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsizec, pd->subsampling_x, pd->subsampling_y); + get_plane_block_size(bsize, subsampling_x, subsampling_y); assert(plane_bsize < BLOCK_SIZES_ALL); - const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int mi_height = block_size_high[plane_bsize] >> tx_size_high_log2[0]; + const int mi_width = mi_size_wide[plane_bsize]; + const int mi_height = mi_size_high[plane_bsize]; const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, plane); - const BLOCK_SIZE txb_size = txsize_to_bsize[max_tx_size]; - const int bw = block_size_wide[txb_size] >> tx_size_wide_log2[0]; - const int bh = block_size_high[txb_size] >> tx_size_high_log2[0]; - int idx, idy; + const int bw = mi_size_wide[txb_size]; + const int bh = mi_size_high[txb_size]; int block = 0; - int step = tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; - av1_get_entropy_contexts(bsizec, pd, ctx.ta[plane], ctx.tl[plane]); - - av1_subtract_plane(x, bsizec, plane); - + const int step = + tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; + av1_get_entropy_contexts(plane_bsize, pd, ctx.ta[plane], ctx.tl[plane]); + av1_subtract_plane(x, plane_bsize, plane); arg.ta = ctx.ta[plane]; arg.tl = ctx.tl[plane]; - const BLOCK_SIZE max_unit_bsize = - get_plane_block_size(BLOCK_64X64, pd->subsampling_x, pd->subsampling_y); - int mu_blocks_wide = - block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = - block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; - + get_plane_block_size(BLOCK_64X64, subsampling_x, subsampling_y); + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(mi_width, mu_blocks_wide); mu_blocks_high = AOMMIN(mi_height, mu_blocks_high); - for (idy = 0; idy < mi_height; idy += mu_blocks_high) { - for (idx = 0; idx < mi_width; idx += mu_blocks_wide) { + for (int idy = 0; idy < mi_height; idy += mu_blocks_high) { + for (int idx = 0; idx < mi_width; idx += mu_blocks_wide) { int blk_row, blk_col; const int unit_height = AOMMIN(mu_blocks_high + idy, mi_height); const int unit_width = AOMMIN(mu_blocks_wide + idx, mi_width); for (blk_row = idy; blk_row < unit_height; blk_row += bh) { for (blk_col = idx; blk_col < unit_width; blk_col += bw) { encode_block_inter(plane, block, blk_row, blk_col, plane_bsize, - max_tx_size, &arg, mi_row, mi_col, dry_run); + max_tx_size, &arg, dry_run); block += step; } } @@ -555,7 +677,8 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg) { struct encode_b_args *const args = arg; - const AV1_COMMON *const cm = &args->cpi->common; + const AV1_COMP *const cpi = args->cpi; + const AV1_COMMON *const cm = &cpi->common; MACROBLOCK *const x = args->x; MACROBLOCKD *const xd = &x->e_mbd; struct macroblock_plane *const p = &x->plane[plane]; @@ -564,14 +687,13 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, PLANE_TYPE plane_type = get_plane_type(plane); uint16_t *eob = &p->eobs[block]; const int dst_stride = pd->dst.stride; - uint8_t *dst = - &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]]; + uint8_t *dst = &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2]; int dummy_rate_cost = 0; av1_predict_intra_block_facade(cm, xd, plane, blk_col, blk_row, tx_size); TX_TYPE tx_type = DCT_DCT; - const int bw = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; + const int bw = mi_size_wide[plane_bsize]; if (plane == 0 && is_blk_skip(x, plane, blk_row * bw + blk_col)) { *eob = 0; p->txb_entropy_ctx[block] = 0; @@ -581,28 +703,58 @@ 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]; tx_type = av1_get_tx_type(xd, plane_type, 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, - USE_B_QUANT_NO_TRELLIS && - (args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT) - ? AV1_XFORM_QUANT_B - : AV1_XFORM_QUANT_FP); + cm->features.reduced_tx_set_used); + TxfmParam txfm_param; + QUANT_PARAM quant_param; + const int use_trellis = + is_trellis_used(args->enable_optimize_b, args->dry_run); + int quant_idx; + if (use_trellis) + quant_idx = AV1_XFORM_QUANT_FP; + else + quant_idx = + USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP; + + av1_setup_xform(cm, x, tx_size, tx_type, &txfm_param); + av1_setup_quant(tx_size, use_trellis, quant_idx, cpi->oxcf.quant_b_adapt, + &quant_param); + av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type, + &quant_param); + + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + + // Whether trellis or dropout optimization is required for key frames and + // intra frames. + const bool do_trellis = (frame_is_intra_only(cm) && + (KEY_BLOCK_OPT_TYPE == TRELLIS_OPT || + KEY_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT)) || + (!frame_is_intra_only(cm) && + (INTRA_BLOCK_OPT_TYPE == TRELLIS_OPT || + INTRA_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT)); + const bool do_dropout = (frame_is_intra_only(cm) && + (KEY_BLOCK_OPT_TYPE == DROPOUT_OPT || + KEY_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT)) || + (!frame_is_intra_only(cm) && + (INTRA_BLOCK_OPT_TYPE == DROPOUT_OPT || + INTRA_BLOCK_OPT_TYPE == TRELLIS_DROPOUT_OPT)); + + if (quant_param.use_optimize_b && do_trellis) { 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, - 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, - USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP); + args->cpi->sf.rd_sf.trellis_eob_fast, &dummy_rate_cost); + } + if (do_dropout) { + av1_dropout_qcoeff(x, plane, block, tx_size, tx_type, + cm->quant_params.base_qindex); } } if (*eob) { av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, dst, - dst_stride, *eob, cm->reduced_tx_set_used); + dst_stride, *eob, + cm->features.reduced_tx_set_used); } // TODO(jingning): Temporarily disable txk_type check for eob=0 case. @@ -631,27 +783,23 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, } void av1_encode_intra_block_plane(const struct AV1_COMP *cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int plane, - int enable_optimize_b, int mi_row, - int mi_col) { + BLOCK_SIZE bsize, int plane, RUN_TYPE dry_run, + TRELLIS_OPT_TYPE enable_optimize_b) { + assert(bsize < BLOCK_SIZES_ALL); const MACROBLOCKD *const xd = &x->e_mbd; + if (plane && !xd->is_chroma_ref) return; + + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; ENTROPY_CONTEXT ta[MAX_MIB_SIZE] = { 0 }; ENTROPY_CONTEXT tl[MAX_MIB_SIZE] = { 0 }; - assert(bsize < BLOCK_SIZES_ALL); - - struct encode_b_args arg = { - cpi, x, NULL, &(xd->mi[0]->skip), ta, tl, enable_optimize_b - }; - - if (!is_chroma_reference(mi_row, mi_col, bsize, - xd->plane[plane].subsampling_x, - xd->plane[plane].subsampling_y)) - return; - + struct encode_b_args arg = { cpi, x, NULL, &(xd->mi[0]->skip), + ta, tl, dry_run, enable_optimize_b }; + const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, ss_x, ss_y); if (enable_optimize_b) { - const struct macroblockd_plane *const pd = &xd->plane[plane]; - av1_get_entropy_contexts(bsize, pd, ta, tl); + av1_get_entropy_contexts(plane_bsize, pd, ta, tl); } av1_foreach_transformed_block_in_plane( - xd, bsize, plane, encode_block_intra_and_set_context, &arg); + xd, plane_bsize, plane, encode_block_intra_and_set_context, &arg); } diff --git a/media/libaom/src/av1/encoder/encodemb.h b/media/libaom/src/av1/encoder/encodemb.h index d4394cf0be..a337c83dbd 100644 --- a/media/libaom/src/av1/encoder/encodemb.h +++ b/media/libaom/src/av1/encoder/encodemb.h @@ -14,7 +14,7 @@ #include "config/aom_config.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/txb_common.h" #include "av1/encoder/block.h" #include "av1/encoder/tokenize.h" @@ -34,7 +34,8 @@ struct encode_b_args { int8_t *skip; ENTROPY_CONTEXT *ta; ENTROPY_CONTEXT *tl; - int8_t enable_optimize_b; + RUN_TYPE dry_run; + TRELLIS_OPT_TYPE enable_optimize_b; }; enum { @@ -45,33 +46,75 @@ enum { AV1_XFORM_QUANT_TYPES, } UENUM1BYTE(AV1_XFORM_QUANT); +// Available optimization types to optimize the quantized coefficients. +enum { + NONE_OPT = 0, // No optimization. + TRELLIS_OPT = 1, // Trellis optimization. See `av1_optimize_b()`. + DROPOUT_OPT = 2, // Dropout optimization. See `av1_dropout_qcoeff()`. + TRELLIS_DROPOUT_OPT = 3 // Perform dropout after trellis optimization. +} UENUM1BYTE(OPT_TYPE); + void av1_encode_sb(const struct AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, - int mi_row, int mi_col, RUN_TYPE dry_run); + RUN_TYPE dry_run); void av1_foreach_transformed_block_in_plane( - const MACROBLOCKD *const xd, BLOCK_SIZE bsize, int plane, + const MACROBLOCKD *const xd, BLOCK_SIZE plane_bsize, int plane, foreach_transformed_block_visitor visit, void *arg); -void av1_foreach_transformed_block(const MACROBLOCKD *const xd, - BLOCK_SIZE bsize, int mi_row, int mi_col, - foreach_transformed_block_visitor visit, - void *arg, const int num_planes); +void av1_encode_sby_pass1(struct AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize); -void av1_encode_sby_pass1(AV1_COMMON *cm, MACROBLOCK *x, BLOCK_SIZE bsize); +void av1_setup_xform(const AV1_COMMON *cm, MACROBLOCK *x, TX_SIZE tx_size, + TX_TYPE tx_type, TxfmParam *txfm_param); +void av1_setup_quant(TX_SIZE tx_size, int use_optimize_b, int xform_quant_idx, + int use_quant_b_adapt, QUANT_PARAM *qparam); +void av1_setup_qmatrix(const CommonQuantParams *quant_params, + const MACROBLOCKD *xd, int plane, TX_SIZE tx_size, + TX_TYPE tx_type, QUANT_PARAM *qparam); -void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block, - int blk_row, int blk_col, BLOCK_SIZE plane_bsize, - TX_SIZE tx_size, TX_TYPE tx_type, - AV1_XFORM_QUANT xform_quant_idx); +void av1_xform_quant(MACROBLOCK *x, int plane, int block, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, TxfmParam *txfm_param, + QUANT_PARAM *qparam); int av1_optimize_b(const struct AV1_COMP *cpi, MACROBLOCK *mb, int plane, int block, TX_SIZE tx_size, TX_TYPE tx_type, const TXB_CTX *const txb_ctx, int fast_mode, int *rate_cost); +// This function can be used as (i) a further optimization to reduce the +// redundancy of quantized coefficients (a.k.a., `qcoeff`) after trellis +// optimization, or (ii) an alternative to trellis optimization in high-speed +// compression mode (e.g., real-time mode under speed-6) due to its LOW time +// complexity. The rational behind is to drop out the may-be redundant quantized +// coefficient which is among a bunch of zeros. NOTE: This algorithm is not as +// accurate as trellis optimization since the hyper-parameters are hard-coded +// instead of dynamic search. More adaptive logic may improve the performance. +// This function should be applied to all or partical block cells. +// Inputs: +// mb: Pointer to the MACROBLOCK to perform dropout on. +// plane: Index of the plane to which the target block belongs. +// block: Index of the target block. +// tx_size: Transform size of the target block. +// tx_type: Transform type of the target block. This field is particularly +// used to find out the scan order of the block. +// qindex: Quantization index used for target block. In general, all blocks +// in a same plane share the same quantization index. This field is +// particularly used to determine how many zeros should be used to +// drop out a coefficient. +// Returns: +// Nothing will be returned, but `qcoeff`, `dqcoeff`, `eob`, as well as +// `txb_entropy_ctx`, which `mb` points to, may be modified by this function. +void av1_dropout_qcoeff(MACROBLOCK *mb, int plane, int block, TX_SIZE tx_size, + TX_TYPE tx_type, int qindex); + +void av1_subtract_block(const MACROBLOCKD *xd, int rows, int cols, + int16_t *diff, ptrdiff_t diff_stride, + const uint8_t *src8, ptrdiff_t src_stride, + const uint8_t *pred8, ptrdiff_t pred_stride); + void av1_subtract_txb(MACROBLOCK *x, int plane, BLOCK_SIZE plane_bsize, int blk_col, int blk_row, TX_SIZE tx_size); -void av1_subtract_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane); +void av1_subtract_plane(MACROBLOCK *x, BLOCK_SIZE plane_bsize, int plane); static INLINE void av1_set_txb_context(MACROBLOCK *x, int plane, int block, TX_SIZE tx_size, ENTROPY_CONTEXT *a, @@ -85,10 +128,16 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg); void av1_encode_intra_block_plane(const struct AV1_COMP *cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int plane, - int enable_optimize_b, int mi_row, - int mi_col); + BLOCK_SIZE bsize, int plane, RUN_TYPE dry_run, + TRELLIS_OPT_TYPE enable_optimize_b); +static INLINE int is_trellis_used(TRELLIS_OPT_TYPE optimize_b, + RUN_TYPE dry_run) { + if (optimize_b == NO_TRELLIS_OPT) return false; + if (optimize_b == FINAL_PASS_TRELLIS_OPT && dry_run != OUTPUT_ENABLED) + return false; + return true; +} #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/encodemv.c b/media/libaom/src/av1/encoder/encodemv.c index 43b7237185..167e9c0a37 100644 --- a/media/libaom/src/av1/encoder/encodemv.c +++ b/media/libaom/src/av1/encoder/encodemv.c @@ -20,31 +20,13 @@ #include "aom_dsp/aom_dsp_common.h" #include "aom_ports/bitops.h" -static INLINE int mv_class_base(MV_CLASS_TYPE c) { - return c ? CLASS0_SIZE << (c + 2) : 0; -} - -// If n != 0, returns the floor of log base 2 of n. If n == 0, returns 0. -static INLINE uint8_t log_in_base_2(unsigned int n) { - // get_msb() is only valid when n != 0. - return n == 0 ? 0 : get_msb(n); -} - -static INLINE MV_CLASS_TYPE get_mv_class(int z, int *offset) { - const MV_CLASS_TYPE c = (z >= CLASS0_SIZE * 4096) - ? MV_CLASS_10 - : (MV_CLASS_TYPE)log_in_base_2(z >> 3); - if (offset) *offset = z - mv_class_base(c); - return c; -} - static void update_mv_component_stats(int comp, nmv_component *mvcomp, MvSubpelPrecision precision) { assert(comp != 0); int offset; const int sign = comp < 0; const int mag = sign ? -comp : comp; - const int mv_class = get_mv_class(mag - 1, &offset); + const int mv_class = av1_get_mv_class(mag - 1, &offset); const int d = offset >> 3; // int mv data const int fr = (offset >> 1) & 3; // fractional mv data const int hp = offset & 1; // high precision mv data @@ -98,7 +80,7 @@ static void encode_mv_component(aom_writer *w, int comp, nmv_component *mvcomp, int offset; const int sign = comp < 0; const int mag = sign ? -comp : comp; - const int mv_class = get_mv_class(mag - 1, &offset); + const int mv_class = av1_get_mv_class(mag - 1, &offset); const int d = offset >> 3; // int mv data const int fr = (offset >> 1) & 3; // fractional mv data const int hp = offset & 1; // high precision mv data @@ -161,7 +143,7 @@ static void build_nmv_component_cost_table(int *mvcost, for (v = 1; v <= MV_MAX; ++v) { int z, c, o, d, e, f, cost = 0; z = v - 1; - c = get_mv_class(z, &o); + c = av1_get_mv_class(z, &o); cost += class_cost[c]; d = (o >> 3); /* int mv data */ f = (o >> 1) & 3; /* fractional pel mv data */ @@ -195,7 +177,9 @@ void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref, nmv_context *mvctx, int usehp) { const MV diff = { mv->row - ref->row, mv->col - ref->col }; const MV_JOINT_TYPE j = av1_get_mv_joint(&diff); - if (cpi->common.cur_frame_force_integer_mv) { + // If the mv_diff is zero, then we should have used near or nearest instead. + assert(j != MV_JOINT_ZERO); + if (cpi->common.features.cur_frame_force_integer_mv) { usehp = MV_SUBPEL_NONE; } aom_write_symbol(w, j, mvctx->joints_cdf, MV_JOINTS); @@ -207,9 +191,10 @@ void av1_encode_mv(AV1_COMP *cpi, aom_writer *w, const MV *mv, const MV *ref, // If auto_mv_step_size is enabled then keep track of the largest // motion vector component used. - if (cpi->sf.mv.auto_mv_step_size) { - unsigned int maxv = AOMMAX(abs(mv->row), abs(mv->col)) >> 3; - cpi->max_mv_magnitude = AOMMAX(maxv, cpi->max_mv_magnitude); + if (cpi->sf.mv_sf.auto_mv_step_size) { + int maxv = AOMMAX(abs(mv->row), abs(mv->col)) >> 3; + cpi->mv_search_params.max_mv_magnitude = + AOMMAX(maxv, cpi->mv_search_params.max_mv_magnitude); } } diff --git a/media/libaom/src/av1/encoder/encodemv.h b/media/libaom/src/av1/encoder/encodemv.h index c049035e37..0d130143ec 100644 --- a/media/libaom/src/av1/encoder/encodemv.h +++ b/media/libaom/src/av1/encoder/encodemv.h @@ -51,6 +51,24 @@ static INLINE MV_JOINT_TYPE av1_get_mv_joint(const MV *mv) { return (!!mv->col) | ((!!mv->row) << 1); } +static INLINE int av1_mv_class_base(MV_CLASS_TYPE c) { + return c ? CLASS0_SIZE << (c + 2) : 0; +} + +// If n != 0, returns the floor of log base 2 of n. If n == 0, returns 0. +static INLINE uint8_t av1_log_in_base_2(unsigned int n) { + // get_msb() is only valid when n != 0. + return n == 0 ? 0 : get_msb(n); +} + +static INLINE MV_CLASS_TYPE av1_get_mv_class(int z, int *offset) { + const MV_CLASS_TYPE c = (z >= CLASS0_SIZE * 4096) + ? MV_CLASS_10 + : (MV_CLASS_TYPE)av1_log_in_base_2(z >> 3); + if (offset) *offset = z - av1_mv_class_base(c); + return c; +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/encoder.c b/media/libaom/src/av1/encoder/encoder.c index a94467d876..6406afd4a5 100644 --- a/media/libaom/src/av1/encoder/encoder.c +++ b/media/libaom/src/av1/encoder/encoder.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -61,7 +62,7 @@ #include "av1/encoder/firstpass.h" #include "av1/encoder/grain_test_vectors.h" #include "av1/encoder/hash_motion.h" -#include "av1/encoder/mbgraph.h" +#include "av1/encoder/mv_prec.h" #include "av1/encoder/pass2_strategy.h" #include "av1/encoder/picklpf.h" #include "av1/encoder/pickrst.h" @@ -75,6 +76,10 @@ #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/var_based_part.h" +#if CONFIG_TUNE_VMAF +#include "av1/encoder/tune_vmaf.h" +#endif + #define DEFAULT_EXPLICIT_ORDER_HINT_BITS 7 #if CONFIG_ENTROPY_STATS @@ -84,9 +89,6 @@ FRAME_COUNTS aggregate_fc; #define AM_SEGMENT_ID_INACTIVE 7 #define AM_SEGMENT_ID_ACTIVE 0 -// Q threshold for high precision mv. -#define HIGH_PRECISION_MV_QTHRESH 128 - // #define OUTPUT_YUV_REC #ifdef OUTPUT_YUV_SKINMAP FILE *yuv_skinmap_file = NULL; @@ -246,6 +248,128 @@ const int default_obmc_probs[FRAME_UPDATE_TYPES][BLOCK_SIZES_ALL] = { 35, 32, 19, 16, 16, 0, 0, 49, 55, 29, 19 } }; +const int default_warped_probs[FRAME_UPDATE_TYPES] = { 64, 64, 64, 64, + 64, 64, 64 }; + +// TODO(yunqing): the default probs can be trained later from better +// performance. +const int default_switchable_interp_probs[FRAME_UPDATE_TYPES] + [SWITCHABLE_FILTER_CONTEXTS] + [SWITCHABLE_FILTERS] = { + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } }, + { { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 }, + { 512, 512, 512 } } + }; + static INLINE void Scale2Ratio(AOM_SCALING mode, int *hr, int *hs) { switch (mode) { case NORMAL: @@ -275,17 +399,18 @@ static INLINE void Scale2Ratio(AOM_SCALING mode, int *hr, int *hs) { // Mark all inactive blocks as active. Other segmentation features may be set // so memset cannot be used, instead only inactive blocks should be reset. static void suppress_active_map(AV1_COMP *cpi) { - unsigned char *const seg_map = cpi->segmentation_map; + unsigned char *const seg_map = cpi->enc_seg.map; int i; if (cpi->active_map.enabled || cpi->active_map.update) - for (i = 0; i < cpi->common.mi_rows * cpi->common.mi_cols; ++i) + for (i = 0; + i < cpi->common.mi_params.mi_rows * cpi->common.mi_params.mi_cols; ++i) if (seg_map[i] == AM_SEGMENT_ID_INACTIVE) seg_map[i] = AM_SEGMENT_ID_ACTIVE; } static void apply_active_map(AV1_COMP *cpi) { struct segmentation *const seg = &cpi->common.seg; - unsigned char *const seg_map = cpi->segmentation_map; + unsigned char *const seg_map = cpi->enc_seg.map; const unsigned char *const active_map = cpi->active_map.map; int i; @@ -298,7 +423,9 @@ static void apply_active_map(AV1_COMP *cpi) { if (cpi->active_map.update) { if (cpi->active_map.enabled) { - for (i = 0; i < cpi->common.mi_rows * cpi->common.mi_cols; ++i) + for (i = 0; + i < cpi->common.mi_params.mi_rows * cpi->common.mi_params.mi_cols; + ++i) if (seg_map[i] == AM_SEGMENT_ID_ACTIVE) seg_map[i] = active_map[i]; av1_enable_segmentation(seg); av1_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP); @@ -332,10 +459,11 @@ static void apply_active_map(AV1_COMP *cpi) { int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, int cols) { - if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) { + const CommonModeInfoParams *const mi_params = &cpi->common.mi_params; + if (rows == mi_params->mb_rows && cols == mi_params->mb_cols) { unsigned char *const active_map_8x8 = cpi->active_map.map; - const int mi_rows = cpi->common.mi_rows; - const int mi_cols = cpi->common.mi_cols; + const int mi_rows = mi_params->mi_rows; + const int mi_cols = mi_params->mi_cols; const int row_scale = mi_size_high[BLOCK_16X16] == 2 ? 1 : 2; const int col_scale = mi_size_wide[BLOCK_16X16] == 2 ? 1 : 2; cpi->active_map.update = 1; @@ -361,11 +489,12 @@ int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, int av1_get_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, int cols) { - if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols && + const CommonModeInfoParams *const mi_params = &cpi->common.mi_params; + if (rows == mi_params->mb_rows && cols == mi_params->mb_cols && new_map_16x16) { - unsigned char *const seg_map_8x8 = cpi->segmentation_map; - const int mi_rows = cpi->common.mi_rows; - const int mi_cols = cpi->common.mi_cols; + unsigned char *const seg_map_8x8 = cpi->enc_seg.map; + const int mi_rows = mi_params->mi_rows; + const int mi_cols = mi_params->mi_cols; const int row_scale = mi_size_high[BLOCK_16X16] == 2 ? 1 : 2; const int col_scale = mi_size_wide[BLOCK_16X16] == 2 ? 1 : 2; @@ -447,21 +576,6 @@ static void analyze_hor_freq(const AV1_COMP *cpi, double *energy) { } } -static void set_high_precision_mv(AV1_COMP *cpi, int allow_high_precision_mv, - int cur_frame_force_integer_mv) { - MACROBLOCK *const x = &cpi->td.mb; - cpi->common.allow_high_precision_mv = - allow_high_precision_mv && cur_frame_force_integer_mv == 0; - const int copy_hp = - cpi->common.allow_high_precision_mv && cur_frame_force_integer_mv == 0; - x->nmvcost[0] = &x->nmv_costs[0][MV_MAX]; - x->nmvcost[1] = &x->nmv_costs[1][MV_MAX]; - x->nmvcost_hp[0] = &x->nmv_costs_hp[0][MV_MAX]; - x->nmvcost_hp[1] = &x->nmv_costs_hp[1][MV_MAX]; - int *(*src)[2] = copy_hp ? &x->nmvcost_hp : &x->nmvcost; - x->mv_cost_stack = *src; -} - static BLOCK_SIZE select_sb_size(const AV1_COMP *const cpi) { const AV1_COMMON *const cm = &cpi->common; @@ -472,6 +586,12 @@ static BLOCK_SIZE select_sb_size(const AV1_COMP *const cpi) { assert(cpi->oxcf.superblock_size == AOM_SUPERBLOCK_SIZE_DYNAMIC); + if (cpi->svc.number_spatial_layers > 1) { + // Use the configured size (top resolution) for spatial layers. + return AOMMIN(cpi->oxcf.width, cpi->oxcf.height) > 480 ? BLOCK_128X128 + : BLOCK_64X64; + } + // TODO(any): Possibly could improve this with a heuristic. // When superres / resize is on, 'cm->width / height' can change between // calls, so we don't apply this heuristic there. @@ -494,8 +614,8 @@ static void setup_frame(AV1_COMP *cpi) { // other inter-frames the encoder currently uses only two contexts; // context 1 for ALTREF frames and context 0 for the others. - if (frame_is_intra_only(cm) || cm->error_resilient_mode || - cpi->ext_use_primary_ref_none) { + if (frame_is_intra_only(cm) || cm->features.error_resilient_mode || + cpi->ext_flags.use_primary_ref_none) { av1_setup_past_independence(cm); } @@ -520,7 +640,7 @@ static void setup_frame(AV1_COMP *cpi) { cpi->vaq_refresh = 0; } -static void enc_set_mb_mi(AV1_COMMON *cm, int width, int height) { +static void set_mb_mi(CommonModeInfoParams *mi_params, int width, int height) { // Ensure that the decoded width and height are both multiples of // 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if // subsampling is used). @@ -529,71 +649,60 @@ static void enc_set_mb_mi(AV1_COMMON *cm, int width, int height) { const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); const int aligned_height = ALIGN_POWER_OF_TWO(height, 3); - cm->mi_cols = aligned_width >> MI_SIZE_LOG2; - cm->mi_rows = aligned_height >> MI_SIZE_LOG2; - cm->mi_stride = calc_mi_size(cm->mi_cols); + mi_params->mi_cols = aligned_width >> MI_SIZE_LOG2; + mi_params->mi_rows = aligned_height >> MI_SIZE_LOG2; + mi_params->mi_stride = calc_mi_size(mi_params->mi_cols); - cm->mb_cols = (cm->mi_cols + 2) >> 2; - cm->mb_rows = (cm->mi_rows + 2) >> 2; - cm->MBs = cm->mb_rows * cm->mb_cols; + mi_params->mb_cols = (mi_params->mi_cols + 2) >> 2; + mi_params->mb_rows = (mi_params->mi_rows + 2) >> 2; + mi_params->MBs = mi_params->mb_rows * mi_params->mb_cols; - const int is_4k_or_larger = AOMMIN(width, height) >= 2160; + const int mi_alloc_size_1d = mi_size_wide[mi_params->mi_alloc_bsize]; + mi_params->mi_alloc_stride = + (mi_params->mi_stride + mi_alloc_size_1d - 1) / mi_alloc_size_1d; - cm->mi_alloc_bsize = is_4k_or_larger ? BLOCK_8X8 : BLOCK_4X4; - const int mi_alloc_size_1d = mi_size_wide[cm->mi_alloc_bsize]; - cm->mi_alloc_rows = (cm->mi_rows + mi_alloc_size_1d - 1) / mi_alloc_size_1d; - cm->mi_alloc_cols = (cm->mi_cols + mi_alloc_size_1d - 1) / mi_alloc_size_1d; - cm->mi_alloc_stride = - (cm->mi_stride + mi_alloc_size_1d - 1) / mi_alloc_size_1d; - - assert(mi_size_wide[cm->mi_alloc_bsize] == mi_size_high[cm->mi_alloc_bsize]); + assert(mi_size_wide[mi_params->mi_alloc_bsize] == + mi_size_high[mi_params->mi_alloc_bsize]); #if CONFIG_LPF_MASK - av1_alloc_loop_filter_mask(cm); + av1_alloc_loop_filter_mask(mi_params); #endif } -static void enc_setup_mi(AV1_COMMON *cm) { - const int mi_grid_size = cm->mi_stride * calc_mi_size(cm->mi_rows); - memset(cm->mi, 0, cm->mi_alloc_size * sizeof(*cm->mi)); - memset(cm->mi_grid_base, 0, mi_grid_size * sizeof(*cm->mi_grid_base)); - memset(cm->tx_type_map, 0, mi_grid_size * sizeof(*cm->tx_type_map)); +static void enc_set_mb_mi(CommonModeInfoParams *mi_params, int width, + int height) { + const int is_4k_or_larger = AOMMIN(width, height) >= 2160; + mi_params->mi_alloc_bsize = is_4k_or_larger ? BLOCK_8X8 : BLOCK_4X4; + + set_mb_mi(mi_params, width, height); } -static int enc_alloc_mi(AV1_COMMON *cm) { - const int mi_grid_size = cm->mi_stride * calc_mi_size(cm->mi_rows); - const int alloc_size_1d = mi_size_wide[cm->mi_alloc_bsize]; - const int alloc_mi_size = - cm->mi_alloc_stride * (calc_mi_size(cm->mi_rows) / alloc_size_1d); +static void stat_stage_set_mb_mi(CommonModeInfoParams *mi_params, int width, + int height) { + mi_params->mi_alloc_bsize = BLOCK_16X16; - if (cm->mi_alloc_size < alloc_mi_size || cm->mi_grid_size < mi_grid_size) { - cm->free_mi(cm); - - cm->mi = aom_calloc(alloc_mi_size, sizeof(*cm->mi)); - if (!cm->mi) return 1; - cm->mi_alloc_size = alloc_mi_size; - - cm->mi_grid_base = - (MB_MODE_INFO **)aom_calloc(mi_grid_size, sizeof(MB_MODE_INFO *)); - if (!cm->mi_grid_base) return 1; - cm->mi_grid_size = mi_grid_size; - - cm->tx_type_map = aom_calloc(calc_mi_size(cm->mi_rows) * cm->mi_stride, - sizeof(*cm->tx_type_map)); - if (!cm->tx_type_map) return 1; - } - - return 0; + set_mb_mi(mi_params, width, height); } -static void enc_free_mi(AV1_COMMON *cm) { - aom_free(cm->mi); - cm->mi = NULL; - aom_free(cm->mi_grid_base); - cm->mi_grid_base = NULL; - cm->mi_alloc_size = 0; - aom_free(cm->tx_type_map); - cm->tx_type_map = NULL; +static void enc_setup_mi(CommonModeInfoParams *mi_params) { + const int mi_grid_size = + mi_params->mi_stride * calc_mi_size(mi_params->mi_rows); + memset(mi_params->mi_alloc, 0, + mi_params->mi_alloc_size * sizeof(*mi_params->mi_alloc)); + memset(mi_params->mi_grid_base, 0, + mi_grid_size * sizeof(*mi_params->mi_grid_base)); + memset(mi_params->tx_type_map, 0, + mi_grid_size * sizeof(*mi_params->tx_type_map)); +} + +static void enc_free_mi(CommonModeInfoParams *mi_params) { + aom_free(mi_params->mi_alloc); + mi_params->mi_alloc = NULL; + aom_free(mi_params->mi_grid_base); + mi_params->mi_grid_base = NULL; + mi_params->mi_alloc_size = 0; + aom_free(mi_params->tx_type_map); + mi_params->tx_type_map = NULL; } void av1_initialize_enc(void) { @@ -606,24 +715,35 @@ void av1_initialize_enc(void) { av1_init_wedge_masks(); } -static void dealloc_context_buffers_ext(AV1_COMP *cpi) { - if (cpi->mbmi_ext_frame_base) { - aom_free(cpi->mbmi_ext_frame_base); - cpi->mbmi_ext_frame_base = NULL; +static void dealloc_context_buffers_ext(MBMIExtFrameBufferInfo *mbmi_ext_info) { + if (mbmi_ext_info->frame_base) { + aom_free(mbmi_ext_info->frame_base); + mbmi_ext_info->frame_base = NULL; + mbmi_ext_info->alloc_size = 0; } } -static void alloc_context_buffers_ext(AV1_COMP *cpi) { - AV1_COMMON *cm = &cpi->common; - const int new_ext_mi_size = cm->mi_alloc_rows * cm->mi_alloc_cols; +static void alloc_context_buffers_ext(AV1_COMMON *cm, + MBMIExtFrameBufferInfo *mbmi_ext_info) { + const CommonModeInfoParams *const mi_params = &cm->mi_params; - if (new_ext_mi_size > cpi->mi_ext_alloc_size) { - dealloc_context_buffers_ext(cpi); + const int mi_alloc_size_1d = mi_size_wide[mi_params->mi_alloc_bsize]; + const int mi_alloc_rows = + (mi_params->mi_rows + mi_alloc_size_1d - 1) / mi_alloc_size_1d; + const int mi_alloc_cols = + (mi_params->mi_cols + mi_alloc_size_1d - 1) / mi_alloc_size_1d; + const int new_ext_mi_size = mi_alloc_rows * mi_alloc_cols; + + if (new_ext_mi_size > mbmi_ext_info->alloc_size) { + dealloc_context_buffers_ext(mbmi_ext_info); CHECK_MEM_ERROR( - cm, cpi->mbmi_ext_frame_base, - aom_calloc(new_ext_mi_size, sizeof(*cpi->mbmi_ext_frame_base))); - cpi->mi_ext_alloc_size = new_ext_mi_size; + cm, mbmi_ext_info->frame_base, + aom_calloc(new_ext_mi_size, sizeof(*mbmi_ext_info->frame_base))); + mbmi_ext_info->alloc_size = new_ext_mi_size; } + // The stride needs to be updated regardless of whether new allocation + // happened or not. + mbmi_ext_info->stride = mi_alloc_cols; } static void reset_film_grain_chroma_params(aom_film_grain_t *pars) { @@ -686,14 +806,14 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - dealloc_context_buffers_ext(cpi); + dealloc_context_buffers_ext(&cpi->mbmi_ext_info); aom_free(cpi->tile_data); cpi->tile_data = NULL; // Delete sementation map - aom_free(cpi->segmentation_map); - cpi->segmentation_map = NULL; + aom_free(cpi->enc_seg.map); + cpi->enc_seg.map = NULL; av1_cyclic_refresh_free(cpi->cyclic_refresh); cpi->cyclic_refresh = NULL; @@ -710,6 +830,11 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { aom_free(cpi->tpl_sb_rdmult_scaling_factors); cpi->tpl_sb_rdmult_scaling_factors = NULL; +#if CONFIG_TUNE_VMAF + aom_free(cpi->vmaf_rdmult_scaling_factors); + cpi->vmaf_rdmult_scaling_factors = NULL; +#endif + aom_free(cpi->td.mb.above_pred_buf); cpi->td.mb.above_pred_buf = NULL; @@ -724,8 +849,8 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) { - aom_free(cpi->td.mb.hash_value_buffer[i][j]); - cpi->td.mb.hash_value_buffer[i][j] = NULL; + aom_free(cpi->td.mb.intrabc_hash_info.hash_value_buffer[i][j]); + cpi->td.mb.intrabc_hash_info.hash_value_buffer[i][j] = NULL; } aom_free(cpi->td.mb.mask_buf); cpi->td.mb.mask_buf = NULL; @@ -736,6 +861,11 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { aom_free(cpi->td.mb.mbmi_ext); cpi->td.mb.mbmi_ext = NULL; + if (cpi->td.vt64x64) { + aom_free(cpi->td.vt64x64); + cpi->td.vt64x64 = NULL; + } + av1_free_ref_frame_buffers(cm->buffer_pool); av1_free_txb_buf(cpi); av1_free_context_buffers(cm); @@ -754,7 +884,7 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { aom_free(cpi->tplist[0][0]); cpi->tplist[0][0] = NULL; - av1_free_pc_tree(&cpi->td, num_planes); + av1_free_pc_tree(cpi, &cpi->td, num_planes, cm->seq_params.sb_size); aom_free(cpi->td.mb.palette_buffer); av1_release_compound_type_rd_buffers(&cpi->td.mb.comp_rd_buffer); @@ -775,7 +905,7 @@ static void dealloc_compressor_data(AV1_COMP *cpi) { } for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { - aom_free(cpi->level_info[i]); + aom_free(cpi->level_params.level_info[i]); } if (cpi->use_svc) av1_free_svc_cyclic_refresh(cpi); @@ -792,10 +922,9 @@ static void configure_static_seg_features(AV1_COMP *cpi) { // Disable and clear down for KF if (cm->current_frame.frame_type == KEY_FRAME) { // Clear down the global segmentation map - memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); seg->update_map = 0; seg->update_data = 0; - cpi->static_mb_pct = 0; // Disable segmentation av1_disable_segmentation(seg); @@ -805,21 +934,14 @@ static void configure_static_seg_features(AV1_COMP *cpi) { } else if (cpi->refresh_alt_ref_frame) { // If this is an alt ref frame // Clear down the global segmentation map - memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols); seg->update_map = 0; seg->update_data = 0; - cpi->static_mb_pct = 0; // Disable segmentation and individual segment features by default av1_disable_segmentation(seg); av1_clearall_segfeatures(seg); -#if !CONFIG_REALTIME_ONLY - // Scan frames from current to arf frame. - // This function re-enables segmentation if appropriate. - av1_update_mbgraph_stats(cpi); -#endif - // If segmentation was enabled set those features needed for the // arf itself. if (seg->enabled) { @@ -867,7 +989,7 @@ static void configure_static_seg_features(AV1_COMP *cpi) { av1_enable_segfeature(seg, 1, SEG_LVL_ALT_LF_V); // Segment coding disabled for compred testing - if (high_q || (cpi->static_mb_pct == 100)) { + if (high_q) { av1_set_segdata(seg, 1, SEG_LVL_REF_FRAME, ALTREF_FRAME); av1_enable_segfeature(seg, 1, SEG_LVL_REF_FRAME); av1_enable_segfeature(seg, 1, SEG_LVL_SKIP); @@ -878,7 +1000,8 @@ static void configure_static_seg_features(AV1_COMP *cpi) { av1_disable_segmentation(seg); - memset(cpi->segmentation_map, 0, cm->mi_rows * cm->mi_cols); + memset(cpi->enc_seg.map, 0, + cm->mi_params.mi_rows * cm->mi_params.mi_cols); seg->update_map = 0; seg->update_data = 0; @@ -919,44 +1042,31 @@ static void configure_static_seg_features(AV1_COMP *cpi) { static void update_reference_segmentation_map(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; - MB_MODE_INFO **mi_4x4_ptr = cm->mi_grid_base; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + MB_MODE_INFO **mi_4x4_ptr = mi_params->mi_grid_base; uint8_t *cache_ptr = cm->cur_frame->seg_map; - int row, col; - for (row = 0; row < cm->mi_rows; row++) { + for (int row = 0; row < mi_params->mi_rows; row++) { MB_MODE_INFO **mi_4x4 = mi_4x4_ptr; uint8_t *cache = cache_ptr; - for (col = 0; col < cm->mi_cols; col++, mi_4x4++, cache++) + for (int col = 0; col < mi_params->mi_cols; col++, mi_4x4++, cache++) cache[0] = mi_4x4[0]->segment_id; - mi_4x4_ptr += cm->mi_stride; - cache_ptr += cm->mi_cols; + mi_4x4_ptr += mi_params->mi_stride; + cache_ptr += mi_params->mi_cols; } } -static void alloc_raw_frame_buffers(AV1_COMP *cpi) { +static void alloc_altref_frame_buffer(AV1_COMP *cpi) { AV1_COMMON *cm = &cpi->common; const SequenceHeader *const seq_params = &cm->seq_params; const AV1EncoderConfig *oxcf = &cpi->oxcf; - int is_scale = (oxcf->resize_mode || oxcf->superres_mode); - - if (!cpi->lookahead) { - 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, is_scale); - } - if (!cpi->lookahead) - aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, - "Failed to allocate lag buffers"); // TODO(agrange) Check if ARF is enabled and skip allocation if not. - // (yunqing)Here use same border as lookahead buffers. if (aom_realloc_frame_buffer( &cpi->alt_ref_buffer, oxcf->width, oxcf->height, seq_params->subsampling_x, seq_params->subsampling_y, - seq_params->use_highbitdepth, - is_scale ? oxcf->border_in_pixels : AOM_ENC_LOOKAHEAD_BORDER, - cm->byte_alignment, NULL, NULL, NULL)) + seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, + cm->features.byte_alignment, NULL, NULL, NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate altref buffer"); } @@ -964,10 +1074,11 @@ static void alloc_raw_frame_buffers(AV1_COMP *cpi) { static void alloc_util_frame_buffers(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; const SequenceHeader *const seq_params = &cm->seq_params; + const int byte_alignment = cm->features.byte_alignment; if (aom_realloc_frame_buffer( &cpi->last_frame_uf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL)) + cpi->oxcf.border_in_pixels, byte_alignment, NULL, NULL, NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate last frame buffer"); @@ -975,14 +1086,14 @@ static void alloc_util_frame_buffers(AV1_COMP *cpi) { &cpi->trial_frame_rst, cm->superres_upscaled_width, cm->superres_upscaled_height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - AOM_RESTORATION_FRAME_BORDER, cm->byte_alignment, NULL, NULL, NULL)) + AOM_RESTORATION_FRAME_BORDER, byte_alignment, NULL, NULL, NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate trial restored frame buffer"); if (aom_realloc_frame_buffer( &cpi->scaled_source, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL)) + cpi->oxcf.border_in_pixels, byte_alignment, NULL, NULL, NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate scaled source buffer"); @@ -990,7 +1101,7 @@ static void alloc_util_frame_buffers(AV1_COMP *cpi) { &cpi->scaled_last_source, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->byte_alignment, NULL, NULL, NULL)) + byte_alignment, NULL, NULL, NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate scaled last source buffer"); } @@ -1005,28 +1116,31 @@ static void alloc_compressor_data(AV1_COMP *cpi) { } int mi_rows_aligned_to_sb = - ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); + ALIGN_POWER_OF_TWO(cm->mi_params.mi_rows, cm->seq_params.mib_size_log2); int sb_rows = mi_rows_aligned_to_sb >> cm->seq_params.mib_size_log2; - av1_alloc_txb_buf(cpi); + if (!is_stat_generation_stage(cpi)) { + av1_alloc_txb_buf(cpi); - alloc_context_buffers_ext(cpi); + alloc_context_buffers_ext(cm, &cpi->mbmi_ext_info); + } aom_free(cpi->tile_tok[0][0]); - - { - unsigned int tokens = - get_token_alloc(cm->mb_rows, cm->mb_cols, MAX_SB_SIZE_LOG2, num_planes); - CHECK_MEM_ERROR(cm, cpi->tile_tok[0][0], - aom_calloc(tokens, sizeof(*cpi->tile_tok[0][0]))); - } aom_free(cpi->tplist[0][0]); - CHECK_MEM_ERROR(cm, cpi->tplist[0][0], - aom_calloc(sb_rows * MAX_TILE_ROWS * MAX_TILE_COLS, - sizeof(*cpi->tplist[0][0]))); + if (!is_stat_generation_stage(cpi)) { + unsigned int tokens = + get_token_alloc(cm->mi_params.mb_rows, cm->mi_params.mb_cols, + MAX_SB_SIZE_LOG2, num_planes); + CHECK_MEM_ERROR(cm, cpi->tile_tok[0][0], + aom_calloc(tokens, sizeof(*cpi->tile_tok[0][0]))); - av1_setup_pc_tree(&cpi->common, &cpi->td); + CHECK_MEM_ERROR(cm, cpi->tplist[0][0], + aom_calloc(sb_rows * MAX_TILE_ROWS * MAX_TILE_COLS, + sizeof(*cpi->tplist[0][0]))); + } + + av1_setup_pc_tree(cpi, &cpi->td); } void av1_new_framerate(AV1_COMP *cpi, double framerate) { @@ -1052,49 +1166,55 @@ double av1_get_compression_ratio(const AV1_COMMON *const cm, static void set_tile_info(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const SequenceHeader *const seq_params = &cm->seq_params; + CommonTileParams *const tiles = &cm->tiles; int i, start_sb; av1_get_tile_limits(cm); // configure tile columns if (cpi->oxcf.tile_width_count == 0 || cpi->oxcf.tile_height_count == 0) { - cm->uniform_tile_spacing_flag = 1; - cm->log2_tile_cols = AOMMAX(cpi->oxcf.tile_columns, cm->min_log2_tile_cols); - cm->log2_tile_cols = AOMMIN(cm->log2_tile_cols, cm->max_log2_tile_cols); + tiles->uniform_spacing = 1; + tiles->log2_cols = AOMMAX(cpi->oxcf.tile_columns, tiles->min_log2_cols); + tiles->log2_cols = AOMMIN(tiles->log2_cols, tiles->max_log2_cols); } else { - int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, cm->seq_params.mib_size_log2); - int sb_cols = mi_cols >> cm->seq_params.mib_size_log2; + int mi_cols = + ALIGN_POWER_OF_TWO(mi_params->mi_cols, seq_params->mib_size_log2); + int sb_cols = mi_cols >> seq_params->mib_size_log2; int size_sb, j = 0; - cm->uniform_tile_spacing_flag = 0; + tiles->uniform_spacing = 0; for (i = 0, start_sb = 0; start_sb < sb_cols && i < MAX_TILE_COLS; i++) { - cm->tile_col_start_sb[i] = start_sb; + tiles->col_start_sb[i] = start_sb; size_sb = cpi->oxcf.tile_widths[j++]; if (j >= cpi->oxcf.tile_width_count) j = 0; - start_sb += AOMMIN(size_sb, cm->max_tile_width_sb); + start_sb += AOMMIN(size_sb, tiles->max_width_sb); } - cm->tile_cols = i; - cm->tile_col_start_sb[i] = sb_cols; + tiles->cols = i; + tiles->col_start_sb[i] = sb_cols; } - av1_calculate_tile_cols(cm); + av1_calculate_tile_cols(seq_params, mi_params->mi_rows, mi_params->mi_cols, + tiles); // configure tile rows - if (cm->uniform_tile_spacing_flag) { - cm->log2_tile_rows = AOMMAX(cpi->oxcf.tile_rows, cm->min_log2_tile_rows); - cm->log2_tile_rows = AOMMIN(cm->log2_tile_rows, cm->max_log2_tile_rows); + if (tiles->uniform_spacing) { + tiles->log2_rows = AOMMAX(cpi->oxcf.tile_rows, tiles->min_log2_rows); + tiles->log2_rows = AOMMIN(tiles->log2_rows, tiles->max_log2_rows); } else { - int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, cm->seq_params.mib_size_log2); - int sb_rows = mi_rows >> cm->seq_params.mib_size_log2; + int mi_rows = + ALIGN_POWER_OF_TWO(mi_params->mi_rows, seq_params->mib_size_log2); + int sb_rows = mi_rows >> seq_params->mib_size_log2; int size_sb, j = 0; for (i = 0, start_sb = 0; start_sb < sb_rows && i < MAX_TILE_ROWS; i++) { - cm->tile_row_start_sb[i] = start_sb; + tiles->row_start_sb[i] = start_sb; size_sb = cpi->oxcf.tile_heights[j++]; if (j >= cpi->oxcf.tile_height_count) j = 0; - start_sb += AOMMIN(size_sb, cm->max_tile_height_sb); + start_sb += AOMMIN(size_sb, tiles->max_height_sb); } - cm->tile_rows = i; - cm->tile_row_start_sb[i] = sb_rows; + tiles->rows = i; + tiles->row_start_sb[i] = sb_rows; } - av1_calculate_tile_rows(cm); + av1_calculate_tile_rows(seq_params, mi_params->mi_rows, tiles); } static void update_frame_size(AV1_COMP *cpi) { @@ -1106,23 +1226,22 @@ static void update_frame_size(AV1_COMP *cpi) { aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate context buffers"); } - av1_init_context_buffers(cm); + av1_init_mi_buffers(&cm->mi_params); av1_init_macroblockd(cm, xd, NULL); - const int ext_mi_size = cm->mi_alloc_rows * cm->mi_alloc_cols; - alloc_context_buffers_ext(cpi); - memset(cpi->mbmi_ext_frame_base, 0, - ext_mi_size * sizeof(*cpi->mbmi_ext_frame_base)); + if (!is_stat_generation_stage(cpi)) + alloc_context_buffers_ext(cm, &cpi->mbmi_ext_info); set_tile_info(cpi); } -static void init_buffer_indices(AV1_COMP *cpi) { +static void init_buffer_indices(ForceIntegerMVInfo *const force_intpel_info, + int *const remapped_ref_idx) { int fb_idx; for (fb_idx = 0; fb_idx < REF_FRAMES; ++fb_idx) - cpi->common.remapped_ref_idx[fb_idx] = fb_idx; - cpi->rate_index = 0; - cpi->rate_size = 0; + remapped_ref_idx[fb_idx] = fb_idx; + force_intpel_info->rate_index = 0; + force_intpel_info->rate_size = 0; } static INLINE int does_level_match(int width, int height, double fps, @@ -1177,33 +1296,27 @@ static void set_bitstream_level_tier(SequenceHeader *seq, AV1_COMMON *cm, level = SEQ_LEVEL_6_0; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 8192, 4352, 60.0, 2)) { + level = SEQ_LEVEL_6_1; } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, 8192, 4352, 120.0, 2)) { level = SEQ_LEVEL_6_2; - } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, - 16384, 8704, 30.0, 2)) { - level = SEQ_LEVEL_7_0; - } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, - 16384, 8704, 60.0, 2)) { - level = SEQ_LEVEL_7_1; - } else if (does_level_match(oxcf->width, oxcf->height, oxcf->init_framerate, - 16384, 8704, 120.0, 2)) { - level = SEQ_LEVEL_7_2; } + + SequenceHeader *const seq_params = &cm->seq_params; for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { 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 = av1_max_level_bitrate( + seq_params->op_params[i].bitrate = av1_max_level_bitrate( 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) + if (seq_params->op_params[i].bitrate == 0) aom_internal_error( &cm->error, AOM_CODEC_UNSUP_BITSTREAM, "AV1 does not support this combination of profile, level, and tier."); // Buffer size in bits/s is bitrate in bits/s * 1 s - cm->op_params[i].buffer_size = cm->op_params[i].bitrate; + seq_params->op_params[i].buffer_size = seq_params->op_params[i].bitrate; } } @@ -1284,78 +1397,80 @@ static void init_seq_coding_tools(SequenceHeader *seq, AV1_COMMON *cm, static void init_config(struct AV1_COMP *cpi, AV1EncoderConfig *oxcf) { AV1_COMMON *const cm = &cpi->common; + SequenceHeader *const seq_params = &cm->seq_params; + ResizePendingParams *resize_pending_params = &cpi->resize_pending_params; cpi->oxcf = *oxcf; cpi->framerate = oxcf->init_framerate; - cm->seq_params.profile = oxcf->profile; - cm->seq_params.bit_depth = oxcf->bit_depth; - cm->seq_params.use_highbitdepth = oxcf->use_highbitdepth; - cm->seq_params.color_primaries = oxcf->color_primaries; - cm->seq_params.transfer_characteristics = oxcf->transfer_characteristics; - cm->seq_params.matrix_coefficients = oxcf->matrix_coefficients; - cm->seq_params.monochrome = oxcf->monochrome; - cm->seq_params.chroma_sample_position = oxcf->chroma_sample_position; - cm->seq_params.color_range = oxcf->color_range; - cm->timing_info_present = oxcf->timing_info_present; - cm->timing_info.num_units_in_display_tick = + seq_params->profile = oxcf->profile; + seq_params->bit_depth = oxcf->bit_depth; + seq_params->use_highbitdepth = oxcf->use_highbitdepth; + seq_params->color_primaries = oxcf->color_primaries; + seq_params->transfer_characteristics = oxcf->transfer_characteristics; + seq_params->matrix_coefficients = oxcf->matrix_coefficients; + seq_params->monochrome = oxcf->monochrome; + seq_params->chroma_sample_position = oxcf->chroma_sample_position; + seq_params->color_range = oxcf->color_range; + seq_params->timing_info_present = oxcf->timing_info_present; + seq_params->timing_info.num_units_in_display_tick = oxcf->timing_info.num_units_in_display_tick; - cm->timing_info.time_scale = oxcf->timing_info.time_scale; - cm->timing_info.equal_picture_interval = + seq_params->timing_info.time_scale = oxcf->timing_info.time_scale; + seq_params->timing_info.equal_picture_interval = oxcf->timing_info.equal_picture_interval; - cm->timing_info.num_ticks_per_picture = + seq_params->timing_info.num_ticks_per_picture = oxcf->timing_info.num_ticks_per_picture; - cm->seq_params.display_model_info_present_flag = + seq_params->display_model_info_present_flag = oxcf->display_model_info_present_flag; - cm->seq_params.decoder_model_info_present_flag = + seq_params->decoder_model_info_present_flag = oxcf->decoder_model_info_present_flag; if (oxcf->decoder_model_info_present_flag) { // set the decoder model parameters in schedule mode - cm->buffer_model.num_units_in_decoding_tick = + seq_params->decoder_model_info.num_units_in_decoding_tick = oxcf->buffer_model.num_units_in_decoding_tick; cm->buffer_removal_time_present = 1; - av1_set_aom_dec_model_info(&cm->buffer_model); - av1_set_dec_model_op_parameters(&cm->op_params[0]); - } else if (cm->timing_info_present && - cm->timing_info.equal_picture_interval && - !cm->seq_params.decoder_model_info_present_flag) { + av1_set_aom_dec_model_info(&seq_params->decoder_model_info); + av1_set_dec_model_op_parameters(&seq_params->op_params[0]); + } else if (seq_params->timing_info_present && + seq_params->timing_info.equal_picture_interval && + !seq_params->decoder_model_info_present_flag) { // set the decoder model parameters in resource availability mode - av1_set_resource_availability_parameters(&cm->op_params[0]); + av1_set_resource_availability_parameters(&seq_params->op_params[0]); } else { - cm->op_params[0].initial_display_delay = + seq_params->op_params[0].initial_display_delay = 10; // Default value (not signaled) } - if (cm->seq_params.monochrome) { - cm->seq_params.subsampling_x = 1; - cm->seq_params.subsampling_y = 1; - } else if (cm->seq_params.color_primaries == AOM_CICP_CP_BT_709 && - cm->seq_params.transfer_characteristics == AOM_CICP_TC_SRGB && - cm->seq_params.matrix_coefficients == AOM_CICP_MC_IDENTITY) { - cm->seq_params.subsampling_x = 0; - cm->seq_params.subsampling_y = 0; + if (seq_params->monochrome) { + seq_params->subsampling_x = 1; + seq_params->subsampling_y = 1; + } else if (seq_params->color_primaries == AOM_CICP_CP_BT_709 && + seq_params->transfer_characteristics == AOM_CICP_TC_SRGB && + seq_params->matrix_coefficients == AOM_CICP_MC_IDENTITY) { + seq_params->subsampling_x = 0; + seq_params->subsampling_y = 0; } else { - if (cm->seq_params.profile == 0) { - cm->seq_params.subsampling_x = 1; - cm->seq_params.subsampling_y = 1; - } else if (cm->seq_params.profile == 1) { - cm->seq_params.subsampling_x = 0; - cm->seq_params.subsampling_y = 0; + if (seq_params->profile == 0) { + seq_params->subsampling_x = 1; + seq_params->subsampling_y = 1; + } else if (seq_params->profile == 1) { + seq_params->subsampling_x = 0; + seq_params->subsampling_y = 0; } else { - if (cm->seq_params.bit_depth == AOM_BITS_12) { - cm->seq_params.subsampling_x = oxcf->chroma_subsampling_x; - cm->seq_params.subsampling_y = oxcf->chroma_subsampling_y; + if (seq_params->bit_depth == AOM_BITS_12) { + seq_params->subsampling_x = oxcf->chroma_subsampling_x; + seq_params->subsampling_y = oxcf->chroma_subsampling_y; } else { - cm->seq_params.subsampling_x = 1; - cm->seq_params.subsampling_y = 0; + seq_params->subsampling_x = 1; + seq_params->subsampling_y = 0; } } } cm->width = oxcf->width; cm->height = oxcf->height; - set_sb_size(&cm->seq_params, + set_sb_size(seq_params, select_sb_size(cpi)); // set sb size before allocations alloc_compressor_data(cpi); @@ -1368,6 +1483,8 @@ static void init_config(struct AV1_COMP *cpi, AV1EncoderConfig *oxcf) { cpi->use_svc = 0; cpi->svc.external_ref_frame_config = 0; cpi->svc.non_reference_frame = 0; + cpi->svc.number_spatial_layers = 1; + cpi->svc.number_temporal_layers = 1; cm->number_spatial_layers = 1; cm->number_temporal_layers = 1; cm->spatial_layer_id = 0; @@ -1376,14 +1493,13 @@ static void init_config(struct AV1_COMP *cpi, AV1EncoderConfig *oxcf) { // change includes all joint functionality av1_change_config(cpi, oxcf); - cpi->static_mb_pct = 0; cpi->ref_frame_flags = 0; // Reset resize pending flags - cpi->resize_pending_width = 0; - cpi->resize_pending_height = 0; + resize_pending_params->width = 0; + resize_pending_params->height = 0; - init_buffer_indices(cpi); + init_buffer_indices(&cpi->force_intpel_info, cm->remapped_ref_idx); } static void set_rc_buffer_sizes(RATE_CONTROL *rc, @@ -2562,29 +2678,31 @@ static void highbd_set_var_fns(AV1_COMP *const cpi) { static void realloc_segmentation_maps(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; + CommonModeInfoParams *const mi_params = &cm->mi_params; // Create the encoder segmentation map and set all entries to 0 - aom_free(cpi->segmentation_map); - CHECK_MEM_ERROR(cm, cpi->segmentation_map, - aom_calloc(cm->mi_rows * cm->mi_cols, 1)); + aom_free(cpi->enc_seg.map); + CHECK_MEM_ERROR(cm, cpi->enc_seg.map, + aom_calloc(mi_params->mi_rows * mi_params->mi_cols, 1)); // Create a map used for cyclic background refresh. if (cpi->cyclic_refresh) av1_cyclic_refresh_free(cpi->cyclic_refresh); - CHECK_MEM_ERROR(cm, cpi->cyclic_refresh, - av1_cyclic_refresh_alloc(cm->mi_rows, cm->mi_cols)); + CHECK_MEM_ERROR( + cm, cpi->cyclic_refresh, + av1_cyclic_refresh_alloc(mi_params->mi_rows, mi_params->mi_cols)); // Create a map used to mark inactive areas. aom_free(cpi->active_map.map); CHECK_MEM_ERROR(cm, cpi->active_map.map, - aom_calloc(cm->mi_rows * cm->mi_cols, 1)); + aom_calloc(mi_params->mi_rows * mi_params->mi_cols, 1)); } -static void set_tpl_stats_block_size(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - const int is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720; +static AOM_INLINE void set_tpl_stats_block_size(int width, int height, + uint8_t *block_mis_log2) { + const int is_720p_or_larger = AOMMIN(width, height) >= 720; // 0: 4x4, 1: 8x8, 2: 16x16 - cpi->tpl_stats_block_mis_log2 = is_720p_or_larger ? 2 : 1; + *block_mis_log2 = is_720p_or_larger ? 2 : 1; } void av1_alloc_compound_type_rd_buffers(AV1_COMMON *const cm, @@ -2630,9 +2748,10 @@ static void config_target_level(AV1_COMP *const cpi, AV1_LEVEL target_level, oxcf->target_bandwidth = AOMMIN(oxcf->target_bandwidth, max_bitrate); // Also need to update cpi->twopass.bits_left. TWO_PASS *const twopass = &cpi->twopass; - FIRSTPASS_STATS *stats = &twopass->total_stats; - cpi->twopass.bits_left = - (int64_t)(stats->duration * cpi->oxcf.target_bandwidth / 10000000.0); + FIRSTPASS_STATS *stats = twopass->stats_buf_ctx->total_stats; + if (stats != NULL) + cpi->twopass.bits_left = + (int64_t)(stats->duration * cpi->oxcf.target_bandwidth / 10000000.0); // Adjust max over-shoot percentage. oxcf->over_shoot_pct = 0; @@ -2665,6 +2784,7 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { const int num_planes = av1_num_planes(cm); RATE_CONTROL *const rc = &cpi->rc; MACROBLOCK *const x = &cpi->td.mb; + AV1LevelParams *const level_params = &cpi->level_params; if (seq_params->profile != oxcf->profile) seq_params->profile = oxcf->profile; seq_params->bit_depth = oxcf->bit_depth; @@ -2678,13 +2798,13 @@ 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)); - cm->timing_info_present = oxcf->timing_info_present; - cm->timing_info.num_units_in_display_tick = + seq_params->timing_info_present = oxcf->timing_info_present; + seq_params->timing_info.num_units_in_display_tick = oxcf->timing_info.num_units_in_display_tick; - cm->timing_info.time_scale = oxcf->timing_info.time_scale; - cm->timing_info.equal_picture_interval = + seq_params->timing_info.time_scale = oxcf->timing_info.time_scale; + seq_params->timing_info.equal_picture_interval = oxcf->timing_info.equal_picture_interval; - cm->timing_info.num_ticks_per_picture = + seq_params->timing_info.num_ticks_per_picture = oxcf->timing_info.num_ticks_per_picture; seq_params->display_model_info_present_flag = @@ -2693,62 +2813,63 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { oxcf->decoder_model_info_present_flag; if (oxcf->decoder_model_info_present_flag) { // set the decoder model parameters in schedule mode - cm->buffer_model.num_units_in_decoding_tick = + seq_params->decoder_model_info.num_units_in_decoding_tick = oxcf->buffer_model.num_units_in_decoding_tick; cm->buffer_removal_time_present = 1; - av1_set_aom_dec_model_info(&cm->buffer_model); - av1_set_dec_model_op_parameters(&cm->op_params[0]); - } else if (cm->timing_info_present && - cm->timing_info.equal_picture_interval && + av1_set_aom_dec_model_info(&seq_params->decoder_model_info); + av1_set_dec_model_op_parameters(&seq_params->op_params[0]); + } else if (seq_params->timing_info_present && + seq_params->timing_info.equal_picture_interval && !seq_params->decoder_model_info_present_flag) { // set the decoder model parameters in resource availability mode - av1_set_resource_availability_parameters(&cm->op_params[0]); + av1_set_resource_availability_parameters(&seq_params->op_params[0]); } else { - cm->op_params[0].initial_display_delay = + seq_params->op_params[0].initial_display_delay = 10; // Default value (not signaled) } update_film_grain_parameters(cpi, oxcf); cpi->oxcf = *oxcf; + cpi->superres_mode = oxcf->superres_mode; // default x->e_mbd.bd = (int)seq_params->bit_depth; x->e_mbd.global_motion = cm->global_motion; - memcpy(cpi->target_seq_level_idx, cpi->oxcf.target_seq_level_idx, - sizeof(cpi->target_seq_level_idx)); - cpi->keep_level_stats = 0; + memcpy(level_params->target_seq_level_idx, cpi->oxcf.target_seq_level_idx, + sizeof(level_params->target_seq_level_idx)); + level_params->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 |= 1u << i; - if (!cpi->level_info[i]) { - CHECK_MEM_ERROR(cm, cpi->level_info[i], - aom_calloc(1, sizeof(*cpi->level_info[i]))); + if (level_params->target_seq_level_idx[i] <= SEQ_LEVELS) { + level_params->keep_level_stats |= 1u << i; + if (!level_params->level_info[i]) { + CHECK_MEM_ERROR(cm, level_params->level_info[i], + aom_calloc(1, sizeof(*level_params->level_info[i]))); } } } // TODO(huisu@): level targeting currently only works for the 0th operating // point, so scalable coding is not supported yet. - if (cpi->target_seq_level_idx[0] < SEQ_LEVELS) { + if (level_params->target_seq_level_idx[0] < SEQ_LEVELS) { // Adjust encoder config in order to meet target level. - config_target_level(cpi, cpi->target_seq_level_idx[0], seq_params->tier[0]); + config_target_level(cpi, level_params->target_seq_level_idx[0], + seq_params->tier[0]); } - if ((oxcf->pass == 0) && (oxcf->rc_mode == AOM_Q)) { + if ((has_no_stats_stage(cpi)) && (oxcf->rc_mode == AOM_Q)) { rc->baseline_gf_interval = FIXED_GF_INTERVAL; } else { rc->baseline_gf_interval = (MIN_GF_INTERVAL + MAX_GF_INTERVAL) / 2; } - cpi->refresh_last_frame = 1; cpi->refresh_golden_frame = 0; cpi->refresh_bwd_ref_frame = 0; - cm->refresh_frame_context = (oxcf->frame_parallel_decoding_mode) - ? REFRESH_FRAME_CONTEXT_DISABLED - : REFRESH_FRAME_CONTEXT_BACKWARD; + cm->features.refresh_frame_context = (oxcf->frame_parallel_decoding_mode) + ? REFRESH_FRAME_CONTEXT_DISABLED + : REFRESH_FRAME_CONTEXT_BACKWARD; if (oxcf->large_scale_tile) - cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; + cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; if (x->palette_buffer == NULL) { CHECK_MEM_ERROR(cm, x->palette_buffer, @@ -2775,7 +2896,8 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { } av1_reset_segment_features(cm); - set_high_precision_mv(cpi, 1, 0); + + av1_set_high_precision_mv(cpi, 1, 0); set_rc_buffer_sizes(rc, &cpi->oxcf); @@ -2791,8 +2913,9 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { rc->worst_quality = cpi->oxcf.worst_allowed_q; rc->best_quality = cpi->oxcf.best_allowed_q; - cm->interp_filter = oxcf->large_scale_tile ? EIGHTTAP_REGULAR : SWITCHABLE; - cm->switchable_motion_mode = 1; + cm->features.interp_filter = + oxcf->large_scale_tile ? EIGHTTAP_REGULAR : SWITCHABLE; + cm->features.switchable_motion_mode = 1; if (cpi->oxcf.render_width > 0 && cpi->oxcf.render_height > 0) { cm->render_width = cpi->oxcf.render_width; @@ -2816,7 +2939,7 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { if (cm->width > cpi->initial_width || cm->height > cpi->initial_height || seq_params->sb_size != sb_size) { av1_free_context_buffers(cm); - av1_free_pc_tree(&cpi->td, num_planes); + av1_free_pc_tree(cpi, &cpi->td, num_planes, (BLOCK_SIZE)sb_size); alloc_compressor_data(cpi); realloc_segmentation_maps(cpi); cpi->initial_width = cpi->initial_height = 0; @@ -2824,14 +2947,13 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { } update_frame_size(cpi); - cpi->alt_ref_source = NULL; rc->is_src_frame_alt_ref = 0; set_tile_info(cpi); if (!cpi->svc.external_ref_frame_config) - cpi->ext_refresh_frame_flags_pending = 0; - cpi->ext_refresh_frame_context_pending = 0; + cpi->ext_flags.refresh_frame_flags_pending = 0; + cpi->ext_flags.refresh_frame_context_pending = 0; #if CONFIG_AV1_HIGHBITDEPTH highbd_set_var_fns(cpi); @@ -2851,9 +2973,67 @@ void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { av1_update_layer_context_change_config(cpi, oxcf->target_bandwidth); } -AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, - BufferPool *const pool) { - unsigned int i; +static INLINE void setup_tpl_buffers(AV1_COMMON *const cm, + TplParams *const tpl_data) { + CommonModeInfoParams *const mi_params = &cm->mi_params; + set_tpl_stats_block_size(cm->width, cm->height, + &tpl_data->tpl_stats_block_mis_log2); + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; + + for (int frame = 0; frame < MAX_LENGTH_TPL_FRAME_STATS; ++frame) { + const int mi_cols = + ALIGN_POWER_OF_TWO(mi_params->mi_cols, MAX_MIB_SIZE_LOG2); + const int mi_rows = + ALIGN_POWER_OF_TWO(mi_params->mi_rows, MAX_MIB_SIZE_LOG2); + + tpl_data->tpl_stats_buffer[frame].is_valid = 0; + tpl_data->tpl_stats_buffer[frame].width = mi_cols >> block_mis_log2; + tpl_data->tpl_stats_buffer[frame].height = mi_rows >> block_mis_log2; + tpl_data->tpl_stats_buffer[frame].stride = + tpl_data->tpl_stats_buffer[frame].width; + tpl_data->tpl_stats_buffer[frame].mi_rows = mi_params->mi_rows; + tpl_data->tpl_stats_buffer[frame].mi_cols = mi_params->mi_cols; + } + + for (int frame = 0; frame < MAX_LAG_BUFFERS; ++frame) { + CHECK_MEM_ERROR( + cm, tpl_data->tpl_stats_pool[frame], + aom_calloc(tpl_data->tpl_stats_buffer[frame].width * + tpl_data->tpl_stats_buffer[frame].height, + sizeof(*tpl_data->tpl_stats_buffer[frame].tpl_stats_ptr))); + if (aom_alloc_frame_buffer( + &tpl_data->tpl_rec_pool[frame], cm->width, cm->height, + cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, + cm->seq_params.use_highbitdepth, AOM_ENC_NO_SCALE_BORDER, + cm->features.byte_alignment)) + aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, + "Failed to allocate frame buffer"); + } + + tpl_data->tpl_frame = &tpl_data->tpl_stats_buffer[REF_FRAMES + 1]; +} + +static INLINE void init_frame_info(FRAME_INFO *frame_info, + const AV1_COMMON *const cm) { + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const SequenceHeader *const seq_params = &cm->seq_params; + frame_info->frame_width = cm->width; + frame_info->frame_height = cm->height; + frame_info->mi_cols = mi_params->mi_cols; + frame_info->mi_rows = mi_params->mi_rows; + frame_info->mb_cols = mi_params->mb_cols; + frame_info->mb_rows = mi_params->mb_rows; + frame_info->num_mbs = mi_params->MBs; + frame_info->bit_depth = seq_params->bit_depth; + frame_info->subsampling_x = seq_params->subsampling_x; + frame_info->subsampling_y = seq_params->subsampling_y; +} + +AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, BufferPool *const pool, + FIRSTPASS_STATS *frame_stats_buf, + COMPRESSOR_STAGE stage, int num_lap_buffers, + int lap_lag_in_frames, + STATS_BUFFER_CTX *stats_buf_context) { AV1_COMP *volatile const cpi = aom_memalign(32, sizeof(AV1_COMP)); AV1_COMMON *volatile const cm = cpi != NULL ? &cpi->common : NULL; @@ -2871,12 +3051,17 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, } cm->error.setjmp = 1; - cm->alloc_mi = enc_alloc_mi; - cm->free_mi = enc_free_mi; - cm->setup_mi = enc_setup_mi; - cm->set_mb_mi = enc_set_mb_mi; + cpi->lap_enabled = num_lap_buffers > 0; + cpi->compressor_stage = stage; - cm->mi_alloc_bsize = BLOCK_4X4; + CommonModeInfoParams *const mi_params = &cm->mi_params; + mi_params->free_mi = enc_free_mi; + mi_params->setup_mi = enc_setup_mi; + mi_params->set_mb_mi = (oxcf->pass == 1 || cpi->compressor_stage == LAP_STAGE) + ? stat_stage_set_mb_mi + : enc_set_mb_mi; + + mi_params->mi_alloc_bsize = BLOCK_4X4; CHECK_MEM_ERROR(cm, cm->fc, (FRAME_CONTEXT *)aom_memalign(32, sizeof(*cm->fc))); @@ -2886,15 +3071,19 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, memset(cm->fc, 0, sizeof(*cm->fc)); memset(cm->default_frame_context, 0, sizeof(*cm->default_frame_context)); - cpi->resize_state = 0; - cpi->resize_avg_qp = 0; - cpi->resize_buffer_underflow = 0; - cpi->common.buffer_pool = pool; init_config(cpi, oxcf); + if (cpi->compressor_stage == LAP_STAGE) { + cpi->oxcf.lag_in_frames = lap_lag_in_frames; + } + av1_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc); + cpi->rc.enable_scenecut_detection = 1; + if (cpi->lap_enabled && + (num_lap_buffers < (MAX_GF_LENGTH_LAP + SCENE_CUT_KEY_TEST_INTERVAL + 1))) + cpi->rc.enable_scenecut_detection = 0; init_frame_info(&cpi->frame_info, cm); cm->current_frame.frame_number = 0; @@ -2905,13 +3094,6 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, cpi->last_show_frame_buf = NULL; realloc_segmentation_maps(cpi); - for (i = 0; i < (sizeof(cpi->mbgraph_stats) / sizeof(cpi->mbgraph_stats[0])); - i++) { - CHECK_MEM_ERROR( - cm, cpi->mbgraph_stats[i].mb_stats, - aom_calloc(cm->MBs * sizeof(*cpi->mbgraph_stats[i].mb_stats), 1)); - } - cpi->refresh_alt_ref_frame = 0; cpi->b_calculate_psnr = CONFIG_INTERNAL_STATS; @@ -2945,9 +3127,10 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, } if (cpi->b_calculate_consistency) { - CHECK_MEM_ERROR(cm, cpi->ssim_vars, - aom_malloc(sizeof(*cpi->ssim_vars) * 4 * - cpi->common.mi_rows * cpi->common.mi_cols)); + CHECK_MEM_ERROR( + cm, cpi->ssim_vars, + aom_malloc(sizeof(*cpi->ssim_vars) * 4 * cpi->common.mi_params.mi_rows * + cpi->common.mi_params.mi_cols)); cpi->worst_consistency = 100.0; } #endif @@ -2955,7 +3138,7 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, av1_zero(aggregate_fc); #endif // CONFIG_ENTROPY_STATS - cpi->first_time_stamp_ever = INT64_MAX; + cpi->time_stamps.first_ever = INT64_MAX; #ifdef OUTPUT_YUV_SKINMAP yuv_skinmap_file = fopen("skinmap.yuv", "ab"); @@ -2964,18 +3147,31 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, yuv_rec_file = fopen("rec.yuv", "wb"); #endif + assert(MAX_LAP_BUFFERS >= MAX_LAG_BUFFERS); + int size = get_stats_buf_size(num_lap_buffers, MAX_LAG_BUFFERS); + for (int i = 0; i < size; i++) + cpi->twopass.frame_stats_arr[i] = &frame_stats_buf[i]; + + cpi->twopass.stats_buf_ctx = stats_buf_context; + cpi->twopass.stats_in = cpi->twopass.stats_buf_ctx->stats_in_start; + #if !CONFIG_REALTIME_ONLY - if (oxcf->pass == 1) { - av1_init_first_pass(cpi); - } else if (oxcf->pass == 2) { + if (is_stat_consumption_stage(cpi)) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz); - 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]; + if (!cpi->lap_enabled) { + /*Re-initialize to stats buffer, populated by application in the case of + * two pass*/ + cpi->twopass.stats_buf_ctx->stats_in_start = oxcf->two_pass_stats_in.buf; + cpi->twopass.stats_in = cpi->twopass.stats_buf_ctx->stats_in_start; + cpi->twopass.stats_buf_ctx->stats_in_end = + &cpi->twopass.stats_buf_ctx->stats_in_start[packets - 1]; - av1_init_second_pass(cpi); + av1_init_second_pass(cpi); + } else { + av1_init_single_pass_lap(cpi); + } } #endif @@ -3001,11 +3197,12 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, for (int x = 0; x < 2; x++) for (int y = 0; y < 2; y++) CHECK_MEM_ERROR( - cm, cpi->td.mb.hash_value_buffer[x][y], - (uint32_t *)aom_malloc(AOM_BUFFER_SIZE_FOR_BLOCK_HASH * - sizeof(*cpi->td.mb.hash_value_buffer[0][0]))); + cm, cpi->td.mb.intrabc_hash_info.hash_value_buffer[x][y], + (uint32_t *)aom_malloc( + AOM_BUFFER_SIZE_FOR_BLOCK_HASH * + sizeof(*cpi->td.mb.intrabc_hash_info.hash_value_buffer[0][0]))); - cpi->td.mb.g_crc_initialized = 0; + cpi->td.mb.intrabc_hash_info.g_crc_initialized = 0; CHECK_MEM_ERROR(cm, cpi->td.mb.mask_buf, (int32_t *)aom_memalign( @@ -3021,8 +3218,8 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, const int bsize = BLOCK_16X16; const int w = mi_size_wide[bsize]; const int h = mi_size_high[bsize]; - const int num_cols = (cm->mi_cols + w - 1) / w; - const int num_rows = (cm->mi_rows + h - 1) / h; + const int num_cols = (mi_params->mi_cols + w - 1) / w; + const int num_rows = (mi_params->mi_rows + h - 1) / h; CHECK_MEM_ERROR(cm, cpi->tpl_rdmult_scaling_factors, aom_calloc(num_rows * num_cols, sizeof(*cpi->tpl_rdmult_scaling_factors))); @@ -3035,42 +3232,30 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, const int bsize = BLOCK_16X16; const int w = mi_size_wide[bsize]; const int h = mi_size_high[bsize]; - const int num_cols = (cm->mi_cols + w - 1) / w; - const int num_rows = (cm->mi_rows + h - 1) / h; + const int num_cols = (mi_params->mi_cols + w - 1) / w; + const int num_rows = (mi_params->mi_rows + h - 1) / h; CHECK_MEM_ERROR(cm, cpi->ssim_rdmult_scaling_factors, aom_calloc(num_rows * num_cols, sizeof(*cpi->ssim_rdmult_scaling_factors))); } - set_tpl_stats_block_size(cpi); - for (int frame = 0; frame < MAX_LENGTH_TPL_FRAME_STATS; ++frame) { - const int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2); - const int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, MAX_MIB_SIZE_LOG2); - - cpi->tpl_stats_buffer[frame].is_valid = 0; - cpi->tpl_stats_buffer[frame].width = - mi_cols >> cpi->tpl_stats_block_mis_log2; - cpi->tpl_stats_buffer[frame].height = - mi_rows >> cpi->tpl_stats_block_mis_log2; - cpi->tpl_stats_buffer[frame].stride = cpi->tpl_stats_buffer[frame].width; - cpi->tpl_stats_buffer[frame].mi_rows = cm->mi_rows; - cpi->tpl_stats_buffer[frame].mi_cols = cm->mi_cols; - - CHECK_MEM_ERROR( - cm, cpi->tpl_stats_buffer[frame].tpl_stats_ptr, - aom_calloc(cpi->tpl_stats_buffer[frame].width * - cpi->tpl_stats_buffer[frame].height, - sizeof(*cpi->tpl_stats_buffer[frame].tpl_stats_ptr))); - - if (aom_alloc_frame_buffer( - &cpi->tpl_stats_buffer[frame].rec_picture_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->byte_alignment)) - aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, - "Failed to allocate frame buffer"); +#if CONFIG_TUNE_VMAF + { + const int bsize = BLOCK_64X64; + const int w = mi_size_wide[bsize]; + const int h = mi_size_high[bsize]; + const int num_cols = (mi_params->mi_cols + w - 1) / w; + const int num_rows = (mi_params->mi_rows + h - 1) / h; + CHECK_MEM_ERROR(cm, cpi->vmaf_rdmult_scaling_factors, + aom_calloc(num_rows * num_cols, + sizeof(*cpi->vmaf_rdmult_scaling_factors))); + cpi->last_frame_unsharp_amount = 0.0; + } +#endif + + if (!is_stat_generation_stage(cpi)) { + setup_tpl_buffers(cm, &cpi->tpl_data); } - cpi->tpl_frame = &cpi->tpl_stats_buffer[REF_FRAMES + 1]; #if CONFIG_COLLECT_PARTITION_STATS == 2 av1_zero(cpi->partition_stats); @@ -3285,8 +3470,9 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, * called later when needed. This will avoid unnecessary calls of * av1_init_quantizer() for every frame. */ - av1_init_quantizer(cpi); - av1_qm_init(cm); + av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, + cm->seq_params.bit_depth); + av1_qm_init(&cm->quant_params, av1_num_planes(cm)); av1_loop_filter_init(cm); cm->superres_scale_denominator = SCALE_NUMERATOR; @@ -3308,7 +3494,7 @@ AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, void av1_remove_compressor(AV1_COMP *cpi) { AV1_COMMON *cm; - unsigned int i; + TplParams *const tpl_data = &cpi->tpl_data; int t; if (!cpi) return; @@ -3318,7 +3504,7 @@ void av1_remove_compressor(AV1_COMP *cpi) { if (cm->current_frame.frame_number > 0) { #if CONFIG_ENTROPY_STATS - if (cpi->oxcf.pass != 1) { + if (!is_stat_generation_stage(cpi)) { fprintf(stderr, "Writing counts.stt\n"); FILE *f = fopen("counts.stt", "wb"); fwrite(&aggregate_fc, sizeof(aggregate_fc), 1, f); @@ -3328,12 +3514,12 @@ void av1_remove_compressor(AV1_COMP *cpi) { #if CONFIG_INTERNAL_STATS aom_clear_system_state(); - if (cpi->oxcf.pass != 1) { + if (!is_stat_generation_stage(cpi)) { char headings[512] = { 0 }; char results[512] = { 0 }; FILE *f = fopen("opsnr.stt", "a"); double time_encoded = - (cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) / + (cpi->time_stamps.prev_end_seen - cpi->time_stamps.first_ever) / 10000000.000; double total_encode_time = (cpi->time_receive_data + cpi->time_compress_data) / 1000.000; @@ -3399,24 +3585,21 @@ void av1_remove_compressor(AV1_COMP *cpi) { } #endif // CONFIG_INTERNAL_STATS #if CONFIG_SPEED_STATS - if (cpi->oxcf.pass != 1) { + if (!is_stat_generation_stage(cpi)) { fprintf(stdout, "tx_search_count = %d\n", cpi->tx_search_count); } #endif // CONFIG_SPEED_STATS #if CONFIG_COLLECT_PARTITION_STATS == 2 - if (cpi->oxcf.pass != 1) { + if (!is_stat_generation_stage(cpi)) { av1_print_partition_stats(&cpi->partition_stats); } #endif } - for (int frame = 0; frame < MAX_LENGTH_TPL_FRAME_STATS; ++frame) { - aom_free(cpi->tpl_stats_buffer[frame].tpl_stats_ptr); - cpi->tpl_stats_buffer[frame].is_valid = 0; - - aom_free_frame_buffer(&cpi->tpl_stats_buffer[frame].rec_picture_buf); - cpi->tpl_stats_buffer[frame].rec_picture = NULL; + for (int frame = 0; frame < MAX_LAG_BUFFERS; ++frame) { + aom_free(tpl_data->tpl_stats_pool[frame]); + aom_free_frame_buffer(&tpl_data->tpl_rec_pool[frame]); } for (t = cpi->num_workers - 1; t >= 0; --t) { @@ -3438,6 +3621,7 @@ void av1_remove_compressor(AV1_COMP *cpi) { aom_free(thread_data->td->above_pred_buf); aom_free(thread_data->td->left_pred_buf); aom_free(thread_data->td->wsrc_buf); + aom_free(thread_data->td->vt64x64); aom_free(thread_data->td->inter_modes_info); for (int x = 0; x < 2; x++) { @@ -3448,7 +3632,8 @@ void av1_remove_compressor(AV1_COMP *cpi) { } aom_free(thread_data->td->mask_buf); aom_free(thread_data->td->counts); - av1_free_pc_tree(thread_data->td, num_planes); + av1_free_pc_tree(cpi, thread_data->td, num_planes, + cm->seq_params.sb_size); aom_free(thread_data->td->mbmi_ext); aom_free(thread_data->td); } @@ -3470,24 +3655,17 @@ void av1_remove_compressor(AV1_COMP *cpi) { dealloc_compressor_data(cpi); - for (i = 0; i < sizeof(cpi->mbgraph_stats) / sizeof(cpi->mbgraph_stats[0]); - ++i) { - aom_free(cpi->mbgraph_stats[i].mb_stats); - } - #if CONFIG_INTERNAL_STATS aom_free(cpi->ssim_vars); cpi->ssim_vars = NULL; #endif // CONFIG_INTERNAL_STATS av1_remove_common(cm); - for (i = 0; i < FRAME_BUFFERS; ++i) { - av1_hash_table_destroy(&cm->buffer_pool->frame_bufs[i].hash_table); - } #if CONFIG_HTB_TRELLIS if (cpi->sf.use_hash_based_trellis) hbt_destroy(); #endif // CONFIG_HTB_TRELLIS av1_free_ref_frame_buffers(cm->buffer_pool); + aom_free(cpi); #ifdef OUTPUT_YUV_SKINMAP @@ -3503,12 +3681,10 @@ static void generate_psnr_packet(AV1_COMP *cpi) { int i; PSNR_STATS psnr; #if CONFIG_AV1_HIGHBITDEPTH - // TODO(yaowu): unify these two versions into one. - if (cpi->common.seq_params.use_highbitdepth) - aom_calc_highbd_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr, - cpi->td.mb.e_mbd.bd, cpi->oxcf.input_bit_depth); - else - aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr); + const uint32_t in_bit_depth = cpi->oxcf.input_bit_depth; + const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; + aom_calc_highbd_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr, + bit_depth, in_bit_depth); #else aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr); #endif @@ -3522,10 +3698,10 @@ static void generate_psnr_packet(AV1_COMP *cpi) { aom_codec_pkt_list_add(cpi->output_pkt_list, &pkt); } -int av1_use_as_reference(AV1_COMP *cpi, int ref_frame_flags) { +int av1_use_as_reference(int *ext_ref_frame_flags, int ref_frame_flags) { if (ref_frame_flags > ((1 << INTER_REFS_PER_FRAME) - 1)) return -1; - cpi->ext_ref_frame_flags = ref_frame_flags; + *ext_ref_frame_flags = ref_frame_flags; return 0; } @@ -3553,9 +3729,10 @@ int av1_set_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd) { } } -int av1_update_entropy(AV1_COMP *cpi, int update) { - cpi->ext_refresh_frame_context = update; - cpi->ext_refresh_frame_context_pending = 1; +int av1_update_entropy(bool *ext_refresh_frame_context, + bool *ext_refresh_frame_context_pending, bool update) { + *ext_refresh_frame_context = update; + *ext_refresh_frame_context_pending = 1; return 0; } @@ -3650,18 +3827,18 @@ void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) { #endif // OUTPUT_YUV_REC #define GM_RECODE_LOOP_NUM4X4_FACTOR 192 -static int recode_loop_test_global_motion(AV1_COMP *cpi) { +static int recode_loop_test_global_motion( + WarpedMotionParams *const global_motion, + const int *const global_motion_used, int *const gm_params_cost) { int i; int recode = 0; - RD_COUNTS *const rdc = &cpi->td.rd_counts; - AV1_COMMON *const cm = &cpi->common; for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { - if (cm->global_motion[i].wmtype != IDENTITY && - rdc->global_motion_used[i] * GM_RECODE_LOOP_NUM4X4_FACTOR < - cpi->gmparams_cost[i]) { - cm->global_motion[i] = default_warp_params; - assert(cm->global_motion[i].wmtype == IDENTITY); - cpi->gmparams_cost[i] = 0; + if (global_motion[i].wmtype != IDENTITY && + global_motion_used[i] * GM_RECODE_LOOP_NUM4X4_FACTOR < + gm_params_cost[i]) { + global_motion[i] = default_warp_params; + assert(global_motion[i].wmtype == IDENTITY); + gm_params_cost[i] = 0; recode = 1; // TODO(sarahparker): The earlier condition for recoding here was: // "recode |= (rdc->global_motion_used[i] > 0);". Can we bring something @@ -3681,8 +3858,9 @@ static int recode_loop_test(AV1_COMP *cpi, int high_limit, int low_limit, int q, int force_recode = 0; if ((rc->projected_frame_size >= rc->max_frame_bandwidth) || - (cpi->sf.recode_loop == ALLOW_RECODE) || - (frame_is_kfgfarf && (cpi->sf.recode_loop == ALLOW_RECODE_KFARFGF))) { + (cpi->sf.hl_sf.recode_loop == ALLOW_RECODE) || + (frame_is_kfgfarf && + (cpi->sf.hl_sf.recode_loop == ALLOW_RECODE_KFARFGF))) { // TODO(agrange) high_limit could be greater than the scale-down threshold. if ((rc->projected_frame_size > high_limit && q < maxq) || (rc->projected_frame_size < low_limit && q > minq)) { @@ -3725,8 +3903,8 @@ static void scale_references(AV1_COMP *cpi) { 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) { + &ref_fb->buf, AOM_BORDER_IN_PIXELS, + cm->features.byte_alignment, num_planes) != 0) { aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); } @@ -3749,7 +3927,7 @@ static void scale_references(AV1_COMP *cpi) { &new_fb->buf, cm->width, cm->height, cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, cm->seq_params.use_highbitdepth, AOM_BORDER_IN_PIXELS, - cm->byte_alignment, NULL, NULL, NULL)) { + cm->features.byte_alignment, NULL, NULL, NULL)) { if (force_scaling) { // Release the reference acquired in the get_free_fb() call above. --new_fb->ref_count; @@ -3770,7 +3948,7 @@ static void scale_references(AV1_COMP *cpi) { ++buf->ref_count; } } else { - if (cpi->oxcf.pass != 0) cpi->scaled_ref_buf[ref_frame - 1] = NULL; + if (!has_no_stats_stage(cpi)) cpi->scaled_ref_buf[ref_frame - 1] = NULL; } } } @@ -3788,51 +3966,60 @@ static void release_scaled_references(AV1_COMP *cpi) { static void set_mv_search_params(AV1_COMP *cpi) { const AV1_COMMON *const cm = &cpi->common; - const unsigned int max_mv_def = AOMMIN(cm->width, cm->height); + MotionVectorSearchParams *const mv_search_params = &cpi->mv_search_params; + const int max_mv_def = AOMMAX(cm->width, cm->height); // Default based on max resolution. - cpi->mv_step_param = av1_init_search_range(max_mv_def); + mv_search_params->mv_step_param = av1_init_search_range(max_mv_def); - if (cpi->sf.mv.auto_mv_step_size) { + if (cpi->sf.mv_sf.auto_mv_step_size) { if (frame_is_intra_only(cm)) { // Initialize max_mv_magnitude for use in the first INTER frame // after a key/intra-only frame. - cpi->max_mv_magnitude = max_mv_def; + mv_search_params->max_mv_magnitude = max_mv_def; } else { - if (cm->show_frame) { + // Use cpi->max_mv_magnitude == -1 to exclude first pass case. + if (cm->show_frame && mv_search_params->max_mv_magnitude != -1) { // Allow mv_steps to correspond to twice the max mv magnitude found // in the previous frame, capped by the default max_mv_magnitude based // on resolution. - cpi->mv_step_param = av1_init_search_range( - AOMMIN(max_mv_def, 2 * cpi->max_mv_magnitude)); + mv_search_params->mv_step_param = av1_init_search_range( + AOMMIN(max_mv_def, 2 * mv_search_params->max_mv_magnitude)); } - cpi->max_mv_magnitude = 0; + mv_search_params->max_mv_magnitude = -1; } } } -static void set_screen_content_options(AV1_COMP *cpi) { - AV1_COMMON *cm = &cpi->common; +void av1_set_screen_content_options(const AV1_COMP *cpi, + FeatureFlags *features) { + const AV1_COMMON *const cm = &cpi->common; if (cm->seq_params.force_screen_content_tools != 2) { - cm->allow_screen_content_tools = cm->allow_intrabc = + features->allow_screen_content_tools = features->allow_intrabc = cm->seq_params.force_screen_content_tools; return; } + if (cpi->oxcf.mode == REALTIME) { + assert(cm->seq_params.reduced_still_picture_hdr); + features->allow_screen_content_tools = features->allow_intrabc = 0; + return; + } + if (cpi->oxcf.content == AOM_CONTENT_SCREEN) { - cm->allow_screen_content_tools = cm->allow_intrabc = 1; + features->allow_screen_content_tools = features->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; + const uint8_t *src = cpi->unfiltered_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 use_hbd = cpi->unfiltered_source->flags & YV12_FLAG_HIGHBITDEPTH; + const int stride = cpi->unfiltered_source->y_stride; + const int width = cpi->unfiltered_source->y_width; + const int height = cpi->unfiltered_source->y_height; const int bd = cm->seq_params.bit_depth; const int blk_w = 16; const int blk_h = 16; @@ -3868,56 +4055,73 @@ static void set_screen_content_options(AV1_COMP *cpi) { } // The threshold values are selected experimentally. - cm->allow_screen_content_tools = + features->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 * 12 > width * height; + features->allow_intrabc = features->allow_screen_content_tools && + counts_2 * blk_h * blk_w * 12 > width * height; } static void set_size_independent_vars(AV1_COMP *cpi) { int i; - AV1_COMMON *cm = &cpi->common; + AV1_COMMON *const cm = &cpi->common; for (i = LAST_FRAME; i <= ALTREF_FRAME; ++i) { 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); + cpi->gm_info.search_done = 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; + cm->features.interp_filter = SWITCHABLE; + cm->features.switchable_motion_mode = 1; } #if !CONFIG_REALTIME_ONLY -static int get_gfu_boost_from_r0(double r0, int frames_to_key) { - double factor = sqrt((double)frames_to_key); - factor = AOMMIN(factor, 10.0); - factor = AOMMAX(factor, 4.0); - const int boost = (int)rint((200.0 + 10.0 * factor) / r0); +double av1_get_gfu_boost_projection_factor(double min_factor, double max_factor, + int frame_count) { + double factor = sqrt((double)frame_count); + factor = AOMMIN(factor, max_factor); + factor = AOMMAX(factor, min_factor); + factor = (200.0 + 10.0 * factor); + return factor; +} + +static int get_gfu_boost_from_r0_lap(double min_factor, double max_factor, + double r0, int frames_to_key) { + double factor = av1_get_gfu_boost_projection_factor(min_factor, max_factor, + frames_to_key); + const int boost = (int)rint(factor / r0); return boost; } -static int get_kf_boost_from_r0(double r0, int frames_to_key) { - double factor = sqrt((double)frames_to_key); +double av1_get_kf_boost_projection_factor(int frame_count) { + double factor = sqrt((double)frame_count); factor = AOMMIN(factor, 10.0); factor = AOMMAX(factor, 4.0); - const int boost = (int)rint((75.0 + 14.0 * factor) / r0); + factor = (75.0 + 14.0 * factor); + return factor; +} + +static int get_kf_boost_from_r0(double r0, int frames_to_key) { + double factor = av1_get_kf_boost_projection_factor(frames_to_key); + const int boost = (int)rint(factor / r0); return boost; } #endif -int combine_prior_with_tpl_boost(int prior_boost, int tpl_boost, +#define MIN_BOOST_COMBINE_FACTOR 4.0 +#define MAX_BOOST_COMBINE_FACTOR 12.0 +int combine_prior_with_tpl_boost(double min_factor, double max_factor, + int prior_boost, int tpl_boost, int frames_to_key) { double factor = sqrt((double)frames_to_key); - factor = AOMMIN(factor, 12.0); - factor = AOMMAX(factor, 4.0); - factor -= 4.0; - int boost = (int)((factor * prior_boost + (8.0 - factor) * tpl_boost) / 8.0); + double range = max_factor - min_factor; + factor = AOMMIN(factor, max_factor); + factor = AOMMAX(factor, min_factor); + factor -= min_factor; + int boost = + (int)((factor * prior_boost + (range - factor) * tpl_boost) / range); return boost; } @@ -3929,34 +4133,31 @@ static void process_tpl_stats_frame(AV1_COMP *cpi) { assert(IMPLIES(gf_group->size > 0, gf_group->index < gf_group->size)); const int tpl_idx = gf_group->index; - TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_idx]; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx]; TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; if (tpl_frame->is_valid) { int tpl_stride = tpl_frame->stride; int64_t intra_cost_base = 0; int64_t mc_dep_cost_base = 0; -#if !USE_TPL_CLASSIC_MODEL int64_t mc_saved_base = 0; int64_t mc_count_base = 0; -#endif // !USE_TPL_CLASSIC_MODEL - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << tpl_data->tpl_stats_block_mis_log2; const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); - for (int row = 0; row < cm->mi_rows; row += step) { + for (int row = 0; row < cm->mi_params.mi_rows; row += step) { for (int col = 0; col < mi_cols_sr; col += step) { - TplDepStats *this_stats = - &tpl_stats[av1_tpl_ptr_pos(cpi, row, col, tpl_stride)]; + TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos( + row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)]; int64_t mc_dep_delta = RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate, this_stats->mc_dep_dist); intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS); mc_dep_cost_base += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta; -#if !USE_TPL_CLASSIC_MODEL mc_count_base += this_stats->mc_count; mc_saved_base += this_stats->mc_saved; -#endif // !USE_TPL_CLASSIC_MODEL } } @@ -3967,12 +4168,22 @@ static void process_tpl_stats_frame(AV1_COMP *cpi) { cpi->rd.r0 = (double)intra_cost_base / mc_dep_cost_base; if (is_frame_arf_and_tpl_eligible(gf_group)) { cpi->rd.arf_r0 = cpi->rd.r0; - const int gfu_boost = - get_gfu_boost_from_r0(cpi->rd.arf_r0, cpi->rc.frames_to_key); - // printf("old boost %d new boost %d\n", cpi->rc.gfu_boost, - // gfu_boost); - cpi->rc.gfu_boost = combine_prior_with_tpl_boost( - cpi->rc.gfu_boost, gfu_boost, cpi->rc.frames_to_key); + if (cpi->lap_enabled) { + double min_boost_factor = sqrt(cpi->rc.baseline_gf_interval); + const int gfu_boost = get_gfu_boost_from_r0_lap( + min_boost_factor, MAX_GFUBOOST_FACTOR, cpi->rd.arf_r0, + cpi->rc.num_stats_required_for_gfu_boost); + // printf("old boost %d new boost %d\n", cpi->rc.gfu_boost, + // gfu_boost); + cpi->rc.gfu_boost = combine_prior_with_tpl_boost( + min_boost_factor, MAX_BOOST_COMBINE_FACTOR, cpi->rc.gfu_boost, + gfu_boost, cpi->rc.num_stats_used_for_gfu_boost); + } else { + const int gfu_boost = (int)(200.0 / cpi->rd.r0); + cpi->rc.gfu_boost = combine_prior_with_tpl_boost( + MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR, + cpi->rc.gfu_boost, gfu_boost, cpi->rc.frames_to_key); + } } else if (frame_is_intra_only(cm)) { // TODO(debargha): Turn off q adjustment for kf temporarily to // reduce impact on speed of encoding. Need to investigate how @@ -3980,45 +4191,37 @@ static void process_tpl_stats_frame(AV1_COMP *cpi) { if (cpi->oxcf.rc_mode == AOM_Q) { const int kf_boost = get_kf_boost_from_r0(cpi->rd.r0, cpi->rc.frames_to_key); - // printf("old kf boost %d new kf boost %d [%d]\n", cpi->rc.kf_boost, - // kf_boost, cpi->rc.frames_to_key); - cpi->rc.kf_boost = combine_prior_with_tpl_boost( - cpi->rc.kf_boost, kf_boost, cpi->rc.frames_to_key); + if (cpi->lap_enabled) { + cpi->rc.kf_boost = combine_prior_with_tpl_boost( + MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR, + cpi->rc.kf_boost, kf_boost, + cpi->rc.num_stats_used_for_kf_boost); + } else { + cpi->rc.kf_boost = combine_prior_with_tpl_boost( + MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR, + cpi->rc.kf_boost, kf_boost, cpi->rc.frames_to_key); + } } } -#if !USE_TPL_CLASSIC_MODEL - cpi->rd.mc_count_base = - (double)mc_count_base / (cm->mi_rows * cm->mi_cols); - cpi->rd.mc_saved_base = - (double)mc_saved_base / (cm->mi_rows * cm->mi_cols); -#endif // !USE_TPL_CLASSIC_MODEL + cpi->rd.mc_count_base = (double)mc_count_base / + (cm->mi_params.mi_rows * cm->mi_params.mi_cols); + cpi->rd.mc_saved_base = (double)mc_saved_base / + (cm->mi_params.mi_rows * cm->mi_params.mi_cols); aom_clear_system_state(); } } } #endif // !CONFIG_REALTIME_ONLY -static int determine_frame_high_precision_mv(const AV1_COMP *cpi, int qindex) { - (void)cpi; - if (cpi->sf.reduce_high_precision_mv_usage == 2) - return 0; - else if (cpi->sf.reduce_high_precision_mv_usage == 1) - return qindex < HIGH_PRECISION_MV_QTHRESH / 2; - else - return qindex < HIGH_PRECISION_MV_QTHRESH; -} - static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index, int *top_index) { AV1_COMMON *const cm = &cpi->common; - const AV1EncoderConfig *const oxcf = &cpi->oxcf; // Setup variables that depend on the dimensions of the frame. av1_set_speed_features_framesize_dependent(cpi, cpi->speed); #if !CONFIG_REALTIME_ONLY - if (cpi->oxcf.enable_tpl_model && cpi->tpl_model_pass == 0 && - is_frame_tpl_eligible(cpi)) { + if (cpi->oxcf.enable_tpl_model && is_frame_tpl_eligible(cpi)) { process_tpl_stats_frame(cpi); av1_tpl_rdmult_setup(cpi); } @@ -4028,50 +4231,49 @@ static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index, *q = av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cm->width, cm->height, cpi->gf_group.index, bottom_index, top_index); - if (!frame_is_intra_only(cm)) { - const int use_hp = cpi->common.cur_frame_force_integer_mv - ? 0 - : determine_frame_high_precision_mv(cpi, *q); - set_high_precision_mv(cpi, use_hp, cpi->common.cur_frame_force_integer_mv); - } - // Configure experimental use of segmentation for enhanced coding of // static regions if indicated. // Only allowed in the second pass of a two pass encode, as it requires // lagged coding, and if the relevant speed feature flag is set. - if (oxcf->pass == 2 && cpi->sf.static_segmentation) + if (is_stat_consumption_stage_twopass(cpi) && + cpi->sf.hl_sf.static_segmentation) configure_static_seg_features(cpi); } static void init_motion_estimation(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; + MotionVectorSearchParams *const mv_search_params = &cpi->mv_search_params; const int y_stride = cpi->scaled_source.y_stride; const int y_stride_src = ((cpi->oxcf.width != cm->width || cpi->oxcf.height != cm->height) || av1_superres_scaled(cm)) ? y_stride : cpi->lookahead->buf->img.y_stride; + int fpf_y_stride = cm->cur_frame != NULL ? cm->cur_frame->buf.y_stride + : cpi->scaled_source.y_stride; + // Update if ss_cfg is uninitialized or the current frame has a new stride - const int should_update = !cpi->ss_cfg[SS_CFG_SRC].stride || - !cpi->ss_cfg[SS_CFG_LOOKAHEAD].stride || - (y_stride != cpi->ss_cfg[SS_CFG_SRC].stride); + const int should_update = + !mv_search_params->ss_cfg[SS_CFG_SRC].stride || + !mv_search_params->ss_cfg[SS_CFG_LOOKAHEAD].stride || + (y_stride != mv_search_params->ss_cfg[SS_CFG_SRC].stride); if (!should_update) { return; } - if (cpi->sf.mv.search_method == DIAMOND) { - av1_init_dsmotion_compensation(&cpi->ss_cfg[SS_CFG_SRC], y_stride); - av1_init_dsmotion_compensation(&cpi->ss_cfg[SS_CFG_LOOKAHEAD], + if (cpi->sf.mv_sf.search_method == DIAMOND) { + av1_init_dsmotion_compensation(&mv_search_params->ss_cfg[SS_CFG_SRC], + y_stride); + av1_init_dsmotion_compensation(&mv_search_params->ss_cfg[SS_CFG_LOOKAHEAD], y_stride_src); } else { - // Update the offsets in search_sites as y_stride can change due to scaled - // references. This update allows NSTEP to be used on scaled references as - // long as sf.mv.search_method is not DIAMOND. Currently in the codebae, - // sf.mv.search_method is never set to DIAMOND. - av1_init3smotion_compensation(&cpi->ss_cfg[SS_CFG_SRC], y_stride); - av1_init3smotion_compensation(&cpi->ss_cfg[SS_CFG_LOOKAHEAD], y_stride_src); + av1_init3smotion_compensation(&mv_search_params->ss_cfg[SS_CFG_SRC], + y_stride); + av1_init3smotion_compensation(&mv_search_params->ss_cfg[SS_CFG_LOOKAHEAD], + y_stride_src); } + av1_init_motion_fpf(&mv_search_params->ss_cfg[SS_CFG_FPF], fpf_y_stride); } #define COUPLED_CHROMA_FROM_LUMA_RESTORATION 0 @@ -4106,15 +4308,10 @@ static void init_ref_frame_bufs(AV1_COMP *cpi) { for (i = 0; i < FRAME_BUFFERS; ++i) { pool->frame_bufs[i].ref_count = 0; } - if (cm->seq_params.force_screen_content_tools) { - for (i = 0; i < FRAME_BUFFERS; ++i) { - av1_hash_table_init(&pool->frame_bufs[i].hash_table, &cpi->td.mb); - } - } } -static void check_initial_width(AV1_COMP *cpi, int use_highbitdepth, - int subsampling_x, int subsampling_y) { +void av1_check_initial_width(AV1_COMP *cpi, int use_highbitdepth, + int subsampling_x, int subsampling_y) { AV1_COMMON *const cm = &cpi->common; SequenceHeader *const seq_params = &cm->seq_params; @@ -4125,15 +4322,20 @@ static void check_initial_width(AV1_COMP *cpi, int use_highbitdepth, seq_params->subsampling_y = subsampling_y; seq_params->use_highbitdepth = use_highbitdepth; - alloc_raw_frame_buffers(cpi); + av1_set_speed_features_framesize_independent(cpi, cpi->oxcf.speed); + av1_set_speed_features_framesize_dependent(cpi, cpi->oxcf.speed); + + if (!is_stat_generation_stage(cpi)) { + alloc_altref_frame_buffer(cpi); + alloc_util_frame_buffers(cpi); + } init_ref_frame_bufs(cpi); - alloc_util_frame_buffers(cpi); init_motion_estimation(cpi); // TODO(agrange) This can be removed. cpi->initial_width = cm->width; cpi->initial_height = cm->height; - cpi->initial_mbs = cm->MBs; + cpi->initial_mbs = cm->mi_params.MBs; } } @@ -4141,9 +4343,9 @@ static void check_initial_width(AV1_COMP *cpi, int use_highbitdepth, int av1_set_size_literal(AV1_COMP *cpi, int width, int height) { AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); - check_initial_width(cpi, cm->seq_params.use_highbitdepth, - cm->seq_params.subsampling_x, - cm->seq_params.subsampling_y); + av1_check_initial_width(cpi, cm->seq_params.use_highbitdepth, + cm->seq_params.subsampling_x, + cm->seq_params.subsampling_y); if (width <= 0 || height <= 0) return 1; @@ -4153,7 +4355,7 @@ int av1_set_size_literal(AV1_COMP *cpi, int width, int height) { if (cpi->initial_width && cpi->initial_height && (cm->width > cpi->initial_width || cm->height > cpi->initial_height)) { av1_free_context_buffers(cm); - av1_free_pc_tree(&cpi->td, num_planes); + av1_free_pc_tree(cpi, &cpi->td, num_planes, cm->seq_params.sb_size); alloc_compressor_data(cpi); realloc_segmentation_maps(cpi); cpi->initial_width = cpi->initial_height = 0; @@ -4173,23 +4375,27 @@ void av1_set_frame_size(AV1_COMP *cpi, int width, int height) { if (width != cm->width || height != cm->height) { // There has been a change in the encoded frame size av1_set_size_literal(cpi, width, height); - set_mv_search_params(cpi); // Recalculate 'all_lossless' in case super-resolution was (un)selected. - cm->all_lossless = cm->coded_lossless && !av1_superres_scaled(cm); + cm->features.all_lossless = + cm->features.coded_lossless && !av1_superres_scaled(cm); } + set_mv_search_params(cpi); - if (cpi->oxcf.pass == 2) { + if (is_stat_consumption_stage(cpi)) { av1_set_target_rate(cpi, cm->width, cm->height); } alloc_frame_mvs(cm, cm->cur_frame); // Allocate above context buffers - if (cm->num_allocated_above_context_planes < av1_num_planes(cm) || - cm->num_allocated_above_context_mi_col < cm->mi_cols || - cm->num_allocated_above_contexts < cm->tile_rows) { - av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts); - if (av1_alloc_above_context_buffers(cm, cm->tile_rows)) + CommonContexts *const above_contexts = &cm->above_contexts; + if (above_contexts->num_planes < av1_num_planes(cm) || + above_contexts->num_mi_cols < cm->mi_params.mi_cols || + above_contexts->num_tile_rows < cm->tiles.rows) { + av1_free_above_context_buffers(above_contexts); + if (av1_alloc_above_context_buffers(above_contexts, cm->tiles.rows, + cm->mi_params.mi_cols, + av1_num_planes(cm))) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate context buffers"); } @@ -4198,7 +4404,8 @@ void av1_set_frame_size(AV1_COMP *cpi, int width, int height) { if (aom_realloc_frame_buffer( &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x, seq_params->subsampling_y, seq_params->use_highbitdepth, - cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL)) + cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL, + NULL)) aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer"); @@ -4211,7 +4418,7 @@ void av1_set_frame_size(AV1_COMP *cpi, int width, int height) { cm->rst_info[i].frame_restoration_type = RESTORE_NONE; av1_alloc_restoration_buffers(cm); - alloc_util_frame_buffers(cpi); + if (!is_stat_generation_stage(cpi)) alloc_util_frame_buffers(cpi); init_motion_estimation(cpi); for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { @@ -4235,7 +4442,7 @@ static uint8_t calculate_next_resize_scale(const AV1_COMP *cpi) { // Choose an arbitrary random number static unsigned int seed = 56789; const AV1EncoderConfig *oxcf = &cpi->oxcf; - if (oxcf->pass == 1) return SCALE_NUMERATOR; + if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR; uint8_t new_denom = SCALE_NUMERATOR; if (cpi->common.seq_params.reduced_still_picture_hdr) return SCALE_NUMERATOR; @@ -4333,6 +4540,7 @@ static uint8_t get_superres_denom_for_qindex(const AV1_COMP *cpi, int qindex, */ #if CONFIG_SUPERRES_IN_RECODE if (superres_in_recode_allowed(cpi)) { + assert(cpi->superres_mode != SUPERRES_NONE); // Force superres to be tried in the recode loop, as full-res is also going // to be tried anyway. denom = AOMMAX(denom, SCALE_NUMERATOR + 1); @@ -4341,11 +4549,15 @@ static uint8_t get_superres_denom_for_qindex(const AV1_COMP *cpi, int qindex, return denom; } +// If true, SUPERRES_AUTO mode will exhaustively search over all superres +// denominators for all frames (except overlay and internal overlay frames). +#define SUPERRES_RECODE_ALL_RATIOS 0 + static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { // Choose an arbitrary random number static unsigned int seed = 34567; const AV1EncoderConfig *oxcf = &cpi->oxcf; - if (oxcf->pass == 1) return SCALE_NUMERATOR; + if (is_stat_generation_stage(cpi)) return SCALE_NUMERATOR; uint8_t new_denom = SCALE_NUMERATOR; // Make sure that superres mode of the frame is consistent with the @@ -4354,8 +4566,14 @@ static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { cpi->common.seq_params.enable_superres)); assert(IMPLIES(!cpi->common.seq_params.enable_superres, oxcf->superres_mode == SUPERRES_NONE)); + // Make sure that superres mode for current encoding is consistent with user + // provided superres mode. + assert(IMPLIES(oxcf->superres_mode != SUPERRES_AUTO, + cpi->superres_mode == oxcf->superres_mode)); - switch (oxcf->superres_mode) { + // Note: we must look at the current superres_mode to be tried in 'cpi' here, + // not the user given mode in 'oxcf'. + switch (cpi->superres_mode) { case SUPERRES_NONE: new_denom = SCALE_NUMERATOR; break; case SUPERRES_FIXED: if (cpi->common.current_frame.frame_type == KEY_FRAME) @@ -4366,7 +4584,7 @@ static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { case SUPERRES_RANDOM: new_denom = lcg_rand16(&seed) % 9 + 8; break; case SUPERRES_QTHRESH: { // Do not use superres when screen content tools are used. - if (cpi->common.allow_screen_content_tools) break; + if (cpi->common.features.allow_screen_content_tools) break; if (oxcf->rc_mode == AOM_VBR || oxcf->rc_mode == AOM_CQ) av1_set_target_rate(cpi, cpi->oxcf.width, cpi->oxcf.height); @@ -4388,7 +4606,7 @@ static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { } case SUPERRES_AUTO: { // Do not use superres when screen content tools are used. - if (cpi->common.allow_screen_content_tools) break; + if (cpi->common.features.allow_screen_content_tools) break; if (oxcf->rc_mode == AOM_VBR || oxcf->rc_mode == AOM_CQ) av1_set_target_rate(cpi, cpi->oxcf.width, cpi->oxcf.height); @@ -4402,7 +4620,14 @@ static uint8_t calculate_next_superres_scale(AV1_COMP *cpi) { if (q <= qthresh) { new_denom = SCALE_NUMERATOR; } else { +#if SUPERRES_RECODE_ALL_RATIOS + if (cpi->common.current_frame.frame_type == KEY_FRAME) + new_denom = oxcf->superres_kf_scale_denominator; + else + new_denom = oxcf->superres_scale_denominator; +#else new_denom = get_superres_denom_for_qindex(cpi, q, 1, 1); +#endif // SUPERRES_RECODE_ALL_RATIOS } break; } @@ -4481,28 +4706,29 @@ static int validate_size_scales(RESIZE_MODE resize_mode, // Calculates resize and superres params for next frame static size_params_type calculate_next_size_params(AV1_COMP *cpi) { const AV1EncoderConfig *oxcf = &cpi->oxcf; + ResizePendingParams *resize_pending_params = &cpi->resize_pending_params; size_params_type rsz = { oxcf->width, oxcf->height, SCALE_NUMERATOR }; int resize_denom = SCALE_NUMERATOR; - if (oxcf->pass == 0 && cpi->use_svc && + if (has_no_stats_stage(cpi) && cpi->use_svc && cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1) { rsz.resize_width = cpi->common.width; rsz.resize_height = cpi->common.height; return rsz; } - if (oxcf->pass == 1) return rsz; - if (cpi->resize_pending_width && cpi->resize_pending_height) { - rsz.resize_width = cpi->resize_pending_width; - rsz.resize_height = cpi->resize_pending_height; - cpi->resize_pending_width = cpi->resize_pending_height = 0; + if (is_stat_generation_stage(cpi)) return rsz; + if (resize_pending_params->width && resize_pending_params->height) { + rsz.resize_width = resize_pending_params->width; + rsz.resize_height = resize_pending_params->height; + resize_pending_params->width = resize_pending_params->height = 0; } else { resize_denom = calculate_next_resize_scale(cpi); - rsz.resize_width = cpi->oxcf.width; - rsz.resize_height = cpi->oxcf.height; + rsz.resize_width = oxcf->width; + rsz.resize_height = oxcf->height; av1_calculate_scaled_size(&rsz.resize_width, &rsz.resize_height, resize_denom); } rsz.superres_denom = calculate_next_superres_scale(cpi); - if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, oxcf->width, + if (!validate_size_scales(oxcf->resize_mode, cpi->superres_mode, oxcf->width, oxcf->height, &rsz)) assert(0 && "Invalid scale parameters"); return rsz; @@ -4540,7 +4766,7 @@ static void superres_post_encode(AV1_COMP *cpi) { assert(cpi->oxcf.enable_superres); assert(!is_lossless_requested(&cpi->oxcf)); - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); av1_superres_upscale(cm, NULL); @@ -4559,7 +4785,8 @@ static void superres_post_encode(AV1_COMP *cpi) { &cpi->scaled_source, cm->superres_upscaled_width, cm->superres_upscaled_height, cm->seq_params.subsampling_x, cm->seq_params.subsampling_y, cm->seq_params.use_highbitdepth, - AOM_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL)) + AOM_BORDER_IN_PIXELS, cm->features.byte_alignment, NULL, NULL, + NULL)) aom_internal_error( &cm->error, AOM_CODEC_MEM_ERROR, "Failed to reallocate scaled source buffer for superres"); @@ -4583,7 +4810,7 @@ static void cdef_restoration_frame(AV1_COMP *cpi, AV1_COMMON *cm, #endif // Find CDEF parameters av1_cdef_search(&cm->cur_frame->buf, cpi->source, cm, xd, - cpi->sf.cdef_pick_method, cpi->td.mb.rdmult); + cpi->sf.lpf_sf.cdef_pick_method, cpi->td.mb.rdmult); // Apply the filter av1_cdef_frame(&cm->cur_frame->buf, cm, xd); @@ -4631,13 +4858,15 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { MACROBLOCKD *xd = &cpi->td.mb.e_mbd; assert(IMPLIES(is_lossless_requested(&cpi->oxcf), - cm->coded_lossless && cm->all_lossless)); + cm->features.coded_lossless && cm->features.all_lossless)); - 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_loopfilter = + !cm->features.coded_lossless && !cm->tiles.large_scale; + const int use_cdef = cm->seq_params.enable_cdef && + !cm->features.coded_lossless && !cm->tiles.large_scale; const int use_restoration = cm->seq_params.enable_restoration && - !cm->all_lossless && !cm->large_scale_tile; + !cm->features.all_lossless && + !cm->tiles.large_scale; struct loopfilter *lf = &cm->lf; @@ -4646,7 +4875,7 @@ static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { #endif if (use_loopfilter) { aom_clear_system_state(); - av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick); + av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_sf.lpf_pick); } else { lf->filter_level[0] = 0; lf->filter_level[1] = 0; @@ -4732,14 +4961,14 @@ static void finalize_encoded_frame(AV1_COMP *const cpi) { } // Initialise all tiles' contexts from the global frame context - for (int tile_col = 0; tile_col < cm->tile_cols; tile_col++) { - for (int tile_row = 0; tile_row < cm->tile_rows; tile_row++) { - const int tile_idx = tile_row * cm->tile_cols + tile_col; + for (int tile_col = 0; tile_col < cm->tiles.cols; tile_col++) { + for (int tile_row = 0; tile_row < cm->tiles.rows; tile_row++) { + const int tile_idx = tile_row * cm->tiles.cols + tile_col; cpi->tile_data[tile_idx].tctx = *cm->fc; } } - fix_interp_filter(&cm->interp_filter, cpi->td.counts); + fix_interp_filter(&cm->features.interp_filter, cpi->td.counts); } static int get_regulated_q_overshoot(AV1_COMP *const cpi, int q_low, int q_high, @@ -4794,6 +5023,7 @@ static void recode_loop_update_q( int *const low_cr_seen, const int loop_at_this_size) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; + *loop = 0; const int min_cr = cpi->oxcf.min_cr; if (min_cr > 0) { @@ -4971,7 +5201,7 @@ static uint16_t setup_interp_filter_search_mask(AV1_COMP *cpi) { int ref_total[REF_FRAMES] = { 0 }; uint16_t mask = ALLOW_ALL_INTERP_FILT_MASK; - if (cpi->common.last_frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame) + if (cpi->last_frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame) return mask; for (MV_REFERENCE_FRAME ref = LAST_FRAME; ref <= ALTREF_FRAME; ++ref) { @@ -5004,25 +5234,191 @@ static uint16_t setup_interp_filter_search_mask(AV1_COMP *cpi) { return mask; } +#if !CONFIG_REALTIME_ONLY +#define STRICT_PSNR_DIFF_THRESH 0.9 +// Encode key frame with/without screen content tools to determine whether +// screen content tools should be enabled for this key frame group or not. +// The first encoding is without screen content tools. +// The second encoding is with screen content tools. +// We compare the psnr and frame size to make the decision. +static void screen_content_tools_determination( + AV1_COMP *cpi, const int allow_screen_content_tools_orig_decision, + const int allow_intrabc_orig_decision, + const int is_screen_content_type_orig_decision, const int pass, + int *projected_size_pass, PSNR_STATS *psnr) { + AV1_COMMON *const cm = &cpi->common; + FeatureFlags *const features = &cm->features; + projected_size_pass[pass] = cpi->rc.projected_frame_size; +#if CONFIG_AV1_HIGHBITDEPTH + const uint32_t in_bit_depth = cpi->oxcf.input_bit_depth; + const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; + aom_calc_highbd_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass], + bit_depth, in_bit_depth); +#else + aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass]); +#endif + if (pass != 1) return; + + const double psnr_diff = psnr[1].psnr[0] - psnr[0].psnr[0]; + const int is_sc_encoding_much_better = psnr_diff > STRICT_PSNR_DIFF_THRESH; + if (is_sc_encoding_much_better) { + // Use screen content tools, if we get coding gain. + features->allow_screen_content_tools = 1; + features->allow_intrabc = cpi->intrabc_used; + cpi->is_screen_content_type = 1; + } else { + // Use original screen content decision. + features->allow_screen_content_tools = + allow_screen_content_tools_orig_decision; + features->allow_intrabc = allow_intrabc_orig_decision; + cpi->is_screen_content_type = is_screen_content_type_orig_decision; + } +} + +// Set some encoding parameters to make the encoding process fast. +// A fixed block partition size, and a large q is used. +static void set_encoding_params_for_screen_content(AV1_COMP *cpi, + const int pass) { + AV1_COMMON *const cm = &cpi->common; + if (pass == 0) { + // In the first pass, encode without screen content tools. + // Use a high q, and a fixed block size for fast encoding. + cm->features.allow_screen_content_tools = 0; + cm->features.allow_intrabc = 0; + cpi->is_screen_content_type = 0; + cpi->sf.part_sf.partition_search_type = FIXED_PARTITION; + cpi->sf.part_sf.always_this_block_size = BLOCK_32X32; + return; + } + assert(pass == 1); + // In the second pass, encode with screen content tools. + // Use a high q, and a fixed block size for fast encoding. + cm->features.allow_screen_content_tools = 1; + // TODO(chengchen): turn intrabc on could lead to data race issue. + // cm->allow_intrabc = 1; + cpi->is_screen_content_type = 1; + cpi->sf.part_sf.partition_search_type = FIXED_PARTITION; + cpi->sf.part_sf.always_this_block_size = BLOCK_32X32; +} + +// Determines whether to use screen content tools for the key frame group. +// This function modifies "cm->features.allow_screen_content_tools", +// "cm->features.allow_intrabc" and "cpi->is_screen_content_type". +static void determine_sc_tools_with_encoding(AV1_COMP *cpi, const int q_orig) { + AV1_COMMON *const cm = &cpi->common; + // Variables to help determine if we should allow screen content tools. + int projected_size_pass[3] = { 0 }; + PSNR_STATS psnr[3]; + const int is_key_frame = cm->current_frame.frame_type == KEY_FRAME; + const int allow_screen_content_tools_orig_decision = + cm->features.allow_screen_content_tools; + const int allow_intrabc_orig_decision = cm->features.allow_intrabc; + const int is_screen_content_type_orig_decision = cpi->is_screen_content_type; + // Turn off the encoding trial for forward key frame and superres. + if (cpi->sf.rt_sf.use_nonrd_pick_mode || cpi->oxcf.fwd_kf_enabled || + cpi->superres_mode != SUPERRES_NONE || cpi->oxcf.mode == REALTIME || + is_screen_content_type_orig_decision || !is_key_frame) { + return; + } + + // TODO(chengchen): multiple encoding for the lossless mode is time consuming. + // Find a better way to determine whether screen content tools should be used + // for lossless coding. + // Use a high q and a fixed partition to do quick encoding. + const int q_for_screen_content_quick_run = + is_lossless_requested(&cpi->oxcf) ? q_orig : AOMMAX(q_orig, 244); + const int partition_search_type_orig = cpi->sf.part_sf.partition_search_type; + const BLOCK_SIZE fixed_partition_block_size_orig = + cpi->sf.part_sf.always_this_block_size; + + // Setup necessary params for encoding, including frame source, etc. + aom_clear_system_state(); + + cpi->source = + av1_scale_if_required(cm, cpi->unscaled_source, &cpi->scaled_source); + if (cpi->unscaled_last_source != NULL) { + cpi->last_source = av1_scale_if_required(cm, cpi->unscaled_last_source, + &cpi->scaled_last_source); + } + + setup_frame(cpi); + + if (cm->seg.enabled) { + if (!cm->seg.update_data && cm->prev_frame) { + segfeatures_copy(&cm->seg, &cm->prev_frame->seg); + cm->seg.enabled = cm->prev_frame->seg.enabled; + } else { + av1_calculate_segdata(&cm->seg); + } + } else { + memset(&cm->seg, 0, sizeof(cm->seg)); + } + segfeatures_copy(&cm->cur_frame->seg, &cm->seg); + cm->cur_frame->seg.enabled = cm->seg.enabled; + + // The two encoding passes aim to help determine whether to use screen + // content tools, with a high q and fixed partition. + for (int pass = 0; pass < 2; ++pass) { + set_encoding_params_for_screen_content(cpi, pass); +#if CONFIG_TUNE_VMAF + if (cpi->oxcf.tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + cpi->oxcf.tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_set_quantizer( + cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + av1_get_vmaf_base_qindex(cpi, q_for_screen_content_quick_run)); + } else { +#endif + av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + q_for_screen_content_quick_run); +#if CONFIG_TUNE_VMAF + } +#endif + av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); + if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, + cm->seq_params.bit_depth); + + av1_set_variance_partition_thresholds(cpi, q_for_screen_content_quick_run, + 0); + // transform / motion compensation build reconstruction frame + av1_encode_frame(cpi); + // Screen content decision + screen_content_tools_determination( + cpi, allow_screen_content_tools_orig_decision, + allow_intrabc_orig_decision, is_screen_content_type_orig_decision, pass, + projected_size_pass, psnr); + } + + // Set partition speed feature back. + cpi->sf.part_sf.partition_search_type = partition_search_type_orig; + cpi->sf.part_sf.always_this_block_size = fixed_partition_block_size_orig; +} +#endif // CONFIG_REALTIME_ONLY + static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; - const int allow_recode = (cpi->sf.recode_loop != DISALLOW_RECODE); + GlobalMotionInfo *const gm_info = &cpi->gm_info; + const int allow_recode = (cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE); // Must allow recode if minimum compression ratio is set. assert(IMPLIES(cpi->oxcf.min_cr > 0, allow_recode)); set_size_independent_vars(cpi); - if (cpi->oxcf.pass == 2 && cpi->sf.adaptive_interp_filter_search) - cpi->sf.interp_filter_search_mask = setup_interp_filter_search_mask(cpi); + if (is_stat_consumption_stage_twopass(cpi) && + cpi->sf.interp_sf.adaptive_interp_filter_search) + cpi->interp_search_flags.interp_filter_search_mask = + setup_interp_filter_search_mask(cpi); cpi->source->buf_8bit_valid = 0; av1_setup_frame_size(cpi); #if CONFIG_SUPERRES_IN_RECODE - if (superres_in_recode_allowed(cpi) && + if (superres_in_recode_allowed(cpi) && cpi->superres_mode != SUPERRES_NONE && cm->superres_scale_denominator == SCALE_NUMERATOR) { - // Superres won't be picked, so no need to try, as we will go through - // another recode loop for full-resolution after this anyway. + // Superres mode is currently enabled, but the denominator selected will + // disable superres. So no need to continue, as we will go through another + // recode loop for full-resolution after this anyway. return -1; } #endif // CONFIG_SUPERRES_IN_RECODE @@ -5032,47 +5428,71 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { set_size_dependent_vars(cpi, &q, &bottom_index, &top_index); q_low = bottom_index; q_high = top_index; - - if (cpi->sf.tx_type_search.prune_tx_type_using_stats && - cm->current_frame.frame_type == KEY_FRAME) { - av1_copy(cpi->tx_type_probs, default_tx_type_probs); - - int thr[2][2] = { { 15, 10 }, { 17, 10 } }; - for (int f = 0; f < FRAME_UPDATE_TYPES; f++) { - int kf_arf_update = (f == KF_UPDATE || f == ARF_UPDATE); - cpi->tx_type_probs_thresh[f] = - thr[cpi->sf.tx_type_search.prune_tx_type_using_stats - 1] - [kf_arf_update]; + if (cpi->sf.part_sf.partition_search_type == VAR_BASED_PARTITION) { + const int num_64x64_blocks = + (cm->seq_params.sb_size == BLOCK_64X64) ? 1 : 4; + if (cpi->td.vt64x64) { + if (num_64x64_blocks != cpi->td.num_64x64_blocks) { + aom_free(cpi->td.vt64x64); + cpi->td.vt64x64 = NULL; + } + } + if (!cpi->td.vt64x64) { + CHECK_MEM_ERROR(cm, cpi->td.vt64x64, + aom_malloc(sizeof(*cpi->td.vt64x64) * num_64x64_blocks)); + cpi->td.num_64x64_blocks = num_64x64_blocks; } } - if (cpi->sf.prune_obmc_using_stats && - cm->current_frame.frame_type == KEY_FRAME) { - av1_copy(cpi->obmc_probs, default_obmc_probs); - cpi->obmc_probs_thresh = 16; - } + if (cm->current_frame.frame_type == KEY_FRAME) { + FrameProbInfo *const frame_probs = &cpi->frame_probs; - // Loop variables - int loop_count = 0; - int loop_at_this_size = 0; - int loop = 0; - int overshoot_seen = 0; - int undershoot_seen = 0; - int low_cr_seen = 0; + if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) { + av1_copy(frame_probs->tx_type_probs, default_tx_type_probs); + } + + if (!cpi->sf.inter_sf.disable_obmc && + cpi->sf.inter_sf.prune_obmc_prob_thresh > 0) { + av1_copy(frame_probs->obmc_probs, default_obmc_probs); + } + + if (cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { + av1_copy(frame_probs->warped_probs, default_warped_probs); + } + + if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { + av1_copy(frame_probs->switchable_interp_probs, + default_switchable_interp_probs); + } + } +#if !CONFIG_REALTIME_ONLY + // Determine whether to use screen content tools using two fast encoding. + determine_sc_tools_with_encoding(cpi, q); +#endif // CONFIG_REALTIME_ONLY #if CONFIG_COLLECT_COMPONENT_TIMING printf("\n Encoding a frame:"); #endif + + // Loop variables + int loop = 0; + int loop_count = 0; + int loop_at_this_size = 0; + int overshoot_seen = 0; + int undershoot_seen = 0; + int low_cr_seen = 0; + int last_loop_allow_hp = 0; + do { loop = 0; aom_clear_system_state(); // if frame was scaled calculate global_motion_search again if already // done - if (loop_count > 0 && cpi->source && cpi->global_motion_search_done) { + if (loop_count > 0 && cpi->source && gm_info->search_done) { if (cpi->source->y_crop_width != cm->width || cpi->source->y_crop_height != cm->height) { - cpi->global_motion_search_done = 0; + gm_info->search_done = 0; } } cpi->source = @@ -5088,8 +5508,23 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { } scale_references(cpi); } - av1_set_quantizer(cm, q); - if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) av1_init_quantizer(cpi); +#if CONFIG_TUNE_VMAF + if (cpi->oxcf.tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + cpi->oxcf.tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + av1_get_vmaf_base_qindex(cpi, q)); + } else { +#endif + av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, q); +#if CONFIG_TUNE_VMAF + } +#endif + av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); + + if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, + cm->seq_params.bit_depth); av1_set_variance_partition_thresholds(cpi, q, 0); @@ -5132,8 +5567,35 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, av1_encode_frame_time); #endif + // Set the motion vector precision based on mv stats from the last coded + // frame. + if (!frame_is_intra_only(cm)) { + av1_pick_and_set_high_precision_mv(cpi, q); + + // If the precision has changed during different iteration of the loop, + // then we need to reset the global motion vectors + if (loop_count > 0 && + cm->features.allow_high_precision_mv != last_loop_allow_hp) { + gm_info->search_done = 0; + } + last_loop_allow_hp = cm->features.allow_high_precision_mv; + } + // transform / motion compensation build reconstruction frame av1_encode_frame(cpi); +#if !CONFIG_REALTIME_ONLY + // Reset the mv_stats in case we are interrupted by an intraframe or an + // overlay frame. + if (cpi->mv_stats.valid) { + av1_zero(cpi->mv_stats); + } + // Gather the mv_stats for the next frame + if (cpi->sf.hl_sf.high_precision_mv_usage == LAST_MV_DATA && + av1_frame_allows_smart_mv(cpi)) { + av1_collect_mv_stats(cpi, q); + } +#endif // !CONFIG_REALTIME_ONLY + #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, av1_encode_frame_time); #endif @@ -5143,14 +5605,17 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { // Dummy pack of the bitstream using up to date stats to get an // accurate estimate of output frame size to determine if we need // to recode. - const int do_dummy_pack = (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF && - cpi->oxcf.rc_mode != AOM_Q) || - cpi->oxcf.min_cr > 0; + const int do_dummy_pack = + (cpi->sf.hl_sf.recode_loop >= ALLOW_RECODE_KFARFGF && + cpi->oxcf.rc_mode != AOM_Q) || + cpi->oxcf.min_cr > 0; if (do_dummy_pack) { finalize_encoded_frame(cpi); int largest_tile_id = 0; // Output from bitstream: unused here - if (av1_pack_bitstream(cpi, dest, size, &largest_tile_id) != AOM_CODEC_OK) + if (av1_pack_bitstream(cpi, dest, size, &largest_tile_id) != + AOM_CODEC_OK) { return AOM_CODEC_ERROR; + } rc->projected_frame_size = (int)(*size) << 3; } @@ -5168,20 +5633,13 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { loop = 0; } - if (allow_recode && !cpi->sf.gm_disable_recode && - recode_loop_test_global_motion(cpi)) { + if (allow_recode && !cpi->sf.gm_sf.gm_disable_recode && + recode_loop_test_global_motion(cm->global_motion, + cpi->td.rd_counts.global_motion_used, + gm_info->params_cost)) { loop = 1; } -#if !CONFIG_REALTIME_ONLY - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - av1_tpl_setup_forward_stats(cpi); - cpi->tpl_model_pass = 0; - loop = 1; - } -#endif - if (loop) { ++loop_count; ++loop_at_this_size; @@ -5196,8 +5654,7 @@ static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest) { } while (loop); // Update some stats from cyclic refresh. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled && - !frame_is_intra_only(cm)) + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && !frame_is_intra_only(cm)) av1_cyclic_refresh_postencode(cpi); return AOM_CODEC_OK; @@ -5265,7 +5722,7 @@ static int encode_with_recode_loop_and_filter(AV1_COMP *cpi, size_t *size, // off. // Pick the loop filter level for the frame. - if (!cm->allow_intrabc) { + if (!cm->features.allow_intrabc) { loopfilter_frame(cpi, cm); } else { cm->lf.filter_level[0] = 0; @@ -5326,7 +5783,7 @@ static void save_cur_buf(AV1_COMP *cpi) { ybf->y_crop_height, ybf->subsampling_x, ybf->subsampling_y, ybf->flags & YV12_FLAG_HIGHBITDEPTH, ybf->border, - cm->byte_alignment) != AOM_CODEC_OK) { + cm->features.byte_alignment) != AOM_CODEC_OK) { aom_internal_error( &cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate copy buffer for saving coding context"); @@ -5376,39 +5833,103 @@ static void restore_all_coding_context(AV1_COMP *cpi) { if (!frame_is_intra_only(&cpi->common)) release_scaled_references(cpi); } +static void release_copy_buffer(CODING_CONTEXT *cc) { + aom_free_frame_buffer(&cc->copy_buffer); +} + static int encode_with_and_without_superres(AV1_COMP *cpi, size_t *size, uint8_t *dest, int *largest_tile_id) { const AV1_COMMON *const cm = &cpi->common; - AV1EncoderConfig *const oxcf = &cpi->oxcf; assert(cm->seq_params.enable_superres); assert(superres_in_recode_allowed(cpi)); aom_codec_err_t err = AOM_CODEC_OK; save_all_coding_context(cpi); // Encode with superres. +#if SUPERRES_RECODE_ALL_RATIOS + AV1EncoderConfig *const oxcf = &cpi->oxcf; + int64_t superres_sses[SCALE_NUMERATOR]; + int64_t superres_rates[SCALE_NUMERATOR]; + int superres_largest_tile_ids[SCALE_NUMERATOR]; + // Use superres for Key-frames and Alt-ref frames only. + const GF_GROUP *const gf_group = &cpi->gf_group; + if (gf_group->update_type[gf_group->index] != OVERLAY_UPDATE && + gf_group->update_type[gf_group->index] != INTNL_OVERLAY_UPDATE) { + for (int denom = SCALE_NUMERATOR + 1; denom <= 2 * SCALE_NUMERATOR; + ++denom) { + oxcf->superres_scale_denominator = denom; + oxcf->superres_kf_scale_denominator = denom; + const int this_index = denom - (SCALE_NUMERATOR + 1); + err = encode_with_recode_loop_and_filter( + cpi, size, dest, &superres_sses[this_index], + &superres_rates[this_index], &superres_largest_tile_ids[this_index]); + if (err != AOM_CODEC_OK) return err; + restore_all_coding_context(cpi); + } + // Reset. + oxcf->superres_scale_denominator = SCALE_NUMERATOR; + oxcf->superres_kf_scale_denominator = SCALE_NUMERATOR; + } else { + for (int denom = SCALE_NUMERATOR + 1; denom <= 2 * SCALE_NUMERATOR; + ++denom) { + const int this_index = denom - (SCALE_NUMERATOR + 1); + superres_sses[this_index] = INT64_MAX; + superres_rates[this_index] = INT64_MAX; + } + } +#else int64_t sse1 = INT64_MAX; int64_t rate1 = INT64_MAX; int largest_tile_id1; err = encode_with_recode_loop_and_filter(cpi, size, dest, &sse1, &rate1, &largest_tile_id1); if (err != AOM_CODEC_OK) return err; + restore_all_coding_context(cpi); +#endif // SUPERRES_RECODE_ALL_RATIOS // Encode without superres. - restore_all_coding_context(cpi); int64_t sse2 = INT64_MAX; int64_t rate2 = INT64_MAX; int largest_tile_id2; - oxcf->superres_mode = SUPERRES_NONE; // To force full-res. + cpi->superres_mode = SUPERRES_NONE; // To force full-res. err = encode_with_recode_loop_and_filter(cpi, size, dest, &sse2, &rate2, &largest_tile_id2); - oxcf->superres_mode = SUPERRES_AUTO; // Reset. + cpi->superres_mode = cpi->oxcf.superres_mode; // Reset. + assert(cpi->oxcf.superres_mode == SUPERRES_AUTO); if (err != AOM_CODEC_OK) return err; // Note: Both use common rdmult based on base qindex of fullres. const int64_t rdmult = - av1_compute_rd_mult_based_on_qindex(cpi, cm->base_qindex); + av1_compute_rd_mult_based_on_qindex(cpi, cm->quant_params.base_qindex); + +#if SUPERRES_RECODE_ALL_RATIOS + // Find the best rdcost among all superres denoms. + double proj_rdcost1 = DBL_MAX; + int64_t sse1 = INT64_MAX; + int64_t rate1 = INT64_MAX; + int largest_tile_id1 = 0; + (void)sse1; + (void)rate1; + (void)largest_tile_id1; + int best_denom = -1; + for (int denom = SCALE_NUMERATOR + 1; denom <= 2 * SCALE_NUMERATOR; ++denom) { + const int this_index = denom - (SCALE_NUMERATOR + 1); + const int64_t this_sse = superres_sses[this_index]; + const int64_t this_rate = superres_rates[this_index]; + const int this_largest_tile_id = superres_largest_tile_ids[this_index]; + const double this_rdcost = RDCOST_DBL(rdmult, this_rate, this_sse); + if (this_rdcost < proj_rdcost1) { + sse1 = this_sse; + rate1 = this_rate; + largest_tile_id1 = this_largest_tile_id; + proj_rdcost1 = this_rdcost; + best_denom = denom; + } + } +#else const double proj_rdcost1 = RDCOST_DBL(rdmult, rate1, sse1); +#endif // SUPERRES_RECODE_ALL_RATIOS const double proj_rdcost2 = RDCOST_DBL(rdmult, rate2, sse2); // Re-encode with superres if it's better. @@ -5417,6 +5938,11 @@ static int encode_with_and_without_superres(AV1_COMP *cpi, size_t *size, // TODO(urvang): We should avoid rerunning the recode loop by saving // previous output+state, or running encode only for the selected 'q' in // previous step. +#if SUPERRES_RECODE_ALL_RATIOS + // Again, temporarily force the best denom. + oxcf->superres_scale_denominator = best_denom; + oxcf->superres_kf_scale_denominator = best_denom; +#endif // SUPERRES_RECODE_ALL_RATIOS int64_t sse3 = INT64_MAX; int64_t rate3 = INT64_MAX; err = encode_with_recode_loop_and_filter(cpi, size, dest, &sse3, &rate3, @@ -5424,10 +5950,17 @@ static int encode_with_and_without_superres(AV1_COMP *cpi, size_t *size, assert(sse1 == sse3); assert(rate1 == rate3); assert(largest_tile_id1 == *largest_tile_id); +#if SUPERRES_RECODE_ALL_RATIOS + // Reset. + oxcf->superres_scale_denominator = SCALE_NUMERATOR; + oxcf->superres_kf_scale_denominator = SCALE_NUMERATOR; +#endif // SUPERRES_RECODE_ALL_RATIOS } else { *largest_tile_id = largest_tile_id2; } + release_copy_buffer(&cpi->coding_context); + return err; } #endif // CONFIG_SUPERRES_IN_RECODE @@ -5527,14 +6060,12 @@ static void dump_filtered_recon_frames(AV1_COMP *cpi) { } #endif // DUMP_RECON_FRAMES -static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture, +static int is_integer_mv(const YV12_BUFFER_CONFIG *cur_picture, const YV12_BUFFER_CONFIG *last_picture, - hash_table *last_hash_table) { + ForceIntegerMVInfo *const force_intpel_info) { aom_clear_system_state(); // check use hash ME int k; - uint32_t hash_value_1; - uint32_t hash_value_2; const int block_size = FORCE_INT_MV_DECISION_BLOCK_SIZE; const double threshold_current = 0.8; @@ -5543,7 +6074,6 @@ static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture, int T = 0; // total block int C = 0; // match with collocated block int S = 0; // smooth region but not match with collocated block - int M = 0; // match with other block const int pic_width = cur_picture->y_width; const int pic_height = cur_picture->y_height; @@ -5597,33 +6127,21 @@ static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture, S++; continue; } - - av1_get_block_hash_value( - cur_picture->y_buffer + y_pos * stride_cur + x_pos, stride_cur, - block_size, &hash_value_1, &hash_value_2, - (cur_picture->flags & YV12_FLAG_HIGHBITDEPTH), &cpi->td.mb); - // Hashing does not work for highbitdepth currently. - // TODO(Roger): Make it work for highbitdepth. - if (av1_use_hash_me(&cpi->common)) { - if (av1_has_exact_match(last_hash_table, hash_value_1, hash_value_2)) { - M++; - } - } } } assert(T > 0); - double csm_rate = ((double)(C + S + M)) / ((double)(T)); - double m_rate = ((double)(M)) / ((double)(T)); + double cs_rate = ((double)(C + S)) / ((double)(T)); - cpi->csm_rate_array[cpi->rate_index] = csm_rate; - cpi->m_rate_array[cpi->rate_index] = m_rate; + force_intpel_info->cs_rate_array[force_intpel_info->rate_index] = cs_rate; - cpi->rate_index = (cpi->rate_index + 1) % max_history_size; - cpi->rate_size++; - cpi->rate_size = AOMMIN(cpi->rate_size, max_history_size); + force_intpel_info->rate_index = + (force_intpel_info->rate_index + 1) % max_history_size; + force_intpel_info->rate_size++; + force_intpel_info->rate_size = + AOMMIN(force_intpel_info->rate_size, max_history_size); - if (csm_rate < threshold_current) { + if (cs_rate < threshold_current) { return 0; } @@ -5631,29 +6149,22 @@ static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture, return 1; } - double csm_average = 0.0; - double m_average = 0.0; + double cs_average = 0.0; - for (k = 0; k < cpi->rate_size; k++) { - csm_average += cpi->csm_rate_array[k]; - m_average += cpi->m_rate_array[k]; + for (k = 0; k < force_intpel_info->rate_size; k++) { + cs_average += force_intpel_info->cs_rate_array[k]; } - csm_average /= cpi->rate_size; - m_average /= cpi->rate_size; + cs_average /= force_intpel_info->rate_size; - if (csm_average < threshold_average) { + if (cs_average < threshold_average) { return 0; } - if (M > (T - C - S) / 3) { + if ((T - C - S) < 0) { return 1; } - if (csm_rate > 0.99 && m_rate > 0.01) { - return 1; - } - - if (csm_average + m_average > 1.01) { + if (cs_average > 1.01) { return 1; } @@ -5672,18 +6183,8 @@ static void refresh_reference_frames(AV1_COMP *cpi) { } } -// Implementation and modifications of C. Yeo, H. L. Tan, and Y. H. Tan, "On -// rate distortion optimization using SSIM," Circuits and Systems for Video -// Technology, IEEE Transactions on, vol. 23, no. 7, pp. 1170-1181, 2013. -// SSIM_VAR_SCALE defines the strength of the bias towards SSIM in RDO: -// Test data set: mid_res (33 frames) -// SSIM_VAR_SCALE avg_psnr ssim ms-ssim -// 8 8.2 -6.0 -6.4 -// 16 4.0 -5.7 -5.9 -// 32 1.6 -4.4 -4.5 -#define SSIM_VAR_SCALE 16.0 static void set_mb_ssim_rdmult_scaling(AV1_COMP *cpi) { - AV1_COMMON *cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cpi->common.mi_params; ThreadData *td = &cpi->td; MACROBLOCK *x = &td->mb; MACROBLOCKD *xd = &x->e_mbd; @@ -5693,28 +6194,23 @@ static void set_mb_ssim_rdmult_scaling(AV1_COMP *cpi) { const int num_mi_w = mi_size_wide[block_size]; const int num_mi_h = mi_size_high[block_size]; - const int num_cols = (cm->mi_cols + num_mi_w - 1) / num_mi_w; - const int num_rows = (cm->mi_rows + num_mi_h - 1) / num_mi_h; + const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w; + const int num_rows = (mi_params->mi_rows + num_mi_h - 1) / num_mi_h; double log_sum = 0.0; - int row, col; const int use_hbd = cpi->source->flags & YV12_FLAG_HIGHBITDEPTH; - // TODO(sdeng): tune this param for 12bit videos. - double c2 = 58.5225; // (.03*255)^2 - c2 *= SSIM_VAR_SCALE; - // Loop through each 16x16 block. - for (row = 0; row < num_rows; ++row) { - for (col = 0; col < num_cols; ++col) { - int mi_row, mi_col; + for (int row = 0; row < num_rows; ++row) { + for (int col = 0; col < num_cols; ++col) { double var = 0.0, num_of_var = 0.0; const int index = row * num_cols + col; // Loop through each 8x8 block. - for (mi_row = row * num_mi_h; - mi_row < cm->mi_rows && mi_row < (row + 1) * num_mi_h; mi_row += 2) { - for (mi_col = col * num_mi_w; - mi_col < cm->mi_cols && mi_col < (col + 1) * num_mi_w; + for (int mi_row = row * num_mi_h; + mi_row < mi_params->mi_rows && mi_row < (row + 1) * num_mi_h; + mi_row += 2) { + for (int mi_col = col * num_mi_w; + mi_col < mi_params->mi_cols && mi_col < (col + 1) * num_mi_w; mi_col += 2) { struct buf_2d buf; const int row_offset_y = mi_row << 2; @@ -5734,36 +6230,26 @@ static void set_mb_ssim_rdmult_scaling(AV1_COMP *cpi) { } } var = var / num_of_var; - var = 2.0 * var + c2; + + // Curve fitting with an exponential model on all 16x16 blocks from the + // midres dataset. + var = 67.035434 * (1 - exp(-0.0021489 * var)) + 17.492222; cpi->ssim_rdmult_scaling_factors[index] = var; log_sum += log(var); } } log_sum = exp(log_sum / (double)(num_rows * num_cols)); - for (row = 0; row < num_rows; ++row) { - for (col = 0; col < num_cols; ++col) { + for (int row = 0; row < num_rows; ++row) { + for (int col = 0; col < num_cols; ++col) { const int index = row * num_cols + col; cpi->ssim_rdmult_scaling_factors[index] /= log_sum; } } - - (void)xd; } -#if CONFIG_DEBUG -static int hash_me_has_at_most_two_refs(RefCntBuffer *frame_bufs) { - int total_count = 0; - for (int frame_idx = 0; frame_idx < FRAME_BUFFERS; ++frame_idx) { - if (frame_bufs[frame_idx].hash_table.has_content > 1) { - return 0; - } - total_count += frame_bufs[frame_idx].hash_table.has_content; - } - - return total_count <= 2; -} -#endif +extern void av1_print_frame_contexts(const FRAME_CONTEXT *fc, + const char *filename); static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest) { @@ -5772,6 +6258,7 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, CurrentFrame *const current_frame = &cm->current_frame; const AV1EncoderConfig *const oxcf = &cpi->oxcf; struct segmentation *const seg = &cm->seg; + FeatureFlags *const features = &cm->features; #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, encode_frame_to_data_rate_time); @@ -5780,19 +6267,19 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, // frame type has been decided outside of this function call cm->cur_frame->frame_type = current_frame->frame_type; - cm->large_scale_tile = cpi->oxcf.large_scale_tile; - cm->single_tile_decoding = cpi->oxcf.single_tile_decoding; + cm->tiles.large_scale = cpi->oxcf.large_scale_tile; + cm->tiles.single_tile_decoding = cpi->oxcf.single_tile_decoding; - cm->allow_ref_frame_mvs &= frame_might_allow_ref_frame_mvs(cm); - // cm->allow_ref_frame_mvs needs to be written into the frame header while - // cm->large_scale_tile is 1, therefore, "cm->large_scale_tile=1" case is - // separated from frame_might_allow_ref_frame_mvs(). - cm->allow_ref_frame_mvs &= !cm->large_scale_tile; + features->allow_ref_frame_mvs &= frame_might_allow_ref_frame_mvs(cm); + // features->allow_ref_frame_mvs needs to be written into the frame header + // while cm->tiles.large_scale is 1, therefore, "cm->tiles.large_scale=1" case + // is separated from frame_might_allow_ref_frame_mvs(). + features->allow_ref_frame_mvs &= !cm->tiles.large_scale; - cm->allow_warped_motion = + features->allow_warped_motion = cpi->oxcf.allow_warped_motion && frame_might_allow_warped_motion(cm); - cm->last_frame_type = current_frame->frame_type; + cpi->last_frame_type = current_frame->frame_type; if (encode_show_existing_frame(cm)) { finalize_encoded_frame(cpi); @@ -5835,33 +6322,23 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, } // Work out whether to force_integer_mv this frame - if (oxcf->pass != 1 && cpi->common.allow_screen_content_tools && + if (!is_stat_generation_stage(cpi) && + cpi->common.features.allow_screen_content_tools && !frame_is_intra_only(cm)) { if (cpi->common.seq_params.force_integer_mv == 2) { // Adaptive mode: see what previous frame encoded did if (cpi->unscaled_last_source != NULL) { - cm->cur_frame_force_integer_mv = - is_integer_mv(cpi, cpi->source, cpi->unscaled_last_source, - cpi->previous_hash_table); + features->cur_frame_force_integer_mv = is_integer_mv( + cpi->source, cpi->unscaled_last_source, &cpi->force_intpel_info); } else { - cpi->common.cur_frame_force_integer_mv = 0; + cpi->common.features.cur_frame_force_integer_mv = 0; } } else { - cpi->common.cur_frame_force_integer_mv = + cpi->common.features.cur_frame_force_integer_mv = cpi->common.seq_params.force_integer_mv; } } else { - cpi->common.cur_frame_force_integer_mv = 0; - } - -#if CONFIG_DEBUG - assert(hash_me_has_at_most_two_refs(cm->buffer_pool->frame_bufs) && - "Hash-me is leaking memory!"); -#endif - - if (cpi->oxcf.pass != 1 && cpi->need_to_clear_prev_hash_table) { - av1_hash_table_clear_all(cpi->previous_hash_table); - cpi->need_to_clear_prev_hash_table = 0; + cpi->common.features.cur_frame_force_integer_mv = 0; } // Set default state for segment based loop filter update flags. @@ -5882,18 +6359,19 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, cpi->rc.source_alt_ref_active = 0; } if (cpi->oxcf.mtu == 0) { - cm->num_tg = cpi->oxcf.num_tile_groups; + cpi->num_tg = cpi->oxcf.num_tile_groups; } else { // Use a default value for the purposes of weighting costs in probability // updates - cm->num_tg = DEFAULT_MAX_NUM_TG; + cpi->num_tg = DEFAULT_MAX_NUM_TG; } // For 1 pass CBR, check if we are dropping this frame. // Never drop on key frame. - if (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR && + if (has_no_stats_stage(cpi) && oxcf->rc_mode == AOM_CBR && current_frame->frame_type != KEY_FRAME) { if (av1_rc_drop_frame(cpi)) { + av1_setup_frame_size(cpi); av1_rc_postencode_update_drop_frame(cpi); release_scaled_references(cpi); return AOM_CODEC_OK; @@ -5902,6 +6380,13 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, if (oxcf->tuning == AOM_TUNE_SSIM) set_mb_ssim_rdmult_scaling(cpi); +#if CONFIG_TUNE_VMAF + if (oxcf->tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_set_mb_vmaf_rdmult_scaling(cpi); + } +#endif + aom_clear_system_state(); #if CONFIG_INTERNAL_STATS @@ -5940,10 +6425,10 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, switch (cpi->oxcf.cdf_update_mode) { case 0: // No CDF update for any frames(4~6% compression loss). - cm->disable_cdf_update = 1; + features->disable_cdf_update = 1; break; case 1: // Enable CDF update for all frames. - cm->disable_cdf_update = 0; + features->disable_cdf_update = 0; break; case 2: // Strategically determine at which frames to do CDF update. @@ -5951,19 +6436,11 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, // compression loss). // TODO(huisu@google.com): design schemes for various trade-offs between // compression quality and decoding speed. - cm->disable_cdf_update = + features->disable_cdf_update = (frame_is_intra_only(cm) || !cm->show_frame) ? 0 : 1; break; } - cm->timing_info_present &= !seq_params->reduced_still_picture_hdr; - - if (cpi->oxcf.pass == 2 && cpi->oxcf.enable_tpl_model == 2 && - current_frame->frame_type == INTER_FRAME) { - if (!cm->show_frame) { - assert(cpi->tpl_model_pass == 0); - cpi->tpl_model_pass = 1; - } - } + seq_params->timing_info_present &= !seq_params->reduced_still_picture_hdr; int largest_tile_id = 0; #if CONFIG_SUPERRES_IN_RECODE @@ -6003,7 +6480,7 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, update_reference_segmentation_map(cpi); } else if (cm->last_frame_seg_map) { memcpy(cm->cur_frame->seg_map, cm->last_frame_seg_map, - cm->mi_cols * cm->mi_rows * sizeof(uint8_t)); + cm->mi_params.mi_cols * cm->mi_params.mi_rows * sizeof(uint8_t)); } } @@ -6021,25 +6498,25 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, av1_accumulate_frame_counts(&aggregate_fc, &cpi->counts); #endif // CONFIG_ENTROPY_STATS - if (cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) { + if (features->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) { *cm->fc = cpi->tile_data[largest_tile_id].tctx; av1_reset_cdf_symbol_counters(cm->fc); } - if (!cm->large_scale_tile) { + if (!cm->tiles.large_scale) { cm->cur_frame->frame_context = *cm->fc; } -#define EXT_TILE_DEBUG 0 -#if EXT_TILE_DEBUG - if (cm->large_scale_tile && oxcf->pass == 2) { - char fn[20] = "./fc"; - fn[4] = current_frame->frame_number / 100 + '0'; - fn[5] = (current_frame->frame_number % 100) / 10 + '0'; - fn[6] = (current_frame->frame_number % 10) + '0'; - fn[7] = '\0'; - av1_print_frame_contexts(cm->fc, fn); + + if (cpi->oxcf.ext_tile_debug) { + // (yunqing) This test ensures the correctness of large scale tile coding. + if (cm->tiles.large_scale && is_stat_consumption_stage(cpi)) { + char fn[20] = "./fc"; + fn[4] = current_frame->frame_number / 100 + '0'; + fn[5] = (current_frame->frame_number % 100) / 10 + '0'; + fn[6] = (current_frame->frame_number % 10) + '0'; + fn[7] = '\0'; + av1_print_frame_contexts(cm->fc, fn); + } } -#endif // EXT_TILE_DEBUG -#undef EXT_TILE_DEBUG #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, encode_frame_to_data_rate_time); @@ -6058,18 +6535,10 @@ static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, } #endif - cm->last_frame_type = current_frame->frame_type; + cpi->last_frame_type = current_frame->frame_type; av1_rc_postencode_update(cpi, *size); - // Store encoded frame's hash table for in_integer_mv() next time. - // Beware! If we don't update previous_hash_table here we will leak the - // items stored in cur_frame's hash_table! - if (oxcf->pass != 1 && av1_use_hash_me(cm)) { - cpi->previous_hash_table = &cm->cur_frame->hash_table; - cpi->need_to_clear_prev_hash_table = 1; - } - // Clear the one shot update flags for segmentation map and mode/ref loop // filter deltas. cm->seg.update_map = 0; @@ -6101,8 +6570,8 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, 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->features.error_resilient_mode = frame_params->error_resilient_mode; + cm->features.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; @@ -6113,7 +6582,6 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, 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_alt_ref_frame = frame_params->refresh_alt_ref_frame; @@ -6121,18 +6589,13 @@ int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, if (current_frame->frame_type == KEY_FRAME && cm->show_frame) current_frame->frame_number = 0; - if (cm->show_existing_frame) { - current_frame->order_hint = cm->cur_frame->order_hint; - current_frame->display_order_hint = cm->cur_frame->display_order_hint; - } else { - current_frame->order_hint = - current_frame->frame_number + frame_params->order_offset; - current_frame->display_order_hint = current_frame->order_hint; - current_frame->order_hint %= - (1 << (cm->seq_params.order_hint_info.order_hint_bits_minus_1 + 1)); - } + current_frame->order_hint = + current_frame->frame_number + frame_params->order_offset; + current_frame->display_order_hint = current_frame->order_hint; + current_frame->order_hint %= + (1 << (cm->seq_params.order_hint_info.order_hint_bits_minus_1 + 1)); - if (cpi->oxcf.pass == 1) { + if (is_stat_generation_stage(cpi)) { #if !CONFIG_REALTIME_ONLY av1_first_pass(cpi, frame_input->ts_duration); #endif @@ -6192,7 +6655,16 @@ int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, const int subsampling_y = sd->subsampling_y; const int use_highbitdepth = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0; - check_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y); +#if CONFIG_TUNE_VMAF + if (!is_stat_generation_stage(cpi) && + cpi->oxcf.tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING) { + av1_vmaf_frame_preprocessing(cpi, sd); + } + if (!is_stat_generation_stage(cpi) && + cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_vmaf_blk_preprocessing(cpi, sd); + } +#endif #if CONFIG_INTERNAL_STATS struct aom_usec_timer timer; @@ -6252,18 +6724,13 @@ static void adjust_image_stat(double y, double u, double v, double all, static void compute_internal_stats(AV1_COMP *cpi, int frame_bytes) { AV1_COMMON *const cm = &cpi->common; double samples = 0.0; - uint32_t in_bit_depth = 8; - uint32_t bit_depth = 8; + const uint32_t in_bit_depth = cpi->oxcf.input_bit_depth; + const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; #if CONFIG_INTER_STATS_ONLY if (cm->current_frame.frame_type == KEY_FRAME) return; // skip key frame #endif cpi->bytes += frame_bytes; - - if (cm->seq_params.use_highbitdepth) { - in_bit_depth = cpi->oxcf.input_bit_depth; - bit_depth = cm->seq_params.bit_depth; - } if (cm->show_frame) { const YV12_BUFFER_CONFIG *orig = cpi->source; const YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf; @@ -6275,11 +6742,7 @@ static void compute_internal_stats(AV1_COMP *cpi, int frame_bytes) { double frame_ssim2 = 0.0, weight = 0.0; aom_clear_system_state(); #if CONFIG_AV1_HIGHBITDEPTH - // TODO(yaowu): unify these two versions into one. - if (cm->seq_params.use_highbitdepth) - aom_calc_highbd_psnr(orig, recon, &psnr, bit_depth, in_bit_depth); - else - aom_calc_psnr(orig, recon, &psnr); + aom_calc_highbd_psnr(orig, recon, &psnr, bit_depth, in_bit_depth); #else aom_calc_psnr(orig, recon, &psnr); #endif @@ -6365,24 +6828,20 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, av1_one_pass_cbr_svc_start_layer(cpi); } - // Indicates whether or not to use an adaptive quantize b rather than - // the traditional version - cm->use_quant_b_adapt = cpi->oxcf.quant_b_adapt; - 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, 1, 0); + av1_set_high_precision_mv(cpi, 1, 0); // Normal defaults - cm->refresh_frame_context = oxcf->frame_parallel_decoding_mode - ? REFRESH_FRAME_CONTEXT_DISABLED - : REFRESH_FRAME_CONTEXT_BACKWARD; + cm->features.refresh_frame_context = oxcf->frame_parallel_decoding_mode + ? REFRESH_FRAME_CONTEXT_DISABLED + : REFRESH_FRAME_CONTEXT_BACKWARD; if (oxcf->large_scale_tile) - cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; + cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED; // Initialize fields related to forward keyframes cpi->no_show_kf = 0; @@ -6403,12 +6862,22 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, cpi->time_compress_data += aom_usec_timer_elapsed(&cmptimer); #endif // CONFIG_INTERNAL_STATS if (cpi->b_calculate_psnr) { - if (cm->show_existing_frame || (oxcf->pass != 1 && cm->show_frame)) { + if (cm->show_existing_frame || + (!is_stat_generation_stage(cpi) && cm->show_frame)) { generate_psnr_packet(cpi); } } - if (cpi->keep_level_stats && oxcf->pass != 1) { +#if CONFIG_TUNE_VMAF + if (!is_stat_generation_stage(cpi) && + (oxcf->tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_MAX_GAIN)) { + av1_update_vmaf_curve(cpi, cpi->source, &cpi->common.cur_frame->buf); + } +#endif + + if (cpi->level_params.keep_level_stats && !is_stat_generation_stage(cpi)) { // Initialize level info. at the beginning of each sequence. if (cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) { av1_init_level_info(cpi); @@ -6417,12 +6886,12 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags, } #if CONFIG_INTERNAL_STATS - if (oxcf->pass != 1) { + if (!is_stat_generation_stage(cpi)) { compute_internal_stats(cpi, (int)(*size)); } #endif // CONFIG_INTERNAL_STATS #if CONFIG_SPEED_STATS - if (cpi->oxcf.pass != 1 && !cm->show_existing_frame) { + if (!is_stat_generation_stage(cpi) && !cm->show_existing_frame) { cpi->tx_search_count += cpi->td.mb.tx_search_count; cpi->td.mb.tx_search_count = 0; } @@ -6484,8 +6953,9 @@ aom_codec_err_t av1_copy_new_frame_enc(AV1_COMMON *cm, return cm->error.error_code; } -int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode, - AOM_SCALING vert_mode) { +int av1_set_internal_size(AV1EncoderConfig *const oxcf, + ResizePendingParams *resize_pending_params, + AOM_SCALING horiz_mode, AOM_SCALING vert_mode) { int hr = 0, hs = 0, vr = 0, vs = 0; if (horiz_mode > ONETWO || vert_mode > ONETWO) return -1; @@ -6494,13 +6964,15 @@ int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode, Scale2Ratio(vert_mode, &vr, &vs); // always go to the next whole number - cpi->resize_pending_width = (hs - 1 + cpi->oxcf.width * hr) / hs; - cpi->resize_pending_height = (vs - 1 + cpi->oxcf.height * vr) / vs; + resize_pending_params->width = (hs - 1 + oxcf->width * hr) / hs; + resize_pending_params->height = (vs - 1 + oxcf->height * vr) / vs; return 0; } -int av1_get_quantizer(AV1_COMP *cpi) { return cpi->common.base_qindex; } +int av1_get_quantizer(AV1_COMP *cpi) { + return cpi->common.quant_params.base_qindex; +} int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *frame_size) { size_t output_size = 0; @@ -6559,29 +7031,42 @@ int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *frame_size) { return AOM_CODEC_OK; } -static void svc_set_updates_external_ref_frame_config(AV1_COMP *cpi) { - cpi->ext_refresh_frame_flags_pending = 1; - cpi->ext_refresh_last_frame = cpi->svc.refresh[cpi->svc.ref_idx[0]]; - cpi->ext_refresh_golden_frame = cpi->svc.refresh[cpi->svc.ref_idx[3]]; - cpi->ext_refresh_bwd_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[4]]; - cpi->ext_refresh_alt2_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[5]]; - cpi->ext_refresh_alt_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[6]]; - cpi->svc.non_reference_frame = 1; +static void svc_set_updates_external_ref_frame_config( + ExternalFlags *const ext_flags, SVC *const svc) { + ext_flags->refresh_frame_flags_pending = 1; + ext_flags->refresh_last_frame = svc->refresh[svc->ref_idx[0]]; + ext_flags->refresh_golden_frame = svc->refresh[svc->ref_idx[3]]; + ext_flags->refresh_bwd_ref_frame = svc->refresh[svc->ref_idx[4]]; + ext_flags->refresh_alt2_ref_frame = svc->refresh[svc->ref_idx[5]]; + ext_flags->refresh_alt_ref_frame = svc->refresh[svc->ref_idx[6]]; + svc->non_reference_frame = 1; for (int i = 0; i < REF_FRAMES; i++) { - if (cpi->svc.refresh[i] == 1) { - cpi->svc.non_reference_frame = 0; + if (svc->refresh[i] == 1) { + svc->non_reference_frame = 0; break; } } } +static int svc_set_references_external_ref_frame_config(AV1_COMP *cpi) { + // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3), + // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). + int ref = AOM_REFFRAME_ALL; + for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { + if (!cpi->svc.reference[i]) ref ^= (1 << i); + } + return ref; +} + void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) { // TODO(yunqingwang): For what references to use, external encoding flags // should be consistent with internal reference frame selection. Need to // ensure that there is not conflict between the two. In AV1 encoder, the // priority rank for 7 reference frames are: LAST, ALTREF, LAST2, LAST3, // GOLDEN, BWDREF, ALTREF2. - cpi->ext_ref_frame_flags = AOM_REFFRAME_ALL; + + ExternalFlags *const ext_flags = &cpi->ext_flags; + ext_flags->ref_frame_flags = AOM_REFFRAME_ALL; if (flags & (AOM_EFLAG_NO_REF_LAST | AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD | @@ -6603,7 +7088,12 @@ void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) { if (flags & AOM_EFLAG_NO_REF_ARF2) ref ^= AOM_ALT2_FLAG; } - av1_use_as_reference(cpi, ref); + av1_use_as_reference(&ext_flags->ref_frame_flags, ref); + } else { + if (cpi->svc.external_ref_frame_config) { + int ref = svc_set_references_external_ref_frame_config(cpi); + av1_use_as_reference(&ext_flags->ref_frame_flags, ref); + } } if (flags & @@ -6621,29 +7111,31 @@ void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) { upd ^= AOM_ALT2_FLAG; } - cpi->ext_refresh_last_frame = (upd & AOM_LAST_FLAG) != 0; - cpi->ext_refresh_golden_frame = (upd & AOM_GOLD_FLAG) != 0; - cpi->ext_refresh_alt_ref_frame = (upd & AOM_ALT_FLAG) != 0; - 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; + ext_flags->refresh_last_frame = (upd & AOM_LAST_FLAG) != 0; + ext_flags->refresh_golden_frame = (upd & AOM_GOLD_FLAG) != 0; + ext_flags->refresh_alt_ref_frame = (upd & AOM_ALT_FLAG) != 0; + ext_flags->refresh_bwd_ref_frame = (upd & AOM_BWD_FLAG) != 0; + ext_flags->refresh_alt2_ref_frame = (upd & AOM_ALT2_FLAG) != 0; + ext_flags->refresh_frame_flags_pending = 1; } else { if (cpi->svc.external_ref_frame_config) - svc_set_updates_external_ref_frame_config(cpi); + svc_set_updates_external_ref_frame_config(ext_flags, &cpi->svc); else - cpi->ext_refresh_frame_flags_pending = 0; + ext_flags->refresh_frame_flags_pending = 0; } - cpi->ext_use_ref_frame_mvs = cpi->oxcf.allow_ref_frame_mvs & - ((flags & AOM_EFLAG_NO_REF_FRAME_MVS) == 0); - cpi->ext_use_error_resilient = cpi->oxcf.error_resilient_mode | - ((flags & AOM_EFLAG_ERROR_RESILIENT) != 0); - cpi->ext_use_s_frame = + ext_flags->use_ref_frame_mvs = cpi->oxcf.allow_ref_frame_mvs & + ((flags & AOM_EFLAG_NO_REF_FRAME_MVS) == 0); + ext_flags->use_error_resilient = cpi->oxcf.error_resilient_mode | + ((flags & AOM_EFLAG_ERROR_RESILIENT) != 0); + ext_flags->use_s_frame = cpi->oxcf.s_frame_mode | ((flags & AOM_EFLAG_SET_S_FRAME) != 0); - cpi->ext_use_primary_ref_none = (flags & AOM_EFLAG_SET_PRIMARY_REF_NONE) != 0; + ext_flags->use_primary_ref_none = + (flags & AOM_EFLAG_SET_PRIMARY_REF_NONE) != 0; if (flags & AOM_EFLAG_NO_UPD_ENTROPY) { - av1_update_entropy(cpi, 0); + av1_update_entropy(&ext_flags->refresh_frame_context, + &ext_flags->refresh_frame_context_pending, 0); } } @@ -6652,7 +7144,7 @@ aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi) { uint8_t header_buf[512] = { 0 }; const uint32_t sequence_header_size = - av1_write_sequence_header_obu(cpi, &header_buf[0]); + av1_write_sequence_header_obu(&cpi->common.seq_params, &header_buf[0]); assert(sequence_header_size <= sizeof(header_buf)); if (sequence_header_size == 0) return NULL; @@ -6663,8 +7155,8 @@ 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 (av1_write_obu_header(cpi, OBU_SEQUENCE_HEADER, 0, &header_buf[0]) != - obu_header_size) { + if (av1_write_obu_header(&cpi->level_params, OBU_SEQUENCE_HEADER, 0, + &header_buf[0]) != obu_header_size) { return NULL; } diff --git a/media/libaom/src/av1/encoder/encoder.h b/media/libaom/src/av1/encoder/encoder.h index 3781139946..82d00cb76a 100644 --- a/media/libaom/src/av1/encoder/encoder.h +++ b/media/libaom/src/av1/encoder/encoder.h @@ -20,28 +20,27 @@ #include "aom/aomcx.h" #include "av1/common/alloccommon.h" -#include "av1/common/entropymode.h" -#include "av1/common/thread_common.h" -#include "av1/common/onyxc_int.h" -#include "av1/common/resize.h" -#include "av1/common/timing.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" +#include "av1/common/entropymode.h" #include "av1/common/enums.h" +#include "av1/common/resize.h" +#include "av1/common/thread_common.h" +#include "av1/common/timing.h" #include "av1/encoder/aq_cyclicrefresh.h" #include "av1/encoder/av1_quantize.h" +#include "av1/encoder/block.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" #include "av1/encoder/ratectrl.h" #include "av1/encoder/rd.h" #include "av1/encoder/speed_features.h" #include "av1/encoder/svc_layercontext.h" #include "av1/encoder/tokenize.h" -#include "av1/encoder/block.h" #if CONFIG_INTERNAL_STATS #include "aom_dsp/ssim.h" @@ -57,6 +56,9 @@ extern "C" { #endif +// Number of frames required to test for scene cut detection +#define SCENE_CUT_KEY_TEST_INTERVAL 16 + // Rational number with an int64 numerator // This structure holds a fractional value typedef struct aom_rational64 { @@ -73,16 +75,6 @@ typedef struct { #endif // CONFIG_SUPERRES_IN_RECODE } CODING_CONTEXT; -enum { - 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); - enum { NORMAL = 0, FOURFIVE = 1, @@ -145,21 +137,20 @@ enum { typedef enum { kInvalid = 0, - kLowSadLowSumdiff = 1, - kLowSadHighSumdiff = 2, - kHighSadLowSumdiff = 3, - kHighSadHighSumdiff = 4, - kLowVarHighSumdiff = 5, - kVeryHighSad = 6, + kLowSad = 1, + kHighSad = 2, + kLowVarHighSumdiff = 3, } CONTENT_STATE_SB; enum { SS_CFG_SRC = 0, SS_CFG_LOOKAHEAD = 1, - SS_CFG_TOTAL = 2 + SS_CFG_FPF = 2, + SS_CFG_TOTAL = 3 } UENUM1BYTE(SS_CFG_OFFSET); -#define MAX_LENGTH_TPL_FRAME_STATS (27 + 9) +// TODO(jingning): This needs to be cleaned up next. +#define MAX_LENGTH_TPL_FRAME_STATS (MAX_TOTAL_BUFFERS + REF_FRAMES + 1) typedef struct TplDepStats { int64_t intra_cost; @@ -170,19 +161,17 @@ typedef struct TplDepStats { int64_t recrf_rate; int64_t mc_dep_rate; int64_t mc_dep_dist; - int_mv mv; + int_mv mv[INTER_REFS_PER_FRAME]; int ref_frame_index; -#if !USE_TPL_CLASSIC_MODEL + int64_t pred_error[INTER_REFS_PER_FRAME]; int64_t mc_count; int64_t mc_saved; -#endif // !USE_TPL_CLASSIC_MODEL } TplDepStats; typedef struct TplDepFrame { uint8_t is_valid; TplDepStats *tpl_stats_ptr; const YV12_BUFFER_CONFIG *gf_picture; - YV12_BUFFER_CONFIG rec_picture_buf; YV12_BUFFER_CONFIG *rec_picture; int ref_map_index[REF_FRAMES]; int stride; @@ -194,6 +183,28 @@ typedef struct TplDepFrame { int base_rdmult; } TplDepFrame; +typedef struct TplParams { + // Block granularity of tpl score storage. + uint8_t tpl_stats_block_mis_log2; + + // Buffer to store the frame level tpl information for each frame in a gf + // group. tpl_stats_buffer[i] stores the tpl information of ith frame in a gf + // group + TplDepFrame tpl_stats_buffer[MAX_LENGTH_TPL_FRAME_STATS]; + + // Buffer to store tpl stats at block granularity. + // tpl_stats_pool[i][j] stores the tpl stats of jth block of ith frame in a gf + // group. + TplDepStats *tpl_stats_pool[MAX_LAG_BUFFERS]; + + // Buffer to store tpl reconstructed frame. + // tpl_rec_pool[i] stores the reconstructed frame of ith frame in a gf group. + YV12_BUFFER_CONFIG tpl_rec_pool[MAX_LAG_BUFFERS]; + + // Pointer to tpl_stats_buffer. + TplDepFrame *tpl_frame; +} TplParams; + typedef enum { COST_UPD_SB, COST_UPD_SBROW, @@ -274,9 +285,6 @@ typedef struct AV1EncoderConfig { int qm_v; int qm_minlevel; int qm_maxlevel; -#if CONFIG_DIST_8X8 - int using_dist_8x8; -#endif unsigned int num_tile_groups; unsigned int mtu; @@ -326,6 +334,7 @@ typedef struct AV1EncoderConfig { int min_gf_interval; int max_gf_interval; + int gf_min_pyr_height; int gf_max_pyr_height; int row_mt; @@ -344,6 +353,7 @@ typedef struct AV1EncoderConfig { aom_fixed_buf_t two_pass_stats_in; aom_tune_metric tuning; + const char *vmaf_model_path; aom_tune_content content; int use_highbitdepth; aom_color_primaries_t color_primaries; @@ -370,6 +380,8 @@ typedef struct AV1EncoderConfig { unsigned int full_still_picture_hdr; int enable_dual_filter; unsigned int motion_vector_unit_test; + unsigned int sb_multipass_unit_test; + unsigned int ext_tile_debug; int enable_rect_partitions; int enable_ab_partitions; int enable_1to4_partitions; @@ -377,7 +389,6 @@ typedef struct AV1EncoderConfig { 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; @@ -426,14 +437,48 @@ typedef struct AV1EncoderConfig { // Bit mask to specify which tier each of the 32 possible operating points // conforms to. unsigned int tier_mask; + // If true, encoder will use fixed QP offsets, that are either: + // - Given by the user, and stored in 'fixed_qp_offsets' array, OR + // - Picked automatically from cq_level. + int use_fixed_qp_offsets; + // List of QP offsets for: keyframe, ALTREF, and 3 levels of internal ARFs. + // If any of these values are negative, fixed offsets are disabled. + // Uses internal q range. + double fixed_qp_offsets[FIXED_QP_OFFSET_COUNT]; // min_cr / 100 is the target minimum compression ratio for each frame. unsigned int min_cr; + const cfg_options_t *encoder_cfg; } AV1EncoderConfig; static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) { return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0; } +typedef struct { + // obmc_probs[i][j] is the probability of OBMC being the best motion mode for + // jth block size and ith frame update type, averaged over past frames. If + // obmc_probs[i][j] < thresh, then OBMC search is pruned. + int obmc_probs[FRAME_UPDATE_TYPES][BLOCK_SIZES_ALL]; + + // warped_probs[i] is the probability of warped motion being the best motion + // mode for ith frame update type, averaged over past frames. If + // warped_probs[i] < thresh, then warped motion search is pruned. + int warped_probs[FRAME_UPDATE_TYPES]; + + // tx_type_probs[i][j][k] is the probability of kth tx_type being the best + // for jth transform size and ith frame update type, averaged over past + // frames. If tx_type_probs[i][j][k] < thresh, then transform search for that + // type is pruned. + int tx_type_probs[FRAME_UPDATE_TYPES][TX_SIZES_ALL][TX_TYPES]; + + // switchable_interp_probs[i][j][k] is the probability of kth interpolation + // filter being the best for jth filter context and ith frame update type, + // averaged over past frames. If switchable_interp_probs[i][j][k] < thresh, + // then interpolation filter search is pruned for that case. + int switchable_interp_probs[FRAME_UPDATE_TYPES][SWITCHABLE_FILTER_CONTEXTS] + [SWITCHABLE_FILTERS]; +} FrameProbInfo; + typedef struct FRAME_COUNTS { // Note: This structure should only contain 'unsigned int' fields, or // aggregates built solely from 'unsigned int' fields/elements @@ -575,11 +620,73 @@ typedef struct AV1RowMTInfo { int num_threads_working; } AV1RowMTInfo; +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; +} VPartVar; + +typedef struct { + VPartVar none; + VPartVar horz[2]; + VPartVar vert[2]; +} VPVariance; + +typedef struct { + VPVariance part_variances; + VPartVar split[4]; +} VP4x4; + +typedef struct { + VPVariance part_variances; + VP4x4 split[4]; +} VP8x8; + +typedef struct { + VPVariance part_variances; + VP8x8 split[4]; +} VP16x16; + +typedef struct { + VPVariance part_variances; + VP16x16 split[4]; +} VP32x32; + +typedef struct { + VPVariance part_variances; + VP32x32 split[4]; +} VP64x64; + +typedef struct { + VPVariance part_variances; + VP64x64 *split; +} VP128x128; + +typedef struct { + // Thresholds for variance based partitioning. If block variance > threshold, + // then that block is forced to split. + // thresholds[0] - threshold for 128x128; + // thresholds[1] - threshold for 64x64; + // thresholds[2] - threshold for 32x32; + // thresholds[3] - threshold for 16x16; + // thresholds[4] - threshold for 8x8; + int64_t thresholds[5]; + + // MinMax variance threshold for 8x8 sub blocks of a 16x16 block. If actual + // minmax > threshold_minmax, the 16x16 is forced to split. + int64_t threshold_minmax; +} VarBasedPartitionInfo; + // TODO(jingning) All spatially adaptive variables should go to TileDataEnc. typedef struct TileDataEnc { TileInfo tile_info; - int m_search_count; - int ex_search_count; CFL_CTX cfl; DECLARE_ALIGNED(16, FRAME_CONTEXT, tctx); FRAME_CONTEXT *row_ctx; @@ -608,8 +715,9 @@ typedef struct RD_COUNTS { int global_motion_used[REF_FRAMES]; int compound_ref_used_flag; int skip_mode_used_flag; - int tx_type_used[FRAME_UPDATE_TYPES][TX_SIZES_ALL][TX_TYPES]; + int tx_type_used[TX_SIZES_ALL][TX_TYPES]; int obmc_used[BLOCK_SIZES_ALL][2]; + int warped_used[2]; } RD_COUNTS; typedef struct ThreadData { @@ -617,7 +725,7 @@ typedef struct ThreadData { RD_COUNTS rd_counts; FRAME_COUNTS *counts; PC_TREE *pc_tree; - PC_TREE *pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2 + 1]; + PC_TREE *pc_root; tran_low_t *tree_coeff_buf[MAX_MB_PLANE]; tran_low_t *tree_qcoeff_buf[MAX_MB_PLANE]; tran_low_t *tree_dqcoeff_buf[MAX_MB_PLANE]; @@ -635,6 +743,8 @@ typedef struct ThreadData { int deltaq_used; FRAME_CONTEXT *tctx; MB_MODE_INFO_EXT *mbmi_ext; + VP64x64 *vt64x64; + int32_t num_64x64_blocks; } ThreadData; struct EncWorkerData; @@ -645,6 +755,16 @@ typedef struct ActiveMap { unsigned char *map; } ActiveMap; +typedef struct { + // cs_rate_array[i] is the fraction of blocks in a frame which either match + // with the collocated block or are smooth, where i is the rate_index. + double cs_rate_array[32]; + // rate_index is used to index cs_rate_array. + int rate_index; + // rate_size is the total number of entries populated in cs_rate_array. + int rate_size; +} ForceIntegerMVInfo; + #if CONFIG_INTERNAL_STATS // types of stats enum { @@ -666,6 +786,17 @@ typedef struct { YV12_BUFFER_CONFIG buf; } EncRefCntBuffer; +typedef struct { + // Buffer to store mode information at mi_alloc_bsize (4x4 or 8x8) level for + // use in bitstream preparation. frame_base[mi_row * stride + mi_col] stores + // the mode information of block (mi_row,mi_col). + MB_MODE_INFO_EXT_FRAME *frame_base; + // Size of frame_base buffer. + int alloc_size; + // Stride of frame_base buffer. + int stride; +} MBMIExtFrameBufferInfo; + #if CONFIG_COLLECT_PARTITION_STATS == 2 typedef struct PartitionStats { int partition_decisions[6][EXT_PARTITION_TYPES]; @@ -739,6 +870,138 @@ static INLINE char const *get_component_name(int index) { // The maximum number of internal ARFs except ALTREF_FRAME #define MAX_INTERNAL_ARFS (REF_FRAMES - BWDREF_FRAME - 1) +typedef struct { + // Array to store the cost for signalling each global motion model. + // gmtype_cost[i] stores the cost of signalling the ith Global Motion model. + int type_cost[TRANS_TYPES]; + + // Array to store the cost for signalling a particular global motion model for + // each reference frame. gmparams_cost[i] stores the cost of signalling global + // motion for the ith reference frame. + int params_cost[REF_FRAMES]; + + // Flag to indicate if global motion search needs to be rerun. + bool search_done; +} GlobalMotionInfo; + +typedef struct { + // Stores the default value of skip flag depending on chroma format + // Set as 1 for monochrome and 3 for other color formats + int default_interp_skip_flags; + // Filter mask to allow certain interp_filter type. + uint16_t interp_filter_search_mask; +} InterpSearchFlags; + +typedef struct { + // Largest MV component used in a frame. + // The value from the previous frame is used to set the full pixel search + // range for the current frame. + int max_mv_magnitude; + // Parameter indicating initial search window to be used in full-pixel search. + // Range [0, MAX_MVSEARCH_STEPS-2]. Lower value indicates larger window. + int mv_step_param; + // Pointer to sub-pixel search function. + // In encoder: av1_find_best_sub_pixel_tree + // av1_find_best_sub_pixel_tree_pruned + // av1_find_best_sub_pixel_tree_pruned_more + // av1_find_best_sub_pixel_tree_pruned_evenmore + // In MV unit test: av1_return_max_sub_pixel_mv + // av1_return_min_sub_pixel_mv + fractional_mv_step_fp *find_fractional_mv_step; + // Search site configuration for full-pel MV search. + // ss_cfg[SS_CFG_SRC]: Used in tpl, rd/non-rd inter mode loop, simple motion + // search. + // ss_cfg[SS_CFG_LOOKAHEAD]: Used in intraBC, temporal filter + // ss_cfg[SS_CFG_FPF]: Used during first pass and lookahead + search_site_config ss_cfg[SS_CFG_TOTAL]; +} MotionVectorSearchParams; + +typedef struct { + // When resize is triggered externally, the desired dimensions are stored in + // this struct until used in the next frame to be coded. These values are + // effective only for one frame and are reset after they are used. + int width; + int height; +} ResizePendingParams; + +typedef struct { + // Threshold of transform domain distortion + // Index 0: Default mode evaluation, Winner mode processing is not applicable + // (Eg : IntraBc). + // Index 1: Mode evaluation. + // Index 2: Winner mode evaluation. + // Index 1 and 2 are applicable when enable_winner_mode_for_use_tx_domain_dist + // speed feature is ON + unsigned int tx_domain_dist_threshold[MODE_EVAL_TYPES]; + + // Factor to control R-D optimization of coeffs based on block + // mse. + // Index 0: Default mode evaluation, Winner mode processing is not applicable + // (Eg : IntraBc). Index 1: Mode evaluation. + // Index 2: Winner mode evaluation + // Index 1 and 2 are applicable when enable_winner_mode_for_coeff_opt speed + // feature is ON + unsigned int coeff_opt_dist_threshold[MODE_EVAL_TYPES]; + + // Transform size to be used in transform search + // Index 0: Default mode evaluation, Winner mode processing is not applicable + // (Eg : IntraBc). + // Index 1: Mode evaluation. Index 2: Winner mode evaluation + // Index 1 and 2 are applicable when enable_winner_mode_for_tx_size_srch speed + // feature is ON + TX_SIZE_SEARCH_METHOD tx_size_search_methods[MODE_EVAL_TYPES]; + + // Transform domain distortion levels + // Index 0: Default mode evaluation, Winner mode processing is not applicable + // (Eg : IntraBc). + // Index 1: Mode evaluation. Index 2: Winner mode evaluation + // Index 1 and 2 are applicable when enable_winner_mode_for_use_tx_domain_dist + // speed feature is ON + unsigned int use_transform_domain_distortion[MODE_EVAL_TYPES]; + + // Predict transform skip levels to be used for default, mode and winner mode + // evaluation. Index 0: Default mode evaluation, Winner mode processing is not + // applicable. Index 1: Mode evaluation, Index 2: Winner mode evaluation + unsigned int predict_skip_level[MODE_EVAL_TYPES]; +} WinnerModeParams; + +typedef struct { + // Bit mask to disable certain reference frame types. + int ref_frame_flags; + + // Flags to determine which reference buffers are refreshed by this frame. + // When set, the encoder will update the particular reference frame buffer + // with the contents of the current frame. + bool refresh_last_frame; + bool refresh_golden_frame; + bool refresh_bwd_ref_frame; + bool refresh_alt2_ref_frame; + bool refresh_alt_ref_frame; + + // Flag to indicate that updation of refresh frame flags from external + // interface is pending. + bool refresh_frame_flags_pending; + + // Flag to enable the updation of frame contexts at the end of a frame decode. + bool refresh_frame_context; + + // Flag to indicate that updation of refresh_frame_context from external + // interface is pending. + bool refresh_frame_context_pending; + + // Flag to enable temporal MV prediction. + bool use_ref_frame_mvs; + + // Flag to code the frame as error-resilient. + bool use_error_resilient; + + // Flag to code the frame as s-frame. + bool use_s_frame; + + // Flag to set the frame's primary_ref_frame to PRIMARY_REF_NONE. + bool use_primary_ref_none; +} ExternalFlags; + typedef struct { int arf_stack[FRAME_BUFFERS]; int arf_stack_size; @@ -748,21 +1011,84 @@ typedef struct { int gld_stack_size; } RefBufferStack; +typedef struct { + // Some misc info + int high_prec; + int q; + int order; + + // MV counters + int inter_count; + int intra_count; + int default_mvs; + int mv_joint_count[4]; + int last_bit_zero; + int last_bit_nonzero; + + // Keep track of the rates + int total_mv_rate; + int hp_total_mv_rate; + int lp_total_mv_rate; + + // Texture info + int horz_text; + int vert_text; + int diag_text; + + // Whether the current struct contains valid data + int valid; +} MV_STATS; + +typedef struct { + int frame_width; + int frame_height; + int mi_rows; + int mi_cols; + int mb_rows; + int mb_cols; + int num_mbs; + aom_bit_depth_t bit_depth; + int subsampling_x; + int subsampling_y; +} FRAME_INFO; + +typedef struct { + // 3-bit number containing the segment affiliation for each 4x4 block in the + // frame. map[y * stride + x] contains the segment id of the 4x4 block at + // (x,y) position. + uint8_t *map; + // Flag to indicate if current frame has lossless segments or not. + // 1: frame has at least one lossless segment. + // 0: frame has no lossless segments. + bool has_lossless_segment; +} EncSegmentationInfo; + +typedef struct { + // Start time stamp of the previous frame + int64_t prev_start_seen; + // End time stamp of the previous frame + int64_t prev_end_seen; + // Start time stamp of the first frame + int64_t first_ever; +} TimeStamps; + typedef struct AV1_COMP { - QUANTS quants; + // Quantization and dequantization parameters for internal quantizer setup + // in the encoder. + EncQuantDequantParams enc_quant_dequant_params; ThreadData td; FRAME_COUNTS counts; - MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame_base; + + // Holds buffer storing mode information at 4x4/8x8 level. + MBMIExtFrameBufferInfo mbmi_ext_info; + CB_COEFF_BUFFER *coeff_buffer_base; - Dequants dequants; AV1_COMMON common; AV1EncoderConfig oxcf; struct lookahead_ctx *lookahead; - struct lookahead_entry *alt_ref_source; int no_show_kf; - int optimize_seg_arr[MAX_SEGMENTS]; - int mi_ext_alloc_size; + TRELLIS_OPT_TYPE optimize_seg_arr[MAX_SEGMENTS]; YV12_BUFFER_CONFIG *source; YV12_BUFFER_CONFIG *last_source; // NULL for first frame and alt_ref frames @@ -770,21 +1096,15 @@ typedef struct AV1_COMP { YV12_BUFFER_CONFIG scaled_source; YV12_BUFFER_CONFIG *unscaled_last_source; YV12_BUFFER_CONFIG scaled_last_source; + YV12_BUFFER_CONFIG *unfiltered_source; - uint8_t tpl_stats_block_mis_log2; // block granularity of tpl score storage - TplDepFrame tpl_stats_buffer[MAX_LENGTH_TPL_FRAME_STATS]; - TplDepFrame *tpl_frame; + TplParams tpl_data; // For a still frame, this flag is set to 1 to skip partition search. int partition_search_skippable_frame; - double csm_rate_array[32]; - double m_rate_array[32]; - int rate_size; - int rate_index; - hash_table *previous_hash_table; - int need_to_clear_prev_hash_table; - int previous_index; + // Variables related to forcing integer mv decisions for the current frame. + ForceIntegerMVInfo force_intpel_info; unsigned int row_mt; RefCntBuffer *scaled_ref_buf[INTER_REFS_PER_FRAME]; @@ -795,14 +1115,8 @@ typedef struct AV1_COMP { // after the current frame is encoded, the XYZ reference frame gets refreshed // (updated) to be the current frame. // - // Special case: 'refresh_last_frame' specifies that: - // - LAST_FRAME reference should be updated to be the current frame (as usual) - // - Also, LAST2_FRAME and LAST3_FRAME references are implicitly updated to be - // the two past reference frames just before LAST_FRAME that are available. - // // Note: Usually at most one of these refresh flags is true at a time. // But a key-frame is special, for which all the flags are true at once. - int refresh_last_frame; int refresh_golden_frame; int refresh_bwd_ref_frame; int refresh_alt_ref_frame; @@ -813,19 +1127,8 @@ typedef struct AV1_COMP { // frame of the same type as the current frame). int fb_of_context_type[REF_FRAMES]; - int ext_refresh_frame_flags_pending; - int ext_refresh_last_frame; - int ext_refresh_golden_frame; - int ext_refresh_bwd_ref_frame; - int ext_refresh_alt2_ref_frame; - int ext_refresh_alt_ref_frame; - - int ext_refresh_frame_context_pending; - int ext_refresh_frame_context; - int ext_use_ref_frame_mvs; - int ext_use_error_resilient; - int ext_use_s_frame; - int ext_use_primary_ref_none; + // Flags signalled by the external interface at frame level. + ExternalFlags ext_flags; YV12_BUFFER_CONFIG last_frame_uf; YV12_BUFFER_CONFIG trial_frame_rst; @@ -837,41 +1140,38 @@ typedef struct AV1_COMP { CODING_CONTEXT coding_context; - int gmtype_cost[TRANS_TYPES]; - int gmparams_cost[REF_FRAMES]; + // Parameters related to global motion search. + GlobalMotionInfo gm_info; - int64_t last_time_stamp_seen; - int64_t last_end_time_stamp_seen; - int64_t first_time_stamp_ever; + // Parameters related to winner mode processing. + WinnerModeParams winner_mode_params; + + // Frame time stamps + TimeStamps time_stamps; RATE_CONTROL rc; double framerate; struct aom_codec_pkt_list *output_pkt_list; - MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS]; - int mbgraph_n_frames; // number of frames filled in the above - int static_mb_pct; // % forced skip mbs by segmentation int ref_frame_flags; - int ext_ref_frame_flags; // speed is passed as a per-frame parameter into the encoder int speed; // sf contains fine-grained config set internally based on speed SPEED_FEATURES sf; - unsigned int max_mv_magnitude; - int mv_step_param; + // Parameters for motion vector search process. + MotionVectorSearchParams mv_search_params; int all_one_sided_refs; - uint8_t *segmentation_map; + // Segmentation related information for current frame. + EncSegmentationInfo enc_seg; CYCLIC_REFRESH *cyclic_refresh; ActiveMap active_map; - 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 @@ -882,12 +1182,6 @@ typedef struct AV1_COMP { // number of show frames encoded in current gf_group int num_gf_group_show_frames; - // when two pass tpl model is used, set to 1 for the - // first pass, then 0 for the final pass. - int tpl_model_pass; - // Number of gf_group frames for tpl stats - int tpl_gf_group_frames; - TWO_PASS twopass; GF_GROUP gf_group; @@ -943,19 +1237,8 @@ typedef struct AV1_COMP { // normalize the firstpass stats. This will differ from the // number of MBs in the current frame when the frame is // scaled. - - // When resize is triggered through external control, the desired width/height - // are stored here until use in the next frame coded. They are effective only - // for - // one frame and are reset after use. - int resize_pending_width; - int resize_pending_height; - - // 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]; + // Resize related parameters + ResizePendingParams resize_pending_params; TileDataEnc *tile_data; int allocated_tiles; // Keep track of memory allocated for tiles. @@ -963,10 +1246,6 @@ typedef struct AV1_COMP { TOKENEXTRA *tile_tok[MAX_TILE_ROWS][MAX_TILE_COLS]; TOKENLIST *tplist[MAX_TILE_ROWS][MAX_TILE_COLS]; - int resize_state; - int resize_avg_qp; - int resize_buffer_underflow; - // Sequence parameters have been transmitted already and locked // or not. Once locked av1_change_config cannot change the seq // parameters. @@ -975,74 +1254,26 @@ 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; + // Thresholds for variance based partitioning. + VarBasedPartitionInfo vbp_info; - int obmc_probs[FRAME_UPDATE_TYPES][BLOCK_SIZES_ALL]; - int obmc_probs_thresh; - int tx_type_probs[FRAME_UPDATE_TYPES][TX_SIZES_ALL][TX_TYPES]; - int tx_type_probs_thresh[FRAME_UPDATE_TYPES]; + // Probabilities for pruning of various AV1 tools. + FrameProbInfo frame_probs; // Multi-threading int num_workers; AVxWorker *workers; struct EncWorkerData *tile_thr_data; int existing_fb_idx_to_show; - int is_arf_filter_off[MAX_INTERNAL_ARFS + 1]; - int global_motion_search_done; 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]; - // TODO(huisu@google.com): we can update dv_joint_cost per SB. - int dv_joint_cost[MV_JOINTS]; - int has_lossless_segment; - // Factors to control gating of compound type selection based on best - // approximate rd so far - int max_comp_type_rd_threshold_mul; - int max_comp_type_rd_threshold_div; + // Tables to calculate IntraBC MV cost. + IntraBCMVCosts dv_costs; - // Threshold of transform domain distortion - // Index 0: Default mode evaluation, Winner mode processing is not applicable - // (Eg : IntraBc). - // Index 1: Mode evaluation. - // Index 2: Winner mode evaluation. - // Index 1 and 2 are applicable when enable_winner_mode_for_use_tx_domain_dist - // speed feature is ON - unsigned int tx_domain_dist_threshold[MODE_EVAL_TYPES]; - - // Factor to control R-D optimization of coeffs based on block - // mse. - // Index 0: Default mode evaluation, Winner mode processing is not applicable - // (Eg : IntraBc). Index 1: Mode evaluation. - // Index 2: Winner mode evaluation - // Index 1 and 2 are applicable when enable_winner_mode_for_coeff_opt speed - // feature is ON - unsigned int coeff_opt_dist_threshold[MODE_EVAL_TYPES]; - - // Transform size to be used in transform search - // Index 0: Default mode evaluation, Winner mode processing is not applicable - // (Eg : IntraBc). - // Index 1: Mode evaluation. Index 2: Winner mode evaluation - // Index 1 and 2 are applicable when enable_winner_mode_for_tx_size_srch speed - // feature is ON - TX_SIZE_SEARCH_METHOD tx_size_search_methods[MODE_EVAL_TYPES]; - - // Transform domain distortion levels - // Index 0: Default mode evaluation, Winner mode processing is not applicable - // (Eg : IntraBc). - // Index 1: Mode evaluation. Index 2: Winner mode evaluation - // Index 1 and 2 are applicable when enable_winner_mode_for_use_tx_domain_dist - // speed feature is ON - unsigned int use_transform_domain_distortion[MODE_EVAL_TYPES]; + // Mark which ref frames can be skipped for encoding current frame druing RDO. + int prune_ref_frame_mask; AV1LfSync lf_row_sync; AV1LrSync lr_row_sync; @@ -1052,10 +1283,10 @@ typedef struct AV1_COMP { #if CONFIG_DENOISE struct aom_denoise_and_model_t *denoise_and_model; #endif - // Stores the default value of skip flag depending on chroma format - // Set as 1 for monochrome and 3 for other color formats - int default_interp_skip_flags; - int preserve_arf_as_gld; + + // Flags related to interpolation filter search. + InterpSearchFlags interp_search_flags; + MultiThreadHandle multi_thread_ctxt; void (*row_mt_sync_read_ptr)(AV1RowMTSync *const, int, int); void (*row_mt_sync_write_ptr)(AV1RowMTSync *const, int, int, const int); @@ -1076,14 +1307,8 @@ typedef struct AV1_COMP { 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]; - // Bit mask to indicate whether to keep level stats for corresponding - // operating points. - uint32_t 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; + // Parameters for AV1 bitstream levels. + AV1LevelParams level_params; // whether any no-zero delta_q was actually used int deltaq_used; @@ -1100,8 +1325,32 @@ typedef struct AV1_COMP { double *tpl_sb_rdmult_scaling_factors; double *ssim_rdmult_scaling_factors; +#if CONFIG_TUNE_VMAF + double *vmaf_rdmult_scaling_factors; + double last_frame_ysse; + double last_frame_vmaf; + double last_frame_unsharp_amount; +#endif + int use_svc; SVC svc; + + int lap_enabled; + COMPRESSOR_STAGE compressor_stage; + + // Some motion vector stats from the last encoded frame to help us decide what + // precision to use to encode the current frame. + MV_STATS mv_stats; + + // Frame type of the last frame. May be used in some heuristics for speeding + // up the encoding. + FRAME_TYPE last_frame_type; + int num_tg; + + // Super-resolution mode currently being used by the encoder. + // This may / may not be same as user-supplied mode in oxcf->superres_mode + // (when we are recoding to try multiple options for example). + SUPERRES_MODE superres_mode; } AV1_COMP; typedef struct { @@ -1130,7 +1379,6 @@ struct EncodeFrameParams { 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_alt_ref_frame; @@ -1150,11 +1398,19 @@ typedef struct { void av1_initialize_enc(void); struct AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf, - BufferPool *const pool); + BufferPool *const pool, + FIRSTPASS_STATS *frame_stats_buf, + COMPRESSOR_STAGE stage, + int num_lap_buffers, + int lap_lag_in_frames, + STATS_BUFFER_CTX *stats_buf_context); void av1_remove_compressor(AV1_COMP *cpi); void av1_change_config(AV1_COMP *cpi, const AV1EncoderConfig *oxcf); +void av1_check_initial_width(AV1_COMP *cpi, int use_highbitdepth, + int subsampling_x, int subsampling_y); + // receive a frames worth of data. caller can assume that a copy of this // frame is made and not just a copy of the pointer.. int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags, @@ -1179,7 +1435,7 @@ aom_codec_err_t av1_copy_new_frame_enc(AV1_COMMON *cm, YV12_BUFFER_CONFIG *new_frame, YV12_BUFFER_CONFIG *sd); -int av1_use_as_reference(AV1_COMP *cpi, int ref_frame_flags); +int av1_use_as_reference(int *ext_ref_frame_flags, int ref_frame_flags); int av1_copy_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd); @@ -1189,14 +1445,16 @@ int av1_set_size_literal(AV1_COMP *cpi, int width, int height); void av1_set_frame_size(AV1_COMP *cpi, int width, int height); -int av1_update_entropy(AV1_COMP *cpi, int update); +int av1_update_entropy(bool *ext_refresh_frame_context, + bool *ext_refresh_frame_context_pending, bool update); int av1_set_active_map(AV1_COMP *cpi, unsigned char *map, int rows, int cols); int av1_get_active_map(AV1_COMP *cpi, unsigned char *map, int rows, int cols); -int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode, - AOM_SCALING vert_mode); +int av1_set_internal_size(AV1EncoderConfig *const oxcf, + ResizePendingParams *resize_pending_params, + AOM_SCALING horiz_mode, AOM_SCALING vert_mode); int av1_get_quantizer(struct AV1_COMP *cpi); @@ -1206,6 +1464,18 @@ void av1_alloc_compound_type_rd_buffers(AV1_COMMON *const cm, CompoundTypeRdBuffers *const bufs); void av1_release_compound_type_rd_buffers(CompoundTypeRdBuffers *const bufs); +// Set screen content options. +// This function estimates whether to use screen content tools, by counting +// the portion of blocks that have few luma colors. +// Modifies: +// cpi->commom.allow_screen_content_tools +// cpi->common.allow_intrabc +// However, the estimation is not accurate and may misclassify videos. +// A slower but more accurate approach that determines whether to use screen +// content tools is employed later. See determine_sc_tools_with_encoding(). +void av1_set_screen_content_options(const struct AV1_COMP *cpi, + FeatureFlags *features); + // TODO(jingning): Move these functions as primitive members for the new cpi // class. static INLINE void stack_push(int *stack, int *stack_size, int item) { @@ -1261,16 +1531,10 @@ static INLINE int frame_is_kf_gf_arf(const AV1_COMP *cpi) { } // TODO(huisu@google.com, youzhou@microsoft.com): enable hash-me for HBD. -static INLINE int av1_use_hash_me(const AV1_COMMON *const cm) { - return cm->allow_screen_content_tools; -} - -static INLINE hash_table *av1_get_ref_frame_hash_map( - const AV1_COMMON *cm, MV_REFERENCE_FRAME ref_frame) { - const int map_idx = get_ref_frame_map_idx(cm, ref_frame); - RefCntBuffer *buf = - (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL; - return buf ? &buf->hash_table : NULL; +static INLINE int av1_use_hash_me(const AV1_COMP *const cpi) { + return (cpi->common.features.allow_screen_content_tools && + cpi->common.features.allow_intrabc && + frame_is_intra_only(&cpi->common)); } static INLINE const YV12_BUFFER_CONFIG *get_ref_frame_yv12_buf( @@ -1328,7 +1592,7 @@ static INLINE void get_start_tok(AV1_COMP *cpi, int tile_row, int tile_col, int mi_row, TOKENEXTRA **tok, int sb_size_log2, int num_planes) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; + const int tile_cols = cm->tiles.cols; TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col]; const TileInfo *const tile_info = &this_tile->tile_info; @@ -1347,6 +1611,36 @@ static INLINE int is_altref_enabled(const AV1_COMP *const cpi) { return cpi->oxcf.lag_in_frames >= ALT_MIN_LAG && cpi->oxcf.enable_auto_arf; } +// Check if statistics generation stage +static INLINE int is_stat_generation_stage(const AV1_COMP *const cpi) { + assert(IMPLIES(cpi->compressor_stage == LAP_STAGE, + cpi->oxcf.pass == 0 && cpi->lap_enabled)); + return (cpi->oxcf.pass == 1 || (cpi->compressor_stage == LAP_STAGE)); +} +// Check if statistics consumption stage +static INLINE int is_stat_consumption_stage_twopass(const AV1_COMP *const cpi) { + return (cpi->oxcf.pass == 2); +} + +// Check if statistics consumption stage +static INLINE int is_stat_consumption_stage(const AV1_COMP *const cpi) { + return (is_stat_consumption_stage_twopass(cpi) || + (cpi->oxcf.pass == 0 && (cpi->compressor_stage == ENCODE_STAGE) && + cpi->lap_enabled)); +} + +// Check if the current stage has statistics +static INLINE int has_no_stats_stage(const AV1_COMP *const cpi) { + assert(IMPLIES(!cpi->lap_enabled, cpi->compressor_stage == ENCODE_STAGE)); + return (cpi->oxcf.pass == 0 && !cpi->lap_enabled); +} + +// Function return size of frame stats buffer +static INLINE int get_stats_buf_size(int num_lap_buffer, int num_lag_buffer) { + /* if lookahead is enabled return num_lap_buffers else num_lag_buffers */ + return (num_lap_buffer > 0 ? num_lap_buffer + 1 : num_lag_buffer); +} + // TODO(zoeliu): To set up cpi->oxcf.enable_auto_brf static INLINE void set_ref_ptrs(const AV1_COMMON *cm, MACROBLOCKD *xd, @@ -1362,8 +1656,17 @@ static INLINE int get_chessboard_index(int frame_index) { return frame_index & 0x1; } +static INLINE const int *cond_cost_list_const(const struct AV1_COMP *cpi, + const int *cost_list) { + const int use_cost_list = cpi->sf.mv_sf.subpel_search_method != SUBPEL_TREE && + cpi->sf.mv_sf.use_fullpel_costlist; + return use_cost_list ? cost_list : NULL; +} + static INLINE int *cond_cost_list(const struct AV1_COMP *cpi, int *cost_list) { - return cpi->sf.mv.subpel_search_method != SUBPEL_TREE ? cost_list : NULL; + const int use_cost_list = cpi->sf.mv_sf.subpel_search_method != SUBPEL_TREE && + cpi->sf.mv_sf.use_fullpel_costlist; + return use_cost_list ? cost_list : NULL; } // Compression ratio of current frame. @@ -1390,26 +1693,31 @@ static INLINE int av1_frame_scaled(const AV1_COMMON *cm) { // frame. An exception can be made for a forward keyframe since it has no // previous dependencies. static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) { - return cm->show_existing_frame && (!cm->error_resilient_mode || + return cm->show_existing_frame && (!cm->features.error_resilient_mode || cm->current_frame.frame_type == KEY_FRAME); } +// Get index into the 'cpi->mbmi_ext_info.frame_base' array for the given +// 'mi_row' and 'mi_col'. +static INLINE int get_mi_ext_idx(const int mi_row, const int mi_col, + const BLOCK_SIZE mi_alloc_bsize, + const int mbmi_ext_stride) { + const int mi_ext_size_1d = mi_size_wide[mi_alloc_bsize]; + const int mi_ext_row = mi_row / mi_ext_size_1d; + const int mi_ext_col = mi_col / mi_ext_size_1d; + return mi_ext_row * mbmi_ext_stride + mi_ext_col; +} + // 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 grid_idx = get_mi_grid_idx(cm, mi_row, mi_col); - const int mi_idx = get_alloc_mi_idx(cm, mi_row, mi_col); - const int ext_idx = get_mi_ext_idx(cm, mi_row, mi_col); - - xd->mi = cm->mi_grid_base + grid_idx; - xd->mi[0] = cm->mi + mi_idx; - xd->tx_type_map = cm->tx_type_map + grid_idx; - xd->tx_type_map_stride = cm->mi_stride; - x->mbmi_ext_frame = cpi->mbmi_ext_frame_base + ext_idx; +static INLINE void set_mode_info_offsets( + const CommonModeInfoParams *const mi_params, + const MBMIExtFrameBufferInfo *const mbmi_ext_info, MACROBLOCK *const x, + MACROBLOCKD *const xd, int mi_row, int mi_col) { + set_mi_offsets(mi_params, xd, mi_row, mi_col); + const int ext_idx = get_mi_ext_idx(mi_row, mi_col, mi_params->mi_alloc_bsize, + mbmi_ext_info->stride); + x->mbmi_ext_frame = mbmi_ext_info->frame_base + ext_idx; } // Check to see if the given partition size is allowed for a specified number @@ -1452,12 +1760,80 @@ static const MV_REFERENCE_FRAME disable_order[] = { static INLINE 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; + (cpi->sf.inter_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); } +static const MV_REFERENCE_FRAME + ref_frame_priority_order[INTER_REFS_PER_FRAME] = { + LAST_FRAME, ALTREF_FRAME, BWDREF_FRAME, GOLDEN_FRAME, + ALTREF2_FRAME, LAST2_FRAME, LAST3_FRAME, + }; + +static INLINE int get_ref_frame_flags(const SPEED_FEATURES *const sf, + const YV12_BUFFER_CONFIG **ref_frames, + const int ext_ref_frame_flags) { + // cpi->ext_flags.ref_frame_flags allows certain reference types to be + // disabled by the external interface. These are set by + // av1_apply_encoding_flags(). Start with what the external interface allows, + // then suppress any reference types which we have found to be duplicates. + int flags = ext_ref_frame_flags; + + for (int i = 1; i < INTER_REFS_PER_FRAME; ++i) { + const YV12_BUFFER_CONFIG *const this_ref = ref_frames[i]; + // If this_ref has appeared before, mark the corresponding ref frame as + // invalid. For nonrd mode, only disable GOLDEN_FRAME if it's the same + // as LAST_FRAME or ALTREF_FRAME (if ALTREF is being used in nonrd). + int index = (sf->rt_sf.use_nonrd_pick_mode && + ref_frame_priority_order[i] == GOLDEN_FRAME) + ? (1 + sf->rt_sf.use_nonrd_altref_frame) + : i; + for (int j = 0; j < index; ++j) { + if (this_ref == ref_frames[j]) { + flags &= ~(1 << (ref_frame_priority_order[i] - 1)); + break; + } + } + } + return flags; +} + +// Enforce the number of references for each arbitrary frame based on user +// options and speed. +static AOM_INLINE void enforce_max_ref_frames(AV1_COMP *cpi, + int *ref_frame_flags) { + MV_REFERENCE_FRAME ref_frame; + int total_valid_refs = 0; + + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { + if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) { + total_valid_refs++; + } + } + + const int max_allowed_refs = get_max_allowed_ref_frames(cpi); + + for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) { + const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i]; + + if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) { + continue; + } + + switch (ref_frame_to_disable) { + case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break; + case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break; + case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break; + case GOLDEN_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break; + default: assert(0); + } + --total_valid_refs; + } + assert(total_valid_refs <= max_allowed_refs); +} + // 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 @@ -1469,6 +1845,12 @@ static INLINE int get_max_allowed_ref_frames(const AV1_COMP *cpi) { // field. aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi); +#define MAX_GFUBOOST_FACTOR 10.0 +#define MIN_GFUBOOST_FACTOR 4.0 +double av1_get_gfu_boost_projection_factor(double min_factor, double max_factor, + int frame_count); +double av1_get_kf_boost_projection_factor(int frame_count); + #define ENABLE_KF_TPL 1 #define MAX_PYR_LEVEL_FROMTOP_DELTAQ 0 diff --git a/media/libaom/src/av1/encoder/encodetxb.c b/media/libaom/src/av1/encoder/encodetxb.c index bcd0c55371..825d52a7ae 100644 --- a/media/libaom/src/av1/encoder/encodetxb.c +++ b/media/libaom/src/av1/encoder/encodetxb.c @@ -73,8 +73,8 @@ static INLINE int get_dqv(const int16_t *dequant, int coeff_idx, void av1_alloc_txb_buf(AV1_COMP *cpi) { AV1_COMMON *cm = &cpi->common; - int size = ((cm->mi_rows >> cm->seq_params.mib_size_log2) + 1) * - ((cm->mi_cols >> cm->seq_params.mib_size_log2) + 1); + int size = ((cm->mi_params.mi_rows >> cm->seq_params.mib_size_log2) + 1) * + ((cm->mi_params.mi_cols >> cm->seq_params.mib_size_log2) + 1); av1_free_txb_buf(cpi); // TODO(jingning): This should be further reduced. @@ -519,8 +519,9 @@ void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCK *const x, if (eob == 0) return; const PLANE_TYPE plane_type = get_plane_type(plane); - const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, cm->reduced_tx_set_used); + const TX_TYPE tx_type = + av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size, + cm->features.reduced_tx_set_used); // Only y plane's tx_type is transmitted if (plane == 0) { av1_write_tx_type(cm, xd, tx_type, tx_size, w); @@ -646,8 +647,8 @@ typedef struct encode_txb_args { aom_writer *w; } ENCODE_TXB_ARGS; -void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x, int mi_row, - int mi_col, aom_writer *w, BLOCK_SIZE bsize) { +void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x, + aom_writer *w, BLOCK_SIZE bsize) { MACROBLOCKD *xd = &x->e_mbd; const int num_planes = av1_num_planes(cm); int block[MAX_MB_PLANE] = { 0 }; @@ -657,23 +658,20 @@ void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x, int mi_row, const int max_blocks_wide = max_block_wide(xd, bsize, 0); const int max_blocks_high = max_block_high(xd, bsize, 0); const BLOCK_SIZE max_unit_bsize = BLOCK_64X64; - int mu_blocks_wide = block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(max_blocks_wide, mu_blocks_wide); mu_blocks_high = AOMMIN(max_blocks_high, mu_blocks_high); for (row = 0; row < max_blocks_high; row += mu_blocks_high) { for (col = 0; col < max_blocks_wide; col += mu_blocks_wide) { for (int plane = 0; plane < num_planes; ++plane) { - const struct macroblockd_plane *const pd = &xd->plane[plane]; - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) - continue; + if (plane && !xd->is_chroma_ref) break; const TX_SIZE tx_size = av1_get_tx_size(plane, xd); const int stepr = tx_size_high_unit[tx_size]; const int stepc = tx_size_wide_unit[tx_size]; const int step = stepr * stepc; - + const struct macroblockd_plane *const pd = &xd->plane[plane]; const int unit_height = ROUND_POWER_OF_TWO( AOMMIN(mu_blocks_high + row, max_blocks_high), pd->subsampling_y); const int unit_width = ROUND_POWER_OF_TWO( @@ -725,6 +723,36 @@ static int get_tx_type_cost(const MACROBLOCK *x, const MACROBLOCKD *xd, return 0; } +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 = AOMSIGN(coeff); + 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 int warehouse_efficients_txb( const MACROBLOCK *x, const int plane, const int block, const TX_SIZE tx_size, const TXB_CTX *const txb_ctx, @@ -761,7 +789,7 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb( { const int pos = scan[c]; const tran_low_t v = qcoeff[pos]; - const int sign = v >> 31; + const int sign = AOMSIGN(v); const int level = (v ^ sign) - sign; const int coeff_ctx = coeff_contexts[pos]; cost += coeff_costs->base_eob_cost[coeff_ctx][AOMMIN(level, 3) - 1]; @@ -803,7 +831,7 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb( const int pos = scan[c]; const tran_low_t v = qcoeff[pos]; const int coeff_ctx = coeff_contexts[pos]; - const int sign = v >> 31; + const int sign = AOMSIGN(v); const int level = (v ^ sign) - sign; cost += base_cost[coeff_ctx][AOMMIN(level, 3)]; @@ -821,6 +849,71 @@ static AOM_FORCE_INLINE int warehouse_efficients_txb( return cost; } +static AOM_FORCE_INLINE int warehouse_efficients_txb_laplacian( + const MACROBLOCK *x, const int plane, const int block, + const TX_SIZE tx_size, const TXB_CTX *const txb_ctx, const int eob, + const PLANE_TYPE plane_type, const LV_MAP_COEFF_COST *const coeff_costs, + const MACROBLOCKD *const xd, const TX_TYPE tx_type, const TX_CLASS tx_class, + int reduced_tx_set_used) { + const int txb_skip_ctx = txb_ctx->txb_skip_ctx; + + const int eob_multi_size = txsize_log2_minus4[tx_size]; + const LV_MAP_EOB_COST *const eob_costs = + &x->eob_costs[eob_multi_size][plane_type]; + int cost = coeff_costs->txb_skip_cost[txb_skip_ctx][0]; + + cost += get_tx_type_cost(x, xd, plane, tx_size, tx_type, reduced_tx_set_used); + + cost += get_eob_cost(eob, eob_costs, coeff_costs, tx_class); + + cost += av1_cost_coeffs_txb_estimate(x, plane, block, tx_size, tx_type); + return cost; +} + +// Look up table of individual cost of coefficient by its quantization level. +// determined based on Laplacian distribution conditioned on estimated context +static const int costLUT[15] = { -1143, 53, 545, 825, 1031, + 1209, 1393, 1577, 1763, 1947, + 2132, 2317, 2501, 2686, 2871 }; +static const int const_term = (1 << AV1_PROB_COST_SHIFT); +static const int loge_par = ((14427 << AV1_PROB_COST_SHIFT) + 5000) / 10000; +int av1_cost_coeffs_txb_estimate(const MACROBLOCK *x, const int plane, + const int block, const TX_SIZE tx_size, + const TX_TYPE tx_type) { + assert(plane == 0); + + int cost = 0; + 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; + tran_low_t *qcoeff = p->qcoeff + BLOCK_OFFSET(block); + + int eob = p->eobs[block]; + + // coeffs + int c = eob - 1; + // eob + { + const int pos = scan[c]; + const tran_low_t v = abs(qcoeff[pos]) - 1; + cost += (v << (AV1_PROB_COST_SHIFT + 2)); + } + // other coeffs + for (c = eob - 2; c >= 0; c--) { + const int pos = scan[c]; + const tran_low_t v = abs(qcoeff[pos]); + const int idx = AOMMIN(v, 14); + + cost += costLUT[idx]; + } + + // const_term does not contain DC, and log(e) does not contain eob, so both + // (eob-1) + cost += (const_term + loge_par) * (eob - 1); + + return cost; +} + int av1_cost_coeffs_txb(const MACROBLOCK *x, const int plane, const int block, const TX_SIZE tx_size, const TX_TYPE tx_type, const TXB_CTX *const txb_ctx, int reduced_tx_set_used) { @@ -842,6 +935,44 @@ int av1_cost_coeffs_txb(const MACROBLOCK *x, const int plane, const int block, tx_class, reduced_tx_set_used); } +int av1_cost_coeffs_txb_laplacian(const MACROBLOCK *x, const int plane, + const int block, const TX_SIZE tx_size, + const TX_TYPE tx_type, + const TXB_CTX *const txb_ctx, + const int reduced_tx_set_used, + const int adjust_eob) { + const struct macroblock_plane *p = &x->plane[plane]; + int eob = p->eobs[block]; + + if (adjust_eob) { + const SCAN_ORDER *scan_order = get_scan(tx_size, tx_type); + const int16_t *scan = scan_order->scan; + tran_low_t *tcoeff = p->coeff + BLOCK_OFFSET(block); + tran_low_t *qcoeff = p->qcoeff + BLOCK_OFFSET(block); + const MACROBLOCKD *xd = &x->e_mbd; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + tran_low_t *dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); + update_coeff_eob_fast(&eob, av1_get_tx_scale(tx_size), p->dequant_QTX, scan, + tcoeff, qcoeff, dqcoeff); + p->eobs[block] = eob; + } + + const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); + const PLANE_TYPE plane_type = get_plane_type(plane); + const LV_MAP_COEFF_COST *const coeff_costs = + &x->coeff_costs[txs_ctx][plane_type]; + if (eob == 0) { + return coeff_costs->txb_skip_cost[txb_ctx->txb_skip_ctx][1]; + } + + const MACROBLOCKD *const xd = &x->e_mbd; + const TX_CLASS tx_class = tx_type_to_class[tx_type]; + + return warehouse_efficients_txb_laplacian( + x, plane, block, tx_size, txb_ctx, eob, plane_type, coeff_costs, xd, + tx_type, tx_class, reduced_tx_set_used); +} + static int optimize_txb(TxbInfo *txb_info, const LV_MAP_COEFF_COST *txb_costs, const LV_MAP_EOB_COST *txb_eob_costs, int *rate_cost) { int update = 0; @@ -1474,36 +1605,6 @@ 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, @@ -1649,11 +1750,8 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, const int shift = av1_get_tx_scale(tx_size); int eob = p->eobs[block]; const int16_t *dequant = p->dequant_QTX; - const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); const qm_val_t *iqmatrix = - IS_2D_TRANSFORM(tx_type) - ? pd->seg_iqmatrix[xd->mi[0]->segment_id][qm_tx_size] - : cpi->common.giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; + av1_get_iqmatrix(&cpi->common.quant_params, xd, plane, tx_size, tx_type); const int block_offset = BLOCK_OFFSET(block); tran_low_t *qcoeff = p->qcoeff + block_offset; tran_low_t *dqcoeff = pd->dqcoeff + block_offset; @@ -1791,8 +1889,8 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, levels, iqmatrix); } - const int tx_type_cost = - get_tx_type_cost(x, xd, plane, tx_size, tx_type, cm->reduced_tx_set_used); + const int tx_type_cost = get_tx_type_cost(x, xd, plane, tx_size, tx_type, + cm->features.reduced_tx_set_used); if (eob == 0) accu_rate += skip_cost; else @@ -1812,7 +1910,7 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, int blk_row, int blk_col, int block, TX_SIZE tx_size, TXB_CTX *txb_ctx, int fast_mode, int *rate_cost) { const AV1_COMMON *cm = &cpi->common; - const int reduced_tx_set_used = cm->reduced_tx_set_used; + const int reduced_tx_set_used = cm->features.reduced_tx_set_used; MACROBLOCKD *const xd = &x->e_mbd; const PLANE_TYPE plane_type = get_plane_type(plane); const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); @@ -1846,11 +1944,8 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane, 2; uint8_t levels_buf[TX_PAD_2D]; uint8_t *const levels = set_levels(levels_buf, width); - const TX_SIZE qm_tx_size = av1_get_adjusted_tx_size(tx_size); const qm_val_t *iqmatrix = - IS_2D_TRANSFORM(tx_type) - ? pd->seg_iqmatrix[mbmi->segment_id][qm_tx_size] - : cm->giqmatrix[NUM_QM_LEVELS - 1][0][qm_tx_size]; + av1_get_iqmatrix(&cpi->common.quant_params, xd, plane, tx_size, tx_type); assert(width == (1 << bwl)); const int tx_type_cost = get_tx_type_cost(x, xd, plane, tx_size, tx_type, reduced_tx_set_used); @@ -1902,28 +1997,6 @@ int av1_get_txb_entropy_context(const tran_low_t *qcoeff, return cul_level; } -void av1_update_txb_context_b(int plane, int block, int blk_row, int blk_col, - BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - void *arg) { - struct tokenize_b_args *const args = arg; - const AV1_COMP *cpi = args->cpi; - const AV1_COMMON *cm = &cpi->common; - ThreadData *const td = args->td; - MACROBLOCK *const x = &td->mb; - MACROBLOCKD *const xd = &x->e_mbd; - struct macroblock_plane *p = &x->plane[plane]; - struct macroblockd_plane *pd = &xd->plane[plane]; - const uint16_t eob = p->eobs[block]; - const tran_low_t *qcoeff = p->qcoeff + BLOCK_OFFSET(block); - const PLANE_TYPE plane_type = pd->plane_type; - const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, cm->reduced_tx_set_used); - const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type); - const int cul_level = av1_get_txb_entropy_context(qcoeff, scan_order, eob); - av1_set_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level, blk_col, - blk_row); -} - static void update_tx_type_count(const AV1_COMP *cpi, const AV1_COMMON *cm, MACROBLOCKD *xd, int blk_row, int blk_col, int plane, TX_SIZE tx_size, @@ -1931,7 +2004,7 @@ static void update_tx_type_count(const AV1_COMP *cpi, const AV1_COMMON *cm, uint8_t allow_update_cdf) { MB_MODE_INFO *mbmi = xd->mi[0]; int is_inter = is_inter_block(mbmi); - const int reduced_tx_set_used = cm->reduced_tx_set_used; + const int reduced_tx_set_used = cm->features.reduced_tx_set_used; FRAME_CONTEXT *fc = xd->tile_ctx; #if !CONFIG_ENTROPY_STATS (void)counts; @@ -1957,7 +2030,7 @@ static void update_tx_type_count(const AV1_COMP *cpi, const AV1_COMMON *cm, } if (get_ext_tx_types(tx_size, is_inter, reduced_tx_set_used) > 1 && - cm->base_qindex > 0 && !mbmi->skip && + cm->quant_params.base_qindex > 0 && !mbmi->skip && !segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { const int eset = get_ext_tx_set(tx_size, is_inter, reduced_tx_set_used); if (eset > 0) { @@ -2006,96 +2079,98 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row, MACROBLOCKD *const xd = &x->e_mbd; struct macroblock_plane *p = &x->plane[plane]; struct macroblockd_plane *pd = &xd->plane[plane]; - MB_MODE_INFO *mbmi = xd->mi[0]; const int eob = p->eobs[block]; - TXB_CTX txb_ctx; - get_txb_ctx(plane_bsize, tx_size, plane, pd->above_context + blk_col, - pd->left_context + blk_row, &txb_ctx); - const int bwl = get_txb_bwl(tx_size); - const int width = get_txb_wide(tx_size); - const int height = get_txb_high(tx_size); - const uint8_t allow_update_cdf = args->allow_update_cdf; - const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size); - FRAME_CONTEXT *ec_ctx = xd->tile_ctx; -#if CONFIG_ENTROPY_STATS - int cdf_idx = cm->coef_cdf_category; -#endif // CONFIG_ENTROPY_STATS - -#if CONFIG_ENTROPY_STATS - ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0]; -#endif // CONFIG_ENTROPY_STATS - if (allow_update_cdf) { - update_cdf(ec_ctx->txb_skip_cdf[txsize_ctx][txb_ctx.txb_skip_ctx], eob == 0, - 2); - } - - CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff; - const int txb_offset = - x->mbmi_ext_frame->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); - uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset; - uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset; - entropy_ctx[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; - } - const int segment_id = mbmi->segment_id; - const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size); - tran_low_t *tcoeff_txb = - cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset; const int block_offset = BLOCK_OFFSET(block); - tran_low_t *tcoeff = tcoeff_txb + block_offset; - const tran_low_t *qcoeff = p->qcoeff + block_offset; - memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob); - - uint8_t levels_buf[TX_PAD_2D]; - uint8_t *const levels = set_levels(levels_buf, width); - av1_txb_init_levels(tcoeff, width, height, levels); - update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size, - td->counts, allow_update_cdf); - + tran_low_t *qcoeff = p->qcoeff + block_offset; const PLANE_TYPE plane_type = pd->plane_type; - const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, cm->reduced_tx_set_used); - const TX_CLASS tx_class = tx_type_to_class[tx_type]; + const TX_TYPE tx_type = + av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size, + cm->features.reduced_tx_set_used); const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type); - const int16_t *const scan = scan_order->scan; + tran_low_t *tcoeff; + assert(args->dry_run != DRY_RUN_COSTCOEFFS); + if (args->dry_run == OUTPUT_ENABLED) { + MB_MODE_INFO *mbmi = xd->mi[0]; + TXB_CTX txb_ctx; + get_txb_ctx(plane_bsize, tx_size, plane, + pd->above_entropy_context + blk_col, + pd->left_entropy_context + blk_row, &txb_ctx); + const int bwl = get_txb_bwl(tx_size); + const int width = get_txb_wide(tx_size); + const int height = get_txb_high(tx_size); + const uint8_t allow_update_cdf = args->allow_update_cdf; + const TX_SIZE txsize_ctx = get_txsize_entropy_ctx(tx_size); + FRAME_CONTEXT *ec_ctx = xd->tile_ctx; +#if CONFIG_ENTROPY_STATS + int cdf_idx = cm->coef_cdf_category; + ++td->counts->txb_skip[cdf_idx][txsize_ctx][txb_ctx.txb_skip_ctx][eob == 0]; +#endif // CONFIG_ENTROPY_STATS + if (allow_update_cdf) { + update_cdf(ec_ctx->txb_skip_cdf[txsize_ctx][txb_ctx.txb_skip_ctx], + eob == 0, 2); + } - // record tx type usage - td->rd_counts - .tx_type_used[get_frame_update_type(&cpi->gf_group)][tx_size][tx_type]++; + CB_COEFF_BUFFER *cb_coef_buff = x->cb_coef_buff; + const int txb_offset = + x->mbmi_ext_frame->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN); + uint16_t *eob_txb = cb_coef_buff->eobs[plane] + txb_offset; + uint8_t *const entropy_ctx = cb_coef_buff->entropy_ctx[plane] + txb_offset; + entropy_ctx[block] = txb_ctx.txb_skip_ctx; + eob_txb[block] = eob; + + if (eob == 0) { + av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col, + blk_row); + return; + } + const int segment_id = mbmi->segment_id; + const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size); + tran_low_t *tcoeff_txb = + cb_coef_buff->tcoeff[plane] + x->mbmi_ext_frame->cb_offset; + tcoeff = tcoeff_txb + block_offset; + memcpy(tcoeff, qcoeff, sizeof(*tcoeff) * seg_eob); + + uint8_t levels_buf[TX_PAD_2D]; + uint8_t *const levels = set_levels(levels_buf, width); + av1_txb_init_levels(tcoeff, width, height, levels); + update_tx_type_count(cpi, cm, xd, blk_row, blk_col, plane, tx_size, + td->counts, allow_update_cdf); + + const TX_CLASS tx_class = tx_type_to_class[tx_type]; + const int16_t *const scan = scan_order->scan; + + // record tx type usage + td->rd_counts.tx_type_used[tx_size][tx_type]++; #if CONFIG_ENTROPY_STATS - av1_update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, - td->counts, allow_update_cdf); + av1_update_eob_context(cdf_idx, eob, tx_size, tx_class, plane_type, ec_ctx, + td->counts, allow_update_cdf); #else - av1_update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx, - allow_update_cdf); + av1_update_eob_context(eob, tx_size, tx_class, plane_type, ec_ctx, + allow_update_cdf); #endif - DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]); - av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, coeff_contexts); + DECLARE_ALIGNED(16, int8_t, coeff_contexts[MAX_TX_SQUARE]); + av1_get_nz_map_contexts(levels, scan, eob, tx_size, tx_class, + coeff_contexts); - for (int c = eob - 1; c >= 0; --c) { - const int pos = scan[c]; - const int coeff_ctx = coeff_contexts[pos]; - const tran_low_t v = qcoeff[pos]; - const tran_low_t level = abs(v); + for (int c = eob - 1; c >= 0; --c) { + const int pos = scan[c]; + const int coeff_ctx = coeff_contexts[pos]; + const tran_low_t v = qcoeff[pos]; + const tran_low_t level = abs(v); - if (allow_update_cdf) { - if (c == eob - 1) { - assert(coeff_ctx < 4); - update_cdf( - ec_ctx->coeff_base_eob_cdf[txsize_ctx][plane_type][coeff_ctx], - AOMMIN(level, 3) - 1, 3); - } else { - update_cdf(ec_ctx->coeff_base_cdf[txsize_ctx][plane_type][coeff_ctx], - AOMMIN(level, 3), 4); + if (allow_update_cdf) { + if (c == eob - 1) { + assert(coeff_ctx < 4); + update_cdf( + ec_ctx->coeff_base_eob_cdf[txsize_ctx][plane_type][coeff_ctx], + AOMMIN(level, 3) - 1, 3); + } else { + update_cdf(ec_ctx->coeff_base_cdf[txsize_ctx][plane_type][coeff_ctx], + AOMMIN(level, 3), 4); + } } - } - { if (c == eob - 1) { assert(coeff_ctx < 4); #if CONFIG_ENTROPY_STATS @@ -2106,77 +2181,72 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row, [coeff_ctx][AOMMIN(level, 3)]; #endif } - } - if (level > NUM_BASE_LEVELS) { - const int base_range = level - 1 - NUM_BASE_LEVELS; - const int br_ctx = get_br_ctx(levels, pos, bwl, tx_class); - for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) { - const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1); - if (allow_update_cdf) { - update_cdf(ec_ctx->coeff_br_cdf[AOMMIN(txsize_ctx, TX_32X32)] - [plane_type][br_ctx], - k, BR_CDF_SIZE); - } - for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) { + if (level > NUM_BASE_LEVELS) { + const int base_range = level - 1 - NUM_BASE_LEVELS; + const int br_ctx = get_br_ctx(levels, pos, bwl, tx_class); + for (int idx = 0; idx < COEFF_BASE_RANGE; idx += BR_CDF_SIZE - 1) { + const int k = AOMMIN(base_range - idx, BR_CDF_SIZE - 1); + if (allow_update_cdf) { + update_cdf(ec_ctx->coeff_br_cdf[AOMMIN(txsize_ctx, TX_32X32)] + [plane_type][br_ctx], + k, BR_CDF_SIZE); + } + for (int lps = 0; lps < BR_CDF_SIZE - 1; lps++) { #if CONFIG_ENTROPY_STATS - ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type][lps] - [br_ctx][lps == k]; + ++td->counts->coeff_lps[AOMMIN(txsize_ctx, TX_32X32)][plane_type] + [lps][br_ctx][lps == k]; #endif // CONFIG_ENTROPY_STATS - if (lps == k) break; - } + if (lps == k) break; + } #if CONFIG_ENTROPY_STATS - ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)] - [plane_type][br_ctx][k]; + ++td->counts->coeff_lps_multi[cdf_idx][AOMMIN(txsize_ctx, TX_32X32)] + [plane_type][br_ctx][k]; #endif - if (k < BR_CDF_SIZE - 1) break; + if (k < BR_CDF_SIZE - 1) break; + } } } - } - - // Update the context needed to code the DC sign (if applicable) - if (tcoeff[0] != 0) { - const int dc_sign = (tcoeff[0] < 0) ? 1 : 0; - const int dc_sign_ctx = txb_ctx.dc_sign_ctx; + // Update the context needed to code the DC sign (if applicable) + if (tcoeff[0] != 0) { + const int dc_sign = (tcoeff[0] < 0) ? 1 : 0; + const int dc_sign_ctx = txb_ctx.dc_sign_ctx; #if CONFIG_ENTROPY_STATS - ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign]; + ++td->counts->dc_sign[plane_type][dc_sign_ctx][dc_sign]; #endif // CONFIG_ENTROPY_STATS - if (allow_update_cdf) - update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2); - entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT; + if (allow_update_cdf) + update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2); + entropy_ctx[block] |= dc_sign_ctx << DC_SIGN_CTX_SHIFT; + } + } else { + tcoeff = qcoeff; } - const int cul_level = av1_get_txb_entropy_context(tcoeff, scan_order, eob); - av1_set_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level, blk_col, - blk_row); + av1_set_entropy_contexts(xd, pd, plane, plane_bsize, tx_size, cul_level, + blk_col, blk_row); } void av1_update_txb_context(const AV1_COMP *cpi, ThreadData *td, - RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate, - int mi_row, int mi_col, uint8_t allow_update_cdf) { + RUN_TYPE dry_run, BLOCK_SIZE bsize, + uint8_t allow_update_cdf) { const AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); MACROBLOCK *const x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; - struct tokenize_b_args arg = { cpi, td, 0, allow_update_cdf }; - (void)rate; - (void)mi_row; - (void)mi_col; + struct tokenize_b_args arg = { cpi, td, 0, allow_update_cdf, dry_run }; if (mbmi->skip) { - av1_reset_skip_context(xd, mi_row, mi_col, bsize, num_planes); + av1_reset_entropy_context(xd, bsize, num_planes); return; } - if (!dry_run) { - av1_foreach_transformed_block(xd, bsize, mi_row, mi_col, - av1_update_and_record_txb_context, &arg, - num_planes); - } else if (dry_run == DRY_RUN_NORMAL) { - av1_foreach_transformed_block(xd, bsize, mi_row, mi_col, - av1_update_txb_context_b, &arg, num_planes); - } else { - printf("DRY_RUN_COSTCOEFFS is not supported yet\n"); - assert(0); + for (int plane = 0; plane < num_planes; ++plane) { + if (plane && !xd->is_chroma_ref) break; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, ss_x, ss_y); + av1_foreach_transformed_block_in_plane( + xd, plane_bsize, plane, av1_update_and_record_txb_context, &arg); } } @@ -2184,7 +2254,7 @@ CB_COEFF_BUFFER *av1_get_cb_coeff_buffer(const struct AV1_COMP *cpi, int mi_row, int mi_col) { const AV1_COMMON *const cm = &cpi->common; const int mib_size_log2 = cm->seq_params.mib_size_log2; - const int stride = (cm->mi_cols >> mib_size_log2) + 1; + const int stride = (cm->mi_params.mi_cols >> mib_size_log2) + 1; const int offset = (mi_row >> mib_size_log2) * stride + (mi_col >> mib_size_log2); return cpi->coeff_buffer_base + offset; diff --git a/media/libaom/src/av1/encoder/encodetxb.h b/media/libaom/src/av1/encoder/encodetxb.h index 677b4f930b..7122895d14 100644 --- a/media/libaom/src/av1/encoder/encodetxb.h +++ b/media/libaom/src/av1/encoder/encodetxb.h @@ -14,8 +14,8 @@ #include "config/aom_config.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" #include "av1/common/txb_common.h" #include "av1/encoder/block.h" #include "av1/encoder/encoder.h" @@ -55,21 +55,25 @@ void av1_free_txb_buf(AV1_COMP *cpi); int av1_cost_coeffs_txb(const MACROBLOCK *x, const int plane, const int block, const TX_SIZE tx_size, const TX_TYPE tx_type, const TXB_CTX *const txb_ctx, int reduced_tx_set_used); +int av1_cost_coeffs_txb_laplacian(const MACROBLOCK *x, const int plane, + const int block, const TX_SIZE tx_size, + const TX_TYPE tx_type, + const TXB_CTX *const txb_ctx, + const int reduced_tx_set_used, + const int adjust_eob); +int av1_cost_coeffs_txb_estimate(const MACROBLOCK *x, const int plane, + const int block, const TX_SIZE tx_size, + const TX_TYPE tx_type); void av1_write_coeffs_txb(const AV1_COMMON *const cm, MACROBLOCK *const x, aom_writer *w, int blk_row, int blk_col, int plane, int block, TX_SIZE tx_size); -void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x, int mi_row, - int mi_col, aom_writer *w, BLOCK_SIZE bsize); +void av1_write_coeffs_mb(const AV1_COMMON *const cm, MACROBLOCK *x, + aom_writer *w, BLOCK_SIZE bsize); int av1_get_txb_entropy_context(const tran_low_t *qcoeff, const SCAN_ORDER *scan_order, int eob); void av1_update_txb_context(const AV1_COMP *cpi, ThreadData *td, - RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate, - int mi_row, int mi_col, uint8_t allow_update_cdf); - -void av1_update_txb_context_b(int plane, int block, int blk_row, int blk_col, - BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - void *arg); - + RUN_TYPE dry_run, BLOCK_SIZE bsize, + uint8_t allow_update_cdf); void av1_update_and_record_txb_context(int plane, int block, int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, void *arg); diff --git a/media/libaom/src/av1/encoder/ethread.c b/media/libaom/src/av1/encoder/ethread.c index 5741f89ea9..693270b873 100644 --- a/media/libaom/src/av1/encoder/ethread.c +++ b/media/libaom/src/av1/encoder/ethread.c @@ -28,12 +28,9 @@ static AOM_INLINE void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) { td_t->rd_counts.compound_ref_used_flag; td->rd_counts.skip_mode_used_flag |= td_t->rd_counts.skip_mode_used_flag; - for (int i = 0; i < FRAME_UPDATE_TYPES; i++) { - for (int j = 0; j < TX_SIZES_ALL; j++) { - for (int k = 0; k < TX_TYPES; k++) - td->rd_counts.tx_type_used[i][j][k] += - td_t->rd_counts.tx_type_used[i][j][k]; - } + for (int i = 0; i < TX_SIZES_ALL; i++) { + for (int j = 0; j < TX_TYPES; j++) + td->rd_counts.tx_type_used[i][j] += td_t->rd_counts.tx_type_used[i][j]; } for (int i = 0; i < BLOCK_SIZES_ALL; i++) { @@ -41,6 +38,10 @@ static AOM_INLINE void accumulate_rd_opt(ThreadData *td, ThreadData *td_t) { td->rd_counts.obmc_used[i][j] += td_t->rd_counts.obmc_used[i][j]; } } + + for (int i = 0; i < 2; i++) { + td->rd_counts.warped_used[i] += td_t->rd_counts.warped_used[i]; + } } static AOM_INLINE void update_delta_lf_for_row_mt(AV1_COMP *cpi) { @@ -49,9 +50,9 @@ static AOM_INLINE void update_delta_lf_for_row_mt(AV1_COMP *cpi) { const int mib_size = cm->seq_params.mib_size; const int frame_lf_count = av1_num_planes(cm) > 1 ? FRAME_LF_COUNT : FRAME_LF_COUNT - 2; - for (int row = 0; row < cm->tile_rows; row++) { - for (int col = 0; col < cm->tile_cols; col++) { - TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col]; + for (int row = 0; row < cm->tiles.rows; row++) { + for (int col = 0; col < cm->tiles.cols; col++) { + TileDataEnc *tile_data = &cpi->tile_data[row * cm->tiles.cols + col]; const TileInfo *const tile_info = &tile_data->tile_info; for (int mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end; mi_row += mib_size) { @@ -59,8 +60,8 @@ static AOM_INLINE void update_delta_lf_for_row_mt(AV1_COMP *cpi) { av1_reset_loop_filter_delta(xd, av1_num_planes(cm)); for (int mi_col = tile_info->mi_col_start; mi_col < tile_info->mi_col_end; mi_col += mib_size) { - const int idx_str = cm->mi_stride * mi_row + mi_col; - MB_MODE_INFO **mi = cm->mi_grid_base + idx_str; + const int idx_str = cm->mi_params.mi_stride * mi_row + mi_col; + MB_MODE_INFO **mi = cm->mi_params.mi_grid_base + idx_str; MB_MODE_INFO *mbmi = mi[0]; if (mbmi->skip == 1 && (mbmi->sb_type == cm->seq_params.sb_size)) { for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id) @@ -239,8 +240,8 @@ static AOM_INLINE void switch_tile_and_get_next_job(AV1_COMP *const cpi, int *current_mi_row, int *end_of_frame) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int tile_id = -1; // Stores the tile ID with minimum proc done int max_mis_to_encode = 0; @@ -341,12 +342,8 @@ static int enc_row_mt_worker_hook(void *arg1, void *unused) { memcpy(td->mb.e_mbd.tile_ctx, &this_tile->tctx, sizeof(FRAME_CONTEXT)); } - av1_init_above_context(cm, &td->mb.e_mbd, tile_row); - - // Disable exhaustive search speed features for row based multi-threading of - // encoder. - td->mb.m_search_count_ptr = NULL; - td->mb.ex_search_count_ptr = NULL; + av1_init_above_context(&cm->above_contexts, av1_num_planes(cm), tile_row, + &td->mb.e_mbd); cfl_init(&td->mb.e_mbd.cfl, &cm->seq_params); av1_crc32c_calculator_init(&td->mb.mb_rd_record.crc_calculator); @@ -368,8 +365,8 @@ static int enc_worker_hook(void *arg1, void *unused) { EncWorkerData *const thread_data = (EncWorkerData *)arg1; AV1_COMP *const cpi = thread_data->cpi; const AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int t; (void)unused; @@ -380,7 +377,7 @@ static int enc_worker_hook(void *arg1, void *unused) { int tile_col = t % tile_cols; TileDataEnc *const this_tile = - &cpi->tile_data[tile_row * cm->tile_cols + tile_col]; + &cpi->tile_data[tile_row * cm->tiles.cols + tile_col]; thread_data->td->mb.e_mbd.tile_ctx = &this_tile->tctx; thread_data->td->mb.tile_pb_ctx = &this_tile->tctx; av1_encode_tile(cpi, thread_data->td, tile_row, tile_col); @@ -429,7 +426,7 @@ static AOM_INLINE void create_enc_workers(AV1_COMP *cpi, int num_workers) { // Set up pc_tree. thread_data->td->pc_tree = NULL; - av1_setup_pc_tree(cm, thread_data->td); + av1_setup_pc_tree(cpi, thread_data->td); CHECK_MEM_ERROR(cm, thread_data->td->above_pred_buf, (uint8_t *)aom_memalign( @@ -487,6 +484,14 @@ static AOM_INLINE void create_enc_workers(AV1_COMP *cpi, int num_workers) { cm, thread_data->td->mbmi_ext, aom_calloc(sb_mi_size, sizeof(*thread_data->td->mbmi_ext))); + if (cpi->sf.part_sf.partition_search_type == VAR_BASED_PARTITION) { + const int num_64x64_blocks = + (cm->seq_params.sb_size == BLOCK_64X64) ? 1 : 4; + CHECK_MEM_ERROR( + cm, thread_data->td->vt64x64, + aom_malloc(sizeof(*thread_data->td->vt64x64) * num_64x64_blocks)); + } + // Create threads if (!winterface->reset(worker)) aom_internal_error(&cm->error, AOM_CODEC_ERROR, @@ -580,10 +585,10 @@ static AOM_INLINE void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook, for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { memcpy(thread_data->td->hash_value_buffer[x][y], - cpi->td.mb.hash_value_buffer[x][y], + cpi->td.mb.intrabc_hash_info.hash_value_buffer[x][y], AOM_BUFFER_SIZE_FOR_BLOCK_HASH * sizeof(*thread_data->td->hash_value_buffer[0][0])); - thread_data->td->mb.hash_value_buffer[x][y] = + thread_data->td->mb.intrabc_hash_info.hash_value_buffer[x][y] = thread_data->td->hash_value_buffer[x][y]; } } @@ -614,8 +619,8 @@ static AOM_INLINE void prepare_enc_workers(AV1_COMP *cpi, AVxWorkerHook hook, void av1_encode_tiles_mt(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; int num_workers = AOMMIN(cpi->oxcf.max_threads, tile_cols * tile_rows); if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) @@ -648,8 +653,8 @@ void av1_accumulate_frame_counts(FRAME_COUNTS *acc_counts, void av1_encode_tiles_row_mt(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt; int num_workers = 0; int total_num_threads_row_mt = 0; @@ -664,7 +669,7 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) { for (int row = 0; row < tile_rows; row++) { for (int col = 0; col < tile_cols; col++) { - TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col]; + TileDataEnc *tile_data = &cpi->tile_data[row * cm->tiles.cols + col]; int num_sb_rows_in_tile = av1_get_sb_rows_in_tile(cm, tile_data->tile_info); int num_sb_cols_in_tile = @@ -706,8 +711,6 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) { av1_zero_above_context(cm, &cpi->td.mb.e_mbd, this_tile->tile_info.mi_col_start, this_tile->tile_info.mi_col_end, tile_row); - this_tile->m_search_count = 0; // Count of motion search hits. - this_tile->ex_search_count = 0; // Exhaustive mesh search hits. } } diff --git a/media/libaom/src/av1/encoder/extend.c b/media/libaom/src/av1/encoder/extend.c index e9621a5742..934cf5644b 100644 --- a/media/libaom/src/av1/encoder/extend.c +++ b/media/libaom/src/av1/encoder/extend.c @@ -103,18 +103,14 @@ static void highbd_copy_and_extend_plane(const uint8_t *src8, int src_pitch, void av1_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst) { // Extend src frame in buffer - // Altref filtering assumes 16 pixel extension - const int et_y = 16; - const int el_y = 16; - // Motion estimation may use src block variance with the block size up - // to 64x64, so the right and bottom need to be extended to 64 multiple - // or up to 16, whichever is greater. + const int et_y = dst->border; + const int el_y = dst->border; const int er_y = - AOMMAX(src->y_width + 16, ALIGN_POWER_OF_TWO(src->y_width, 6)) - + AOMMAX(src->y_width + dst->border, ALIGN_POWER_OF_TWO(src->y_width, 6)) - src->y_crop_width; - const int eb_y = - AOMMAX(src->y_height + 16, ALIGN_POWER_OF_TWO(src->y_height, 6)) - - src->y_crop_height; + const int eb_y = AOMMAX(src->y_height + dst->border, + ALIGN_POWER_OF_TWO(src->y_height, 6)) - + src->y_crop_height; const int uv_width_subsampling = (src->uv_width != src->y_width); const int uv_height_subsampling = (src->uv_height != src->y_height); const int et_uv = et_y >> uv_height_subsampling; @@ -126,63 +122,30 @@ void av1_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src, highbd_copy_and_extend_plane(src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, src->y_crop_width, src->y_crop_height, et_y, el_y, eb_y, er_y); - - highbd_copy_and_extend_plane( - src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride, - src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); - - highbd_copy_and_extend_plane( - src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride, - src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); + if (src->u_buffer) { + highbd_copy_and_extend_plane( + src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride, + src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); + } + if (src->v_buffer) { + highbd_copy_and_extend_plane( + src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride, + src->uv_crop_width, src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); + } return; } copy_and_extend_plane(src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, src->y_crop_width, src->y_crop_height, et_y, el_y, eb_y, er_y); - - copy_and_extend_plane(src->u_buffer, src->uv_stride, dst->u_buffer, - dst->uv_stride, src->uv_crop_width, src->uv_crop_height, - et_uv, el_uv, eb_uv, er_uv); - - copy_and_extend_plane(src->v_buffer, src->uv_stride, dst->v_buffer, - dst->uv_stride, src->uv_crop_width, src->uv_crop_height, - et_uv, el_uv, eb_uv, er_uv); -} - -void av1_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *dst, int srcy, - int srcx, int srch, int srcw) { - // If the side is not touching the bounder then don't extend. - const int et_y = srcy ? 0 : dst->border; - const int el_y = srcx ? 0 : dst->border; - const int eb_y = srcy + srch != src->y_height - ? 0 - : dst->border + dst->y_height - src->y_height; - const int er_y = srcx + srcw != src->y_width - ? 0 - : dst->border + dst->y_width - src->y_width; - const int src_y_offset = srcy * src->y_stride + srcx; - const int dst_y_offset = srcy * dst->y_stride + srcx; - - const int et_uv = ROUND_POWER_OF_TWO(et_y, 1); - const int el_uv = ROUND_POWER_OF_TWO(el_y, 1); - const int eb_uv = ROUND_POWER_OF_TWO(eb_y, 1); - const int er_uv = ROUND_POWER_OF_TWO(er_y, 1); - const int src_uv_offset = ((srcy * src->uv_stride) >> 1) + (srcx >> 1); - const int dst_uv_offset = ((srcy * dst->uv_stride) >> 1) + (srcx >> 1); - const int srch_uv = ROUND_POWER_OF_TWO(srch, 1); - const int srcw_uv = ROUND_POWER_OF_TWO(srcw, 1); - - copy_and_extend_plane(src->y_buffer + src_y_offset, src->y_stride, - dst->y_buffer + dst_y_offset, dst->y_stride, srcw, srch, - et_y, el_y, eb_y, er_y); - - copy_and_extend_plane(src->u_buffer + src_uv_offset, src->uv_stride, - dst->u_buffer + dst_uv_offset, dst->uv_stride, srcw_uv, - srch_uv, et_uv, el_uv, eb_uv, er_uv); - - copy_and_extend_plane(src->v_buffer + src_uv_offset, src->uv_stride, - dst->v_buffer + dst_uv_offset, dst->uv_stride, srcw_uv, - srch_uv, et_uv, el_uv, eb_uv, er_uv); + if (src->u_buffer) { + copy_and_extend_plane(src->u_buffer, src->uv_stride, dst->u_buffer, + dst->uv_stride, src->uv_crop_width, + src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); + } + if (src->v_buffer) { + copy_and_extend_plane(src->v_buffer, src->uv_stride, dst->v_buffer, + dst->uv_stride, src->uv_crop_width, + src->uv_crop_height, et_uv, el_uv, eb_uv, er_uv); + } } diff --git a/media/libaom/src/av1/encoder/extend.h b/media/libaom/src/av1/encoder/extend.h index e0432cc970..b8cc5b9d28 100644 --- a/media/libaom/src/av1/encoder/extend.h +++ b/media/libaom/src/av1/encoder/extend.h @@ -22,9 +22,6 @@ extern "C" { void av1_copy_and_extend_frame(const YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst); -void av1_copy_and_extend_frame_with_rect(const YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *dst, int srcy, - int srcx, int srch, int srcw); #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/firstpass.c b/media/libaom/src/av1/encoder/firstpass.c index aeab7da648..0955510ca9 100644 --- a/media/libaom/src/av1/encoder/firstpass.c +++ b/media/libaom/src/av1/encoder/firstpass.c @@ -17,13 +17,13 @@ #include "config/aom_scale_rtcd.h" #include "aom_dsp/aom_dsp_common.h" +#include "aom_dsp/variance.h" #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" #include "aom_ports/system_state.h" #include "aom_scale/aom_scale.h" #include "aom_scale/yv12config.h" -#include "aom_dsp/variance.h" #include "av1/common/entropymv.h" #include "av1/common/quant_common.h" #include "av1/common/reconinter.h" // av1_setup_dst_planes() @@ -59,7 +59,7 @@ static AOM_INLINE void output_stats(FIRSTPASS_STATS *stats, pkt.kind = AOM_CODEC_STATS_PKT; pkt.data.twopass_stats.buf = stats; pkt.data.twopass_stats.sz = sizeof(FIRSTPASS_STATS); - aom_codec_pkt_list_add(pktlist, &pkt); + if (pktlist != NULL) aom_codec_pkt_list_add(pktlist, &pkt); // TEMP debug code #if OUTPUT_FPF @@ -136,12 +136,9 @@ static AOM_INLINE void accumulate_stats(FIRSTPASS_STATS *section, section->duration += frame->duration; } -void av1_init_first_pass(AV1_COMP *cpi) { - av1_twopass_zero_stats(&cpi->twopass.total_stats); -} - void av1_end_first_pass(AV1_COMP *cpi) { - output_stats(&cpi->twopass.total_stats, cpi->output_pkt_list); + if (cpi->twopass.stats_buf_ctx->total_stats) + output_stats(cpi->twopass.stats_buf_ctx->total_stats, cpi->output_pkt_list); } static aom_variance_fn_t get_block_variance_fn(BLOCK_SIZE bsize) { @@ -215,78 +212,51 @@ static int get_search_range(const AV1_COMP *cpi) { } static AOM_INLINE void first_pass_motion_search(AV1_COMP *cpi, MACROBLOCK *x, - const MV *ref_mv, MV *best_mv, + const MV *ref_mv, + FULLPEL_MV *best_mv, int *best_motion_err) { MACROBLOCKD *const xd = &x->e_mbd; - MV tmp_mv = kZeroMv; - MV ref_mv_full = { ref_mv->row >> 3, ref_mv->col >> 3 }; - int num00, tmp_err, n; + FULLPEL_MV start_mv = get_fullmv_from_mv(ref_mv); + int tmp_err; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; aom_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[bsize]; const int new_mv_mode_penalty = NEW_MV_MODE_PENALTY; - - int step_param = 3; - int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param; const int sr = get_search_range(cpi); - step_param += sr; - further_steps -= sr; + const int step_param = 3 + sr; - // Override the default variance function to use MSE. - v_fn_ptr.vf = get_block_variance_fn(bsize); -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - v_fn_ptr.vf = highbd_get_block_variance_fn(bsize, xd->bd); + const search_site_config *first_pass_search_sites = + &cpi->mv_search_params.ss_cfg[SS_CFG_FPF]; + FULLPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_fullpel_ms_params(&ms_params, cpi, x, bsize, ref_mv, + first_pass_search_sites); + ms_params.search_method = NSTEP; + + FULLPEL_MV this_best_mv; + tmp_err = av1_full_pixel_search(start_mv, &ms_params, step_param, NULL, + &this_best_mv, NULL); + + if (tmp_err < INT_MAX) { + tmp_err = av1_get_mvpred_sse(x, &this_best_mv, ref_mv, &v_fn_ptr) + + new_mv_mode_penalty; } -#endif - // Center the initial step/diamond search on best mv. - 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); - if (tmp_err < INT_MAX - new_mv_mode_penalty) tmp_err += new_mv_mode_penalty; if (tmp_err < *best_motion_err) { *best_motion_err = tmp_err; - *best_mv = tmp_mv; - } - - // Carry out further step/diamond searches as necessary. - n = num00; - num00 = 0; - - while (n < further_steps) { - ++n; - - if (num00) { - --num00; - } else { - 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) - tmp_err += new_mv_mode_penalty; - - if (tmp_err < *best_motion_err) { - *best_motion_err = tmp_err; - *best_mv = tmp_mv; - } - } + *best_mv = this_best_mv; } } -static BLOCK_SIZE get_bsize(const AV1_COMMON *cm, int mb_row, int mb_col) { +static BLOCK_SIZE get_bsize(const CommonModeInfoParams *const mi_params, + int mb_row, int mb_col) { if (mi_size_wide[BLOCK_16X16] * mb_col + mi_size_wide[BLOCK_8X8] < - cm->mi_cols) { + mi_params->mi_cols) { return mi_size_wide[BLOCK_16X16] * mb_row + mi_size_wide[BLOCK_8X8] < - cm->mi_rows + mi_params->mi_rows ? BLOCK_16X16 : BLOCK_16X8; } else { return mi_size_wide[BLOCK_16X16] * mb_row + mi_size_wide[BLOCK_8X8] < - cm->mi_rows + mi_params->mi_rows ? BLOCK_8X16 : BLOCK_8X8; } @@ -319,489 +289,716 @@ static double raw_motion_error_stdev(int *raw_motion_err_list, return raw_err_stdev; } +// This structure contains several key parameters to be accumulate for this +// frame. +typedef struct { + // Intra prediction error. + int64_t intra_error; + // Average wavelet energy computed using Discrete Wavelet Transform (DWT). + int64_t frame_avg_wavelet_energy; + // Best of intra pred error and inter pred error using last frame as ref. + int64_t coded_error; + // Best of intra pred error and inter pred error using golden frame as ref. + int64_t sr_coded_error; + // Best of intra pred error and inter pred error using altref frame as ref. + int64_t tr_coded_error; + // Count of motion vector. + int mv_count; + // Count of blocks that pick inter prediction (inter pred error is smaller + // than intra pred error). + int inter_count; + // Count of blocks that pick second ref (golden frame). + int second_ref_count; + // Count of blocks that pick third ref (altref frame). + int third_ref_count; + // Count of blocks where the inter and intra are very close and very low. + double neutral_count; + // Count of blocks where intra error is very small. + int intra_skip_count; + // Start row. + int image_data_start_row; + // Count of unique non-zero motion vectors. + int new_mv_count; + // Sum of inward motion vectors. + int sum_in_vectors; + // Sum of motion vector row. + int sum_mvr; + // Sum of motion vector column. + int sum_mvc; + // Sum of absolute value of motion vector row. + int sum_mvr_abs; + // Sum of absolute value of motion vector column. + int sum_mvc_abs; + // Sum of the square of motion vector row. + int64_t sum_mvrs; + // Sum of the square of motion vector column. + int64_t sum_mvcs; + // A factor calculated using intra pred error. + double intra_factor; + // A factor that measures brightness. + double brightness_factor; +} FRAME_STATS; + #define UL_INTRA_THRESH 50 #define INVALID_ROW -1 +// Computes and returns the intra pred error of a block. +// intra pred error: sum of squared error of the intra predicted residual. +// Inputs: +// cpi: the encoder setting. Only a few params in it will be used. +// this_frame: the current frame buffer. +// tile: tile information (not used in first pass, already init to zero) +// mb_row: row index in the unit of first pass block size. +// mb_col: column index in the unit of first pass block size. +// y_offset: the offset of y frame buffer, indicating the starting point of +// the current block. +// uv_offset: the offset of u and v frame buffer, indicating the starting +// point of the current block. +// fp_block_size: first pass block size. +// qindex: quantization step size to encode the frame. +// stats: frame encoding stats. +// Modifies: +// stats->intra_skip_count +// stats->image_data_start_row +// stats->intra_factor +// stats->brightness_factor +// stats->intra_error +// stats->frame_avg_wavelet_energy +// Returns: +// this_intra_error. +static int firstpass_intra_prediction( + AV1_COMP *cpi, YV12_BUFFER_CONFIG *const this_frame, + const TileInfo *const tile, const int mb_row, const int mb_col, + const int y_offset, const int uv_offset, const BLOCK_SIZE fp_block_size, + const int qindex, FRAME_STATS *const stats) { + const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const SequenceHeader *const seq_params = &cm->seq_params; + MACROBLOCK *const x = &cpi->td.mb; + MACROBLOCKD *const xd = &x->e_mbd; + const int mb_scale = mi_size_wide[fp_block_size]; + const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); + const int num_planes = av1_num_planes(cm); + const BLOCK_SIZE bsize = get_bsize(mi_params, mb_row, mb_col); + + aom_clear_system_state(); + set_mi_offsets(mi_params, xd, mb_row * mb_scale, mb_col * mb_scale); + xd->plane[0].dst.buf = this_frame->y_buffer + y_offset; + xd->plane[1].dst.buf = this_frame->u_buffer + uv_offset; + xd->plane[2].dst.buf = this_frame->v_buffer + uv_offset; + xd->left_available = (mb_col != 0); + xd->mi[0]->sb_type = bsize; + xd->mi[0]->ref_frame[0] = INTRA_FRAME; + set_mi_row_col(xd, tile, mb_row * mb_scale, mi_size_high[bsize], + mb_col * mb_scale, mi_size_wide[bsize], mi_params->mi_rows, + mi_params->mi_cols); + set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize], num_planes); + xd->mi[0]->segment_id = 0; + xd->lossless[xd->mi[0]->segment_id] = (qindex == 0); + xd->mi[0]->mode = DC_PRED; + xd->mi[0]->tx_size = + use_dc_pred ? (bsize >= fp_block_size ? TX_16X16 : TX_8X8) : TX_4X4; + + av1_encode_intra_block_plane(cpi, x, bsize, 0, DRY_RUN_NORMAL, 0); + int this_intra_error = aom_get_mb_ss(x->plane[0].src_diff); + + if (this_intra_error < UL_INTRA_THRESH) { + ++stats->intra_skip_count; + } else if ((mb_col > 0) && (stats->image_data_start_row == INVALID_ROW)) { + stats->image_data_start_row = mb_row; + } + + if (seq_params->use_highbitdepth) { + switch (seq_params->bit_depth) { + case AOM_BITS_8: break; + case AOM_BITS_10: this_intra_error >>= 4; break; + case AOM_BITS_12: this_intra_error >>= 8; break; + default: + assert(0 && + "seq_params->bit_depth should be AOM_BITS_8, " + "AOM_BITS_10 or AOM_BITS_12"); + return -1; + } + } + + aom_clear_system_state(); + double log_intra = log(this_intra_error + 1.0); + if (log_intra < 10.0) { + stats->intra_factor += 1.0 + ((10.0 - log_intra) * 0.05); + } else { + stats->intra_factor += 1.0; + } + + int level_sample; + if (seq_params->use_highbitdepth) { + level_sample = CONVERT_TO_SHORTPTR(x->plane[0].src.buf)[0]; + } else { + level_sample = x->plane[0].src.buf[0]; + } + if ((level_sample < DARK_THRESH) && (log_intra < 9.0)) { + stats->brightness_factor += 1.0 + (0.01 * (DARK_THRESH - level_sample)); + } else { + stats->brightness_factor += 1.0; + } + + // Intrapenalty below deals with situations where the intra and inter + // error scores are very low (e.g. a plain black frame). + // We do not have special cases in first pass for 0,0 and nearest etc so + // all inter modes carry an overhead cost estimate for the mv. + // When the error score is very low this causes us to pick all or lots of + // INTRA modes and throw lots of key frames. + // This penalty adds a cost matching that of a 0,0 mv to the intra case. + this_intra_error += INTRA_MODE_PENALTY; + + // Accumulate the intra error. + stats->intra_error += (int64_t)this_intra_error; + + const int hbd = is_cur_buf_hbd(xd); + const int stride = x->plane[0].src.stride; + uint8_t *buf = x->plane[0].src.buf; + for (int r8 = 0; r8 < 2; ++r8) { + for (int c8 = 0; c8 < 2; ++c8) { + stats->frame_avg_wavelet_energy += av1_haar_ac_sad_8x8_uint8_input( + buf + c8 * 8 + r8 * 8 * stride, stride, hbd); + } + } + + return this_intra_error; +} + +// Returns the sum of square error between source and reference blocks. +static int get_prediction_error_bitdepth(const int is_high_bitdepth, + const int bitdepth, + const BLOCK_SIZE block_size, + const struct buf_2d *src, + const struct buf_2d *ref) { + (void)is_high_bitdepth; + (void)bitdepth; +#if CONFIG_AV1_HIGHBITDEPTH + if (is_high_bitdepth) { + return highbd_get_prediction_error(block_size, src, ref, bitdepth); + } +#endif // CONFIG_AV1_HIGHBITDEPTH + return get_prediction_error(block_size, src, ref); +} + +// Accumulates motion vector stats. +// Modifies member variables of "stats". +static void accumulate_mv_stats(const MV best_mv, const FULLPEL_MV mv, + const int mb_row, const int mb_col, + const int mb_rows, const int mb_cols, + MV *last_mv, FRAME_STATS *stats) { + if (is_zero_mv(&best_mv)) return; + + ++stats->mv_count; + // Non-zero vector, was it different from the last non zero vector? + if (!is_equal_mv(&best_mv, last_mv)) ++stats->new_mv_count; + *last_mv = best_mv; + + // Does the row vector point inwards or outwards? + if (mb_row < mb_rows / 2) { + if (mv.row > 0) { + --stats->sum_in_vectors; + } else if (mv.row < 0) { + ++stats->sum_in_vectors; + } + } else if (mb_row > mb_rows / 2) { + if (mv.row > 0) { + ++stats->sum_in_vectors; + } else if (mv.row < 0) { + --stats->sum_in_vectors; + } + } + + // Does the col vector point inwards or outwards? + if (mb_col < mb_cols / 2) { + if (mv.col > 0) { + --stats->sum_in_vectors; + } else if (mv.col < 0) { + ++stats->sum_in_vectors; + } + } else if (mb_col > mb_cols / 2) { + if (mv.col > 0) { + ++stats->sum_in_vectors; + } else if (mv.col < 0) { + --stats->sum_in_vectors; + } + } +} + +#define LOW_MOTION_ERROR_THRESH 25 +// Computes and returns the inter prediction error from the last frame. +// Computes inter prediction errors from the golden and alt ref frams and +// Updates stats accordingly. +// Inputs: +// cpi: the encoder setting. Only a few params in it will be used. +// last_frame: the frame buffer of the last frame. +// golden_frame: the frame buffer of the golden frame. +// alt_ref_frame: the frame buffer of the alt ref frame. +// mb_row: row index in the unit of first pass block size. +// mb_col: column index in the unit of first pass block size. +// recon_yoffset: the y offset of the reconstructed frame buffer, +// indicating the starting point of the current block. +// recont_uvoffset: the u/v offset of the reconstructed frame buffer, +// indicating the starting point of the current block. +// src_yoffset: the y offset of the source frame buffer. +// alt_ref_frame_offset: the y offset of the alt ref frame buffer. +// fp_block_size: first pass block size. +// this_intra_error: the intra prediction error of this block. +// raw_motion_err_counts: the count of raw motion vectors. +// raw_motion_err_list: the array that records the raw motion error. +// best_ref_mv: best reference mv found so far. +// last_mv: last mv. +// stats: frame encoding stats. +// Modifies: +// raw_motion_err_list +// best_ref_mv +// last_mv +// stats: many member params in it. +// Returns: +// this_inter_error +static int firstpass_inter_prediction( + AV1_COMP *cpi, const YV12_BUFFER_CONFIG *const last_frame, + const YV12_BUFFER_CONFIG *const golden_frame, + const YV12_BUFFER_CONFIG *const alt_ref_frame, const int mb_row, + const int mb_col, const int recon_yoffset, const int recon_uvoffset, + const int src_yoffset, const int alt_ref_frame_yoffset, + const BLOCK_SIZE fp_block_size, const int this_intra_error, + const int raw_motion_err_counts, int *raw_motion_err_list, MV *best_ref_mv, + MV *last_mv, FRAME_STATS *stats) { + int this_inter_error = this_intra_error; + AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + CurrentFrame *const current_frame = &cm->current_frame; + MACROBLOCK *const x = &cpi->td.mb; + MACROBLOCKD *const xd = &x->e_mbd; + const int is_high_bitdepth = is_cur_buf_hbd(xd); + const int bitdepth = xd->bd; + const int mb_scale = mi_size_wide[fp_block_size]; + const BLOCK_SIZE bsize = get_bsize(mi_params, mb_row, mb_col); + const int fp_block_size_height = block_size_wide[fp_block_size]; + // Assume 0,0 motion with no mv overhead. + FULLPEL_MV mv = kZeroFullMv; + FULLPEL_MV tmp_mv = kZeroFullMv; + xd->plane[0].pre[0].buf = last_frame->y_buffer + recon_yoffset; + // Set up limit values for motion vectors to prevent them extending + // outside the UMV borders. + av1_set_mv_col_limits(mi_params, &x->mv_limits, (mb_col << 2), + (fp_block_size_height >> MI_SIZE_LOG2), + cpi->oxcf.border_in_pixels); + + int motion_error = + get_prediction_error_bitdepth(is_high_bitdepth, bitdepth, bsize, + &x->plane[0].src, &xd->plane[0].pre[0]); + + // Compute the motion error of the 0,0 motion using the last source + // frame as the reference. Skip the further motion search on + // reconstructed frame if this error is small. + struct buf_2d unscaled_last_source_buf_2d; + unscaled_last_source_buf_2d.buf = + cpi->unscaled_last_source->y_buffer + src_yoffset; + unscaled_last_source_buf_2d.stride = cpi->unscaled_last_source->y_stride; + const int raw_motion_error = get_prediction_error_bitdepth( + is_high_bitdepth, bitdepth, bsize, &x->plane[0].src, + &unscaled_last_source_buf_2d); + raw_motion_err_list[raw_motion_err_counts] = raw_motion_error; + + // TODO(pengchong): Replace the hard-coded threshold + if (raw_motion_error > LOW_MOTION_ERROR_THRESH) { + // Test last reference frame using the previous best mv as the + // starting point (best reference) for the search. + first_pass_motion_search(cpi, x, best_ref_mv, &mv, &motion_error); + + // If the current best reference mv is not centered on 0,0 then do a + // 0,0 based search as well. + if (!is_zero_mv(best_ref_mv)) { + int tmp_err = INT_MAX; + first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &tmp_err); + + if (tmp_err < motion_error) { + motion_error = tmp_err; + mv = tmp_mv; + } + } + + // Motion search in 2nd reference frame. + int gf_motion_error = motion_error; + if ((current_frame->frame_number > 1) && golden_frame != NULL) { + // Assume 0,0 motion with no mv overhead. + xd->plane[0].pre[0].buf = golden_frame->y_buffer + recon_yoffset; + xd->plane[0].pre[0].stride = golden_frame->y_stride; + gf_motion_error = + get_prediction_error_bitdepth(is_high_bitdepth, bitdepth, bsize, + &x->plane[0].src, &xd->plane[0].pre[0]); + first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &gf_motion_error); + } + if (gf_motion_error < motion_error && gf_motion_error < this_intra_error) { + ++stats->second_ref_count; + } + // In accumulating a score for the 2nd reference frame take the + // best of the motion predicted score and the intra coded error + // (just as will be done for) accumulation of "coded_error" for + // the last frame. + if ((current_frame->frame_number > 1) && golden_frame != NULL) { + stats->sr_coded_error += AOMMIN(gf_motion_error, this_intra_error); + } else { + // TODO(chengchen): I believe logically this should also be changed to + // stats->sr_coded_error += AOMMIN(gf_motion_error, this_intra_error). + stats->sr_coded_error += motion_error; + } + + // Motion search in 3rd reference frame. + int alt_motion_error = motion_error; + if (alt_ref_frame != NULL) { + xd->plane[0].pre[0].buf = alt_ref_frame->y_buffer + alt_ref_frame_yoffset; + xd->plane[0].pre[0].stride = alt_ref_frame->y_stride; + alt_motion_error = + get_prediction_error_bitdepth(is_high_bitdepth, bitdepth, bsize, + &x->plane[0].src, &xd->plane[0].pre[0]); + first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &alt_motion_error); + } + if (alt_motion_error < motion_error && alt_motion_error < gf_motion_error && + alt_motion_error < this_intra_error) { + ++stats->third_ref_count; + } + // In accumulating a score for the 3rd reference frame take the + // best of the motion predicted score and the intra coded error + // (just as will be done for) accumulation of "coded_error" for + // the last frame. + if (alt_ref_frame != NULL) { + stats->tr_coded_error += AOMMIN(alt_motion_error, this_intra_error); + } else { + // TODO(chengchen): I believe logically this should also be changed to + // stats->tr_coded_error += AOMMIN(alt_motion_error, this_intra_error). + stats->tr_coded_error += motion_error; + } + + // Reset to last frame as reference buffer. + xd->plane[0].pre[0].buf = last_frame->y_buffer + recon_yoffset; + xd->plane[1].pre[0].buf = last_frame->u_buffer + recon_uvoffset; + xd->plane[2].pre[0].buf = last_frame->v_buffer + recon_uvoffset; + } else { + stats->sr_coded_error += motion_error; + stats->tr_coded_error += motion_error; + } + + // Start by assuming that intra mode is best. + best_ref_mv->row = 0; + best_ref_mv->col = 0; + + if (motion_error <= this_intra_error) { + aom_clear_system_state(); + + // Keep a count of cases where the inter and intra were very close + // and very low. This helps with scene cut detection for example in + // cropped clips with black bars at the sides or top and bottom. + if (((this_intra_error - INTRA_MODE_PENALTY) * 9 <= motion_error * 10) && + (this_intra_error < (2 * INTRA_MODE_PENALTY))) { + stats->neutral_count += 1.0; + // Also track cases where the intra is not much worse than the inter + // and use this in limiting the GF/arf group length. + } else if ((this_intra_error > NCOUNT_INTRA_THRESH) && + (this_intra_error < (NCOUNT_INTRA_FACTOR * motion_error))) { + stats->neutral_count += + (double)motion_error / DOUBLE_DIVIDE_CHECK((double)this_intra_error); + } + + const MV best_mv = get_mv_from_fullmv(&mv); + this_inter_error = motion_error; + xd->mi[0]->mode = NEWMV; + xd->mi[0]->mv[0].as_mv = best_mv; + xd->mi[0]->tx_size = TX_4X4; + xd->mi[0]->ref_frame[0] = LAST_FRAME; + xd->mi[0]->ref_frame[1] = NONE_FRAME; + av1_enc_build_inter_predictor(cm, xd, mb_row * mb_scale, mb_col * mb_scale, + NULL, bsize, AOM_PLANE_Y, AOM_PLANE_Y); + av1_encode_sby_pass1(cpi, x, bsize); + stats->sum_mvr += best_mv.row; + stats->sum_mvr_abs += abs(best_mv.row); + stats->sum_mvc += best_mv.col; + stats->sum_mvc_abs += abs(best_mv.col); + stats->sum_mvrs += best_mv.row * best_mv.row; + stats->sum_mvcs += best_mv.col * best_mv.col; + ++stats->inter_count; + + *best_ref_mv = best_mv; + accumulate_mv_stats(best_mv, mv, mb_row, mb_col, mi_params->mb_rows, + mi_params->mb_cols, last_mv, stats); + } + + return this_inter_error; +} + +// Updates the first pass stats of this frame. +// Input: +// cpi: the encoder setting. Only a few params in it will be used. +// stats: stats accumulated for this frame. +// raw_err_stdev: the statndard deviation for the motion error of all the +// inter blocks of the (0,0) motion using the last source +// frame as the reference. +// frame_number: current frame number. +// ts_duration: Duration of the frame / collection of frames. +// Updates: +// twopass->total_stats: the accumulated stats. +// twopass->stats_buf_ctx->stats_in_end: the pointer to the current stats, +// update its value and its position +// in the buffer. +static void update_firstpass_stats(AV1_COMP *cpi, + const FRAME_STATS *const stats, + const double raw_err_stdev, + const int frame_number, + const int64_t ts_duration) { + TWO_PASS *twopass = &cpi->twopass; + AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + FIRSTPASS_STATS *this_frame_stats = twopass->stats_buf_ctx->stats_in_end; + FIRSTPASS_STATS fps; + // The minimum error here insures some bit allocation to frames even + // in static regions. The allocation per MB declines for larger formats + // where the typical "real" energy per MB also falls. + // Initial estimate here uses sqrt(mbs) to define the min_err, where the + // number of mbs is proportional to the image area. + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs + : mi_params->MBs; + const double min_err = 200 * sqrt(num_mbs); + + fps.weight = stats->intra_factor * stats->brightness_factor; + fps.frame = frame_number; + fps.coded_error = (double)(stats->coded_error >> 8) + min_err; + fps.sr_coded_error = (double)(stats->sr_coded_error >> 8) + min_err; + fps.tr_coded_error = (double)(stats->tr_coded_error >> 8) + min_err; + fps.intra_error = (double)(stats->intra_error >> 8) + min_err; + fps.frame_avg_wavelet_energy = (double)stats->frame_avg_wavelet_energy; + fps.count = 1.0; + fps.pcnt_inter = (double)stats->inter_count / num_mbs; + fps.pcnt_second_ref = (double)stats->second_ref_count / num_mbs; + fps.pcnt_third_ref = (double)stats->third_ref_count / num_mbs; + fps.pcnt_neutral = (double)stats->neutral_count / num_mbs; + fps.intra_skip_pct = (double)stats->intra_skip_count / num_mbs; + fps.inactive_zone_rows = (double)stats->image_data_start_row; + fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix + fps.raw_error_stdev = raw_err_stdev; + + if (stats->mv_count > 0) { + fps.MVr = (double)stats->sum_mvr / stats->mv_count; + fps.mvr_abs = (double)stats->sum_mvr_abs / stats->mv_count; + fps.MVc = (double)stats->sum_mvc / stats->mv_count; + fps.mvc_abs = (double)stats->sum_mvc_abs / stats->mv_count; + fps.MVrv = ((double)stats->sum_mvrs - + ((double)stats->sum_mvr * stats->sum_mvr / stats->mv_count)) / + stats->mv_count; + fps.MVcv = ((double)stats->sum_mvcs - + ((double)stats->sum_mvc * stats->sum_mvc / stats->mv_count)) / + stats->mv_count; + fps.mv_in_out_count = (double)stats->sum_in_vectors / (stats->mv_count * 2); + fps.new_mv_count = stats->new_mv_count; + fps.pcnt_motion = (double)stats->mv_count / num_mbs; + } else { + fps.MVr = 0.0; + fps.mvr_abs = 0.0; + fps.MVc = 0.0; + fps.mvc_abs = 0.0; + fps.MVrv = 0.0; + fps.MVcv = 0.0; + fps.mv_in_out_count = 0.0; + fps.new_mv_count = 0.0; + fps.pcnt_motion = 0.0; + } + + // TODO(paulwilkins): Handle the case when duration is set to 0, or + // something less than the full time between subsequent values of + // cpi->source_time_stamp. + fps.duration = (double)ts_duration; + + // We will store the stats inside the persistent twopass struct (and NOT the + // local variable 'fps'), and then cpi->output_pkt_list will point to it. + *this_frame_stats = fps; + output_stats(this_frame_stats, cpi->output_pkt_list); + if (cpi->twopass.stats_buf_ctx->total_stats != NULL) { + accumulate_stats(cpi->twopass.stats_buf_ctx->total_stats, &fps); + } + /*In the case of two pass, first pass uses it as a circular buffer, + * when LAP is enabled it is used as a linear buffer*/ + twopass->stats_buf_ctx->stats_in_end++; + if ((cpi->oxcf.pass == 1) && (twopass->stats_buf_ctx->stats_in_end >= + twopass->stats_buf_ctx->stats_in_buf_end)) { + twopass->stats_buf_ctx->stats_in_end = + twopass->stats_buf_ctx->stats_in_start; + } +} + +static void print_reconstruction_frame( + const YV12_BUFFER_CONFIG *const last_frame, int frame_number, + int do_print) { + if (!do_print) return; + + char filename[512]; + FILE *recon_file; + snprintf(filename, sizeof(filename), "enc%04d.yuv", frame_number); + + if (frame_number == 0) { + recon_file = fopen(filename, "wb"); + } else { + recon_file = fopen(filename, "ab"); + } + + fwrite(last_frame->buffer_alloc, last_frame->frame_size, 1, recon_file); + fclose(recon_file); +} + +#define FIRST_PASS_ALT_REF_DISTANCE 16 void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { - int mb_row, mb_col; MACROBLOCK *const x = &cpi->td.mb; AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; CurrentFrame *const current_frame = &cm->current_frame; const SequenceHeader *const seq_params = &cm->seq_params; const int num_planes = av1_num_planes(cm); MACROBLOCKD *const xd = &x->e_mbd; - TileInfo tile; - struct macroblock_plane *const p = x->plane; - struct macroblockd_plane *const pd = xd->plane; - const PICK_MODE_CONTEXT *ctx = - &cpi->td.pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2]->none; - int i; - - int recon_yoffset, src_yoffset, recon_uvoffset; - int64_t intra_error = 0; - int64_t frame_avg_wavelet_energy = 0; - int64_t coded_error = 0; - int64_t sr_coded_error = 0; - int64_t tr_coded_error = 0; - - int sum_mvr = 0, sum_mvc = 0; - int sum_mvr_abs = 0, sum_mvc_abs = 0; - int64_t sum_mvrs = 0, sum_mvcs = 0; - int mvcount = 0; - int intercount = 0; - int second_ref_count = 0; - int third_ref_count = 0; - const int intrapenalty = INTRA_MODE_PENALTY; - double neutral_count; - int intra_skip_count = 0; - int image_data_start_row = INVALID_ROW; - int new_mv_count = 0; - int sum_in_vectors = 0; - MV lastmv = kZeroMv; - TWO_PASS *twopass = &cpi->twopass; - 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); - const YV12_BUFFER_CONFIG *gld_yv12 = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME); - const YV12_BUFFER_CONFIG *alt_yv12 = NULL; - const int alt_offset = 16 - (current_frame->frame_number % 16); - if (alt_offset < 16) { - const struct lookahead_entry *const alt_buf = - av1_lookahead_peek(cpi->lookahead, alt_offset); - if (alt_buf != NULL) { - alt_yv12 = &alt_buf->img; - } - } - YV12_BUFFER_CONFIG *const new_yv12 = &cm->cur_frame->buf; - double intra_factor; - double brightness_factor; + const PICK_MODE_CONTEXT *ctx = &cpi->td.pc_root->none; + MV last_mv = kZeroMv; const int qindex = find_fp_qindex(seq_params->bit_depth); - const int mb_scale = mi_size_wide[BLOCK_16X16]; - + // Detect if the key frame is screen content type. + if (frame_is_intra_only(cm)) { + FeatureFlags *const features = &cm->features; + av1_set_screen_content_options(cpi, features); + cpi->is_screen_content_type = features->allow_screen_content_tools; + } + // First pass coding proceeds in raster scan order with unit size of 16x16. + const BLOCK_SIZE fp_block_size = BLOCK_16X16; + const int fp_block_size_width = block_size_high[fp_block_size]; + const int fp_block_size_height = block_size_wide[fp_block_size]; int *raw_motion_err_list; int raw_motion_err_counts = 0; - CHECK_MEM_ERROR( - cm, raw_motion_err_list, - aom_calloc(cm->mb_rows * cm->mb_cols, sizeof(*raw_motion_err_list))); + CHECK_MEM_ERROR(cm, raw_motion_err_list, + aom_calloc(mi_params->mb_rows * mi_params->mb_cols, + sizeof(*raw_motion_err_list))); + // Tiling is ignored in the first pass. + TileInfo tile; + av1_tile_init(&tile, cm, 0, 0); + FRAME_STATS stats = { 0 }; + stats.image_data_start_row = INVALID_ROW; + + const YV12_BUFFER_CONFIG *const last_frame = + get_ref_frame_yv12_buf(cm, LAST_FRAME); + const YV12_BUFFER_CONFIG *golden_frame = + get_ref_frame_yv12_buf(cm, GOLDEN_FRAME); + const YV12_BUFFER_CONFIG *alt_ref_frame = NULL; + const int alt_ref_offset = + FIRST_PASS_ALT_REF_DISTANCE - + (current_frame->frame_number % FIRST_PASS_ALT_REF_DISTANCE); + if (alt_ref_offset < FIRST_PASS_ALT_REF_DISTANCE) { + const struct lookahead_entry *const alt_ref_frame_buffer = + av1_lookahead_peek(cpi->lookahead, alt_ref_offset, + cpi->compressor_stage); + if (alt_ref_frame_buffer != NULL) { + alt_ref_frame = &alt_ref_frame_buffer->img; + } + } + YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf; // First pass code requires valid last and new frame buffers. - assert(new_yv12 != NULL); - assert(frame_is_intra_only(cm) || (lst_yv12 != NULL)); + assert(this_frame != NULL); + assert(frame_is_intra_only(cm) || (last_frame != NULL)); av1_setup_frame_size(cpi); aom_clear_system_state(); - xd->mi = cm->mi_grid_base; - xd->mi[0] = cm->mi; - x->e_mbd.mi[0]->sb_type = BLOCK_16X16; - - intra_factor = 0.0; - brightness_factor = 0.0; - neutral_count = 0.0; + set_mi_offsets(mi_params, xd, 0, 0); + xd->mi[0]->sb_type = fp_block_size; // Do not use periodic key frames. cpi->rc.frames_to_key = INT_MAX; - av1_set_quantizer(cm, qindex); + av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, qindex); - av1_setup_block_planes(&x->e_mbd, seq_params->subsampling_x, + av1_setup_block_planes(xd, seq_params->subsampling_x, seq_params->subsampling_y, num_planes); - av1_setup_src_planes(x, cpi->source, 0, 0, num_planes, - x->e_mbd.mi[0]->sb_type); - av1_setup_dst_planes(xd->plane, seq_params->sb_size, new_yv12, 0, 0, 0, + av1_setup_src_planes(x, cpi->source, 0, 0, num_planes, fp_block_size); + av1_setup_dst_planes(xd->plane, seq_params->sb_size, this_frame, 0, 0, 0, num_planes); if (!frame_is_intra_only(cm)) { - av1_setup_pre_planes(xd, 0, lst_yv12, 0, 0, NULL, num_planes); + av1_setup_pre_planes(xd, 0, last_frame, 0, 0, NULL, num_planes); } - xd->mi = cm->mi_grid_base; - xd->mi[0] = cm->mi; + set_mi_offsets(mi_params, xd, 0, 0); // Don't store luma on the fist pass since chroma is not computed xd->cfl.store_y = 0; av1_frame_init_quantizer(cpi); - for (i = 0; i < num_planes; ++i) { - p[i].coeff = ctx->coeff[i]; - p[i].qcoeff = ctx->qcoeff[i]; - pd[i].dqcoeff = ctx->dqcoeff[i]; - p[i].eobs = ctx->eobs[i]; - p[i].txb_entropy_ctx = ctx->txb_entropy_ctx[i]; + for (int i = 0; i < num_planes; ++i) { + x->plane[i].coeff = ctx->coeff[i]; + x->plane[i].qcoeff = ctx->qcoeff[i]; + x->plane[i].eobs = ctx->eobs[i]; + x->plane[i].txb_entropy_ctx = ctx->txb_entropy_ctx[i]; + xd->plane[i].dqcoeff = ctx->dqcoeff[i]; } av1_init_mv_probs(cm); av1_initialize_rd_consts(cpi); - // 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); + const int src_y_stride = cpi->source->y_stride; + const int recon_y_stride = this_frame->y_stride; + const int recon_uv_stride = this_frame->uv_stride; + const int uv_mb_height = + fp_block_size_height >> (this_frame->y_height > this_frame->uv_height); - for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) { + for (int mb_row = 0; mb_row < mi_params->mb_rows; ++mb_row) { MV best_ref_mv = kZeroMv; // 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); - int alt_yv12_yoffset = - (alt_yv12 != NULL) ? mb_row * alt_yv12->y_stride * 16 : -1; + int recon_yoffset = (mb_row * recon_y_stride * fp_block_size_height); + int src_yoffset = (mb_row * src_y_stride * fp_block_size_height); + int recon_uvoffset = (mb_row * recon_uv_stride * uv_mb_height); + int alt_ref_frame_yoffset = + (alt_ref_frame != NULL) + ? mb_row * alt_ref_frame->y_stride * fp_block_size_height + : -1; // Set up limit values for motion vectors to prevent them extending // outside the UMV borders. - x->mv_limits.row_min = -((mb_row * 16) + BORDER_MV_PIXELS_B16); - x->mv_limits.row_max = - ((cm->mb_rows - 1 - mb_row) * 16) + BORDER_MV_PIXELS_B16; + av1_set_mv_row_limits(mi_params, &x->mv_limits, (mb_row << 2), + (fp_block_size_height >> MI_SIZE_LOG2), + cpi->oxcf.border_in_pixels); - for (mb_col = 0; mb_col < cm->mb_cols; ++mb_col) { - int this_intra_error; - const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row); - const BLOCK_SIZE bsize = get_bsize(cm, mb_row, mb_col); - double log_intra; - int level_sample; + for (int mb_col = 0; mb_col < mi_params->mb_cols; ++mb_col) { + int this_intra_error = firstpass_intra_prediction( + cpi, this_frame, &tile, mb_row, mb_col, recon_yoffset, recon_uvoffset, + fp_block_size, qindex, &stats); - aom_clear_system_state(); - - const int grid_idx = - get_mi_grid_idx(cm, mb_row * mb_scale, mb_col * mb_scale); - const int mi_idx = - get_alloc_mi_idx(cm, mb_row * mb_scale, mb_col * mb_scale); - xd->mi = cm->mi_grid_base + grid_idx; - xd->mi[0] = cm->mi + mi_idx; - xd->tx_type_map = cm->tx_type_map + grid_idx; - xd->tx_type_map_stride = cm->mi_stride; - xd->plane[0].dst.buf = new_yv12->y_buffer + recon_yoffset; - xd->plane[1].dst.buf = new_yv12->u_buffer + recon_uvoffset; - xd->plane[2].dst.buf = new_yv12->v_buffer + recon_uvoffset; - xd->left_available = (mb_col != 0); - xd->mi[0]->sb_type = bsize; - xd->mi[0]->ref_frame[0] = INTRA_FRAME; - set_mi_row_col(xd, &tile, mb_row * mb_scale, mi_size_high[bsize], - mb_col * mb_scale, mi_size_wide[bsize], cm->mi_rows, - cm->mi_cols); - - set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize], num_planes); - - // Do intra 16x16 prediction. - xd->mi[0]->segment_id = 0; - xd->lossless[xd->mi[0]->segment_id] = (qindex == 0); - xd->mi[0]->mode = DC_PRED; - xd->mi[0]->tx_size = - use_dc_pred ? (bsize >= BLOCK_16X16 ? TX_16X16 : TX_8X8) : TX_4X4; - av1_encode_intra_block_plane(cpi, x, bsize, 0, 0, mb_row * 2, mb_col * 2); - this_intra_error = aom_get_mb_ss(x->plane[0].src_diff); - - if (this_intra_error < UL_INTRA_THRESH) { - ++intra_skip_count; - } else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) { - image_data_start_row = mb_row; - } - - if (seq_params->use_highbitdepth) { - switch (seq_params->bit_depth) { - case AOM_BITS_8: break; - case AOM_BITS_10: this_intra_error >>= 4; break; - case AOM_BITS_12: this_intra_error >>= 8; break; - default: - assert(0 && - "seq_params->bit_depth should be AOM_BITS_8, " - "AOM_BITS_10 or AOM_BITS_12"); - return; - } - } - - aom_clear_system_state(); - log_intra = log(this_intra_error + 1.0); - if (log_intra < 10.0) - intra_factor += 1.0 + ((10.0 - log_intra) * 0.05); - else - intra_factor += 1.0; - - if (seq_params->use_highbitdepth) - level_sample = CONVERT_TO_SHORTPTR(x->plane[0].src.buf)[0]; - else - level_sample = x->plane[0].src.buf[0]; - if ((level_sample < DARK_THRESH) && (log_intra < 9.0)) - brightness_factor += 1.0 + (0.01 * (DARK_THRESH - level_sample)); - else - brightness_factor += 1.0; - - // Intrapenalty below deals with situations where the intra and inter - // error scores are very low (e.g. a plain black frame). - // We do not have special cases in first pass for 0,0 and nearest etc so - // all inter modes carry an overhead cost estimate for the mv. - // When the error score is very low this causes us to pick all or lots of - // INTRA modes and throw lots of key frames. - // This penalty adds a cost matching that of a 0,0 mv to the intra case. - this_intra_error += intrapenalty; - - // Accumulate the intra error. - intra_error += (int64_t)this_intra_error; - - const int hbd = is_cur_buf_hbd(xd); - const int stride = x->plane[0].src.stride; - uint8_t *buf = x->plane[0].src.buf; - for (int r8 = 0; r8 < 2; ++r8) { - for (int c8 = 0; c8 < 2; ++c8) { - frame_avg_wavelet_energy += av1_haar_ac_sad_8x8_uint8_input( - buf + c8 * 8 + r8 * 8 * stride, stride, hbd); - } - } - - // 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); - x->mv_limits.col_max = - ((cm->mb_cols - 1 - mb_col) * 16) + BORDER_MV_PIXELS_B16; - - if (!frame_is_intra_only(cm)) { // Do a motion search - int tmp_err, motion_error, raw_motion_error; - // Assume 0,0 motion with no mv overhead. - MV mv = kZeroMv, tmp_mv = kZeroMv; - struct buf_2d unscaled_last_source_buf_2d; - - xd->plane[0].pre[0].buf = lst_yv12->y_buffer + recon_yoffset; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - motion_error = highbd_get_prediction_error( - bsize, &x->plane[0].src, &xd->plane[0].pre[0], xd->bd); - } else { - motion_error = get_prediction_error(bsize, &x->plane[0].src, - &xd->plane[0].pre[0]); - } -#else - motion_error = - get_prediction_error(bsize, &x->plane[0].src, &xd->plane[0].pre[0]); -#endif - - // Compute the motion error of the 0,0 motion using the last source - // 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 + src_yoffset; - unscaled_last_source_buf_2d.stride = - cpi->unscaled_last_source->y_stride; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - raw_motion_error = highbd_get_prediction_error( - bsize, &x->plane[0].src, &unscaled_last_source_buf_2d, xd->bd); - } else { - raw_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &unscaled_last_source_buf_2d); - } -#else - raw_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &unscaled_last_source_buf_2d); -#endif - // TODO(pengchong): Replace the hard-coded threshold - if (raw_motion_error > 25) { - // Test last reference frame using the previous best mv as the - // starting point (best reference) for the search. - first_pass_motion_search(cpi, x, &best_ref_mv, &mv, &motion_error); - - // If the current best reference mv is not centered on 0,0 then do a - // 0,0 based search as well. - if (!is_zero_mv(&best_ref_mv)) { - tmp_err = INT_MAX; - first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &tmp_err); - - if (tmp_err < motion_error) { - motion_error = tmp_err; - mv = tmp_mv; - } - } - - // Motion search in 2nd reference frame. - int gf_motion_error; - if ((current_frame->frame_number > 1) && gld_yv12 != NULL) { - // Assume 0,0 motion with no mv overhead. - xd->plane[0].pre[0].buf = gld_yv12->y_buffer + recon_yoffset; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - gf_motion_error = highbd_get_prediction_error( - bsize, &x->plane[0].src, &xd->plane[0].pre[0], xd->bd); - } else { - gf_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &xd->plane[0].pre[0]); - } -#else - gf_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &xd->plane[0].pre[0]); -#endif - first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, - &gf_motion_error); - - if (gf_motion_error < motion_error && - gf_motion_error < this_intra_error) - ++second_ref_count; - - // Reset to last frame as reference buffer. - xd->plane[0].pre[0].buf = lst_yv12->y_buffer + recon_yoffset; - xd->plane[1].pre[0].buf = lst_yv12->u_buffer + recon_uvoffset; - xd->plane[2].pre[0].buf = lst_yv12->v_buffer + recon_uvoffset; - - // In accumulating a score for the 2nd reference frame take the - // best of the motion predicted score and the intra coded error - // (just as will be done for) accumulation of "coded_error" for - // the last frame. - if (gf_motion_error < this_intra_error) - sr_coded_error += gf_motion_error; - else - sr_coded_error += this_intra_error; - } else { - gf_motion_error = motion_error; - sr_coded_error += motion_error; - } - - // Motion search in 3rd reference frame. - if (alt_yv12 != NULL) { - xd->plane[0].pre[0].buf = alt_yv12->y_buffer + alt_yv12_yoffset; - xd->plane[0].pre[0].stride = alt_yv12->y_stride; - int alt_motion_error; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - alt_motion_error = highbd_get_prediction_error( - bsize, &x->plane[0].src, &xd->plane[0].pre[0], xd->bd); - } else { - alt_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &xd->plane[0].pre[0]); - } -#else - alt_motion_error = get_prediction_error(bsize, &x->plane[0].src, - &xd->plane[0].pre[0]); -#endif - first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, - &alt_motion_error); - - if (alt_motion_error < motion_error && - alt_motion_error < gf_motion_error && - alt_motion_error < this_intra_error) - ++third_ref_count; - - // Reset to last frame as reference buffer. - xd->plane[0].pre[0].buf = lst_yv12->y_buffer + recon_yoffset; - xd->plane[0].pre[0].stride = lst_yv12->y_stride; - - // In accumulating a score for the 3rd reference frame take the - // best of the motion predicted score and the intra coded error - // (just as will be done for) accumulation of "coded_error" for - // the last frame. - tr_coded_error += AOMMIN(alt_motion_error, this_intra_error); - } else { - tr_coded_error += motion_error; - } - } else { - sr_coded_error += motion_error; - tr_coded_error += motion_error; - } - - // Start by assuming that intra mode is best. - best_ref_mv.row = 0; - best_ref_mv.col = 0; - - if (motion_error <= this_intra_error) { - aom_clear_system_state(); - - // Keep a count of cases where the inter and intra were very close - // and very low. This helps with scene cut detection for example in - // cropped clips with black bars at the sides or top and bottom. - if (((this_intra_error - intrapenalty) * 9 <= motion_error * 10) && - (this_intra_error < (2 * intrapenalty))) { - neutral_count += 1.0; - // Also track cases where the intra is not much worse than the inter - // and use this in limiting the GF/arf group length. - } else if ((this_intra_error > NCOUNT_INTRA_THRESH) && - (this_intra_error < - (NCOUNT_INTRA_FACTOR * motion_error))) { - neutral_count += (double)motion_error / - DOUBLE_DIVIDE_CHECK((double)this_intra_error); - } - - mv.row *= 8; - mv.col *= 8; - this_intra_error = motion_error; - xd->mi[0]->mode = NEWMV; - xd->mi[0]->mv[0].as_mv = mv; - xd->mi[0]->tx_size = TX_4X4; - xd->mi[0]->ref_frame[0] = LAST_FRAME; - xd->mi[0]->ref_frame[1] = NONE_FRAME; - av1_enc_build_inter_predictor(cm, xd, mb_row * mb_scale, - mb_col * mb_scale, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - av1_encode_sby_pass1(cm, x, bsize); - sum_mvr += mv.row; - sum_mvr_abs += abs(mv.row); - sum_mvc += mv.col; - sum_mvc_abs += abs(mv.col); - sum_mvrs += mv.row * mv.row; - sum_mvcs += mv.col * mv.col; - ++intercount; - - best_ref_mv = mv; - - if (!is_zero_mv(&mv)) { - ++mvcount; - - // Non-zero vector, was it different from the last non zero vector? - if (!is_equal_mv(&mv, &lastmv)) ++new_mv_count; - lastmv = mv; - - // Does the row vector point inwards or outwards? - if (mb_row < cm->mb_rows / 2) { - if (mv.row > 0) - --sum_in_vectors; - else if (mv.row < 0) - ++sum_in_vectors; - } else if (mb_row > cm->mb_rows / 2) { - if (mv.row > 0) - ++sum_in_vectors; - else if (mv.row < 0) - --sum_in_vectors; - } - - // Does the col vector point inwards or outwards? - if (mb_col < cm->mb_cols / 2) { - if (mv.col > 0) - --sum_in_vectors; - else if (mv.col < 0) - ++sum_in_vectors; - } else if (mb_col > cm->mb_cols / 2) { - if (mv.col > 0) - ++sum_in_vectors; - else if (mv.col < 0) - --sum_in_vectors; - } - } - } - raw_motion_err_list[raw_motion_err_counts++] = raw_motion_error; + if (!frame_is_intra_only(cm)) { + const int this_inter_error = firstpass_inter_prediction( + cpi, last_frame, golden_frame, alt_ref_frame, mb_row, mb_col, + recon_yoffset, recon_uvoffset, src_yoffset, alt_ref_frame_yoffset, + fp_block_size, this_intra_error, raw_motion_err_counts, + raw_motion_err_list, &best_ref_mv, &last_mv, &stats); + stats.coded_error += this_inter_error; + ++raw_motion_err_counts; } else { - sr_coded_error += (int64_t)this_intra_error; - tr_coded_error += (int64_t)this_intra_error; + stats.sr_coded_error += this_intra_error; + stats.tr_coded_error += this_intra_error; + stats.coded_error += this_intra_error; } - coded_error += (int64_t)this_intra_error; // Adjust to the next column of MBs. - x->plane[0].src.buf += 16; + x->plane[0].src.buf += fp_block_size_width; x->plane[1].src.buf += uv_mb_height; x->plane[2].src.buf += uv_mb_height; - recon_yoffset += 16; - src_yoffset += 16; + recon_yoffset += fp_block_size_width; + src_yoffset += fp_block_size_width; recon_uvoffset += uv_mb_height; - alt_yv12_yoffset += 16; + alt_ref_frame_yoffset += fp_block_size_width; } // Adjust to the next row of MBs. - x->plane[0].src.buf += 16 * x->plane[0].src.stride - 16 * cm->mb_cols; - x->plane[1].src.buf += - uv_mb_height * x->plane[1].src.stride - uv_mb_height * cm->mb_cols; - x->plane[2].src.buf += - uv_mb_height * x->plane[1].src.stride - uv_mb_height * cm->mb_cols; - - aom_clear_system_state(); + x->plane[0].src.buf += fp_block_size_height * x->plane[0].src.stride - + fp_block_size_width * mi_params->mb_cols; + x->plane[1].src.buf += uv_mb_height * x->plane[1].src.stride - + uv_mb_height * mi_params->mb_cols; + x->plane[2].src.buf += uv_mb_height * x->plane[1].src.stride - + uv_mb_height * mi_params->mb_cols; } const double raw_err_stdev = raw_motion_error_stdev(raw_motion_err_list, raw_motion_err_counts); @@ -809,88 +1006,25 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { // Clamp the image start to rows/2. This number of rows is discarded top // and bottom as dead data so rows / 2 means the frame is blank. - if ((image_data_start_row > cm->mb_rows / 2) || - (image_data_start_row == INVALID_ROW)) { - image_data_start_row = cm->mb_rows / 2; + if ((stats.image_data_start_row > mi_params->mb_rows / 2) || + (stats.image_data_start_row == INVALID_ROW)) { + stats.image_data_start_row = mi_params->mb_rows / 2; } // Exclude any image dead zone - if (image_data_start_row > 0) { - intra_skip_count = - AOMMAX(0, intra_skip_count - (image_data_start_row * cm->mb_cols * 2)); + if (stats.image_data_start_row > 0) { + stats.intra_skip_count = + AOMMAX(0, stats.intra_skip_count - + (stats.image_data_start_row * mi_params->mb_cols * 2)); } - FIRSTPASS_STATS *this_frame_stats = - &twopass->frame_stats_arr[twopass->frame_stats_next_idx]; - { - FIRSTPASS_STATS fps; - // The minimum error here insures some bit allocation to frames even - // in static regions. The allocation per MB declines for larger formats - // where the typical "real" energy per MB also falls. - // Initial estimate here uses sqrt(mbs) to define the min_err, where the - // number of mbs is proportional to the image area. - const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) - ? cpi->initial_mbs - : cpi->common.MBs; - const double min_err = 200 * sqrt(num_mbs); - - intra_factor = intra_factor / (double)num_mbs; - brightness_factor = brightness_factor / (double)num_mbs; - fps.weight = intra_factor * brightness_factor; - - fps.frame = current_frame->frame_number; - fps.coded_error = (double)(coded_error >> 8) + min_err; - fps.sr_coded_error = (double)(sr_coded_error >> 8) + min_err; - fps.tr_coded_error = (double)(tr_coded_error >> 8) + min_err; - fps.intra_error = (double)(intra_error >> 8) + min_err; - fps.frame_avg_wavelet_energy = (double)frame_avg_wavelet_energy; - fps.count = 1.0; - fps.pcnt_inter = (double)intercount / num_mbs; - fps.pcnt_second_ref = (double)second_ref_count / num_mbs; - fps.pcnt_third_ref = (double)third_ref_count / num_mbs; - fps.pcnt_neutral = (double)neutral_count / num_mbs; - fps.intra_skip_pct = (double)intra_skip_count / num_mbs; - fps.inactive_zone_rows = (double)image_data_start_row; - fps.inactive_zone_cols = (double)0; // TODO(paulwilkins): fix - fps.raw_error_stdev = raw_err_stdev; - - if (mvcount > 0) { - fps.MVr = (double)sum_mvr / mvcount; - fps.mvr_abs = (double)sum_mvr_abs / mvcount; - fps.MVc = (double)sum_mvc / mvcount; - fps.mvc_abs = (double)sum_mvc_abs / mvcount; - fps.MVrv = - ((double)sum_mvrs - ((double)sum_mvr * sum_mvr / mvcount)) / mvcount; - fps.MVcv = - ((double)sum_mvcs - ((double)sum_mvc * sum_mvc / mvcount)) / mvcount; - fps.mv_in_out_count = (double)sum_in_vectors / (mvcount * 2); - fps.new_mv_count = new_mv_count; - fps.pcnt_motion = (double)mvcount / num_mbs; - } else { - fps.MVr = 0.0; - fps.mvr_abs = 0.0; - fps.MVc = 0.0; - fps.mvc_abs = 0.0; - fps.MVrv = 0.0; - fps.MVcv = 0.0; - fps.mv_in_out_count = 0.0; - fps.new_mv_count = 0.0; - fps.pcnt_motion = 0.0; - } - - // TODO(paulwilkins): Handle the case when duration is set to 0, or - // something less than the full time between subsequent values of - // cpi->source_time_stamp. - fps.duration = (double)ts_duration; - - // We will store the stats inside the persistent twopass struct (and NOT the - // local variable 'fps'), and then cpi->output_pkt_list will point to it. - *this_frame_stats = fps; - output_stats(this_frame_stats, cpi->output_pkt_list); - accumulate_stats(&twopass->total_stats, &fps); - // Update circular index. - twopass->frame_stats_next_idx = - (twopass->frame_stats_next_idx + 1) % MAX_LAG_BUFFERS; - } + TWO_PASS *twopass = &cpi->twopass; + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs + : mi_params->MBs; + stats.intra_factor = stats.intra_factor / (double)num_mbs; + stats.brightness_factor = stats.brightness_factor / (double)num_mbs; + FIRSTPASS_STATS *this_frame_stats = twopass->stats_buf_ctx->stats_in_end; + update_firstpass_stats(cpi, &stats, raw_err_stdev, + current_frame->frame_number, ts_duration); // Copy the previous Last Frame back into gf buffer if the prediction is good // enough... but also don't allow it to lag too far. @@ -899,7 +1033,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { (this_frame_stats->pcnt_inter > 0.20) && ((this_frame_stats->intra_error / DOUBLE_DIVIDE_CHECK(this_frame_stats->coded_error)) > 2.0))) { - if (gld_yv12 != NULL) { + if (golden_frame != NULL) { assign_frame_buffer_p( &cm->ref_frame_map[get_ref_frame_map_idx(cm, GOLDEN_FRAME)], cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]); @@ -909,7 +1043,7 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { ++twopass->sr_update_lag; } - aom_extend_frame_borders(new_yv12, num_planes); + aom_extend_frame_borders(this_frame, num_planes); // The frame we just compressed now becomes the last frame. assign_frame_buffer_p( @@ -924,21 +1058,8 @@ void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) { cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]); } - // Use this to see what the first pass reconstruction looks like. - if (0) { - char filename[512]; - FILE *recon_file; - snprintf(filename, sizeof(filename), "enc%04d.yuv", - (int)current_frame->frame_number); - - if (current_frame->frame_number == 0) - recon_file = fopen(filename, "wb"); - else - recon_file = fopen(filename, "ab"); - - (void)fwrite(lst_yv12->buffer_alloc, lst_yv12->frame_size, 1, recon_file); - fclose(recon_file); - } + print_reconstruction_frame(last_frame, current_frame->frame_number, + /*do_print=*/0); ++current_frame->frame_number; } diff --git a/media/libaom/src/av1/encoder/firstpass.h b/media/libaom/src/av1/encoder/firstpass.h index 71037a84bd..99d4445395 100644 --- a/media/libaom/src/av1/encoder/firstpass.h +++ b/media/libaom/src/av1/encoder/firstpass.h @@ -12,8 +12,8 @@ #ifndef AOM_AV1_ENCODER_FIRSTPASS_H_ #define AOM_AV1_ENCODER_FIRSTPASS_H_ +#include "av1/common/av1_common_int.h" #include "av1/common/enums.h" -#include "av1/common/onyxc_int.h" #include "av1/encoder/lookahead.h" #include "av1/encoder/ratectrl.h" @@ -30,8 +30,6 @@ extern "C" { #define VLOW_MOTION_THRESHOLD 950 -#define MAX_ARF_LAYERS 5 - typedef struct { // Frame number in display order, if stats are for a single frame. // No real meaning for a collection of frames. @@ -112,6 +110,9 @@ typedef struct { unsigned char index; FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH]; unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH]; + // The number of frames displayed so far within the GOP at a given coding + // frame. + unsigned char cur_frame_idx[MAX_STATIC_GF_GROUP_LENGTH]; unsigned char frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH]; int ref_frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH][REF_FRAMES]; int ref_frame_gop_idx[MAX_STATIC_GF_GROUP_LENGTH][REF_FRAMES]; @@ -128,18 +129,23 @@ typedef struct { int size; } GF_GROUP; +typedef struct { + FIRSTPASS_STATS *stats_in_start; + FIRSTPASS_STATS *stats_in_end; + FIRSTPASS_STATS *stats_in_buf_end; + FIRSTPASS_STATS *total_stats; + FIRSTPASS_STATS *total_left_stats; +} STATS_BUFFER_CTX; + typedef struct { unsigned int section_intra_rating; - FIRSTPASS_STATS total_stats; // Circular queue of first pass stats stored for most recent frames. // cpi->output_pkt_list[i].data.twopass_stats.buf points to actual data stored // here. - FIRSTPASS_STATS frame_stats_arr[MAX_LAG_BUFFERS]; + FIRSTPASS_STATS *frame_stats_arr[MAX_LAP_BUFFERS + 1]; int frame_stats_next_idx; // Index to next unused element in frame_stats_arr. const FIRSTPASS_STATS *stats_in; - const FIRSTPASS_STATS *stats_in_start; - const FIRSTPASS_STATS *stats_in_end; - FIRSTPASS_STATS total_left_stats; + STATS_BUFFER_CTX *stats_buf_ctx; int first_pass_done; int64_t bits_left; double modified_error_min; @@ -157,9 +163,6 @@ typedef struct { // Error score of frames still to be coded in kf group int64_t kf_group_error_left; - // The fraction for a kf groups total bits allocated to the inter frames - double kfgroup_inter_fraction; - // Over time correction for bits per macro block estimation double bpm_factor; @@ -180,7 +183,6 @@ 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); diff --git a/media/libaom/src/av1/encoder/gop_structure.c b/media/libaom/src/av1/encoder/gop_structure.c index 8f6ac61106..1ed71a0f99 100644 --- a/media/libaom/src/av1/encoder/gop_structure.c +++ b/media/libaom/src/av1/encoder/gop_structure.c @@ -19,7 +19,7 @@ #include "aom_ports/system_state.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/encoder/encoder.h" #include "av1/encoder/firstpass.h" @@ -29,8 +29,8 @@ static void set_multi_layer_params(const TWO_PASS *twopass, GF_GROUP *const gf_group, RATE_CONTROL *rc, FRAME_INFO *frame_info, int start, int end, - int *frame_ind, int arf_ind, - int layer_depth) { + int *cur_frame_idx, int *frame_ind, + int arf_ind, int layer_depth) { const int num_frames_to_process = end - start - 1; assert(num_frames_to_process >= 0); if (num_frames_to_process == 0) return; @@ -43,9 +43,12 @@ static void set_multi_layer_params(const TWO_PASS *twopass, while (++start < end) { gf_group->update_type[*frame_ind] = LF_UPDATE; gf_group->arf_src_offset[*frame_ind] = 0; + ++*cur_frame_idx; + gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx; gf_group->frame_disp_idx[*frame_ind] = start; gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS; - gf_group->arf_boost[*frame_ind] = NORMAL_BOOST; + gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost( + twopass, rc, frame_info, start, end - start, 0, NULL, NULL); gf_group->max_layer_depth = AOMMAX(gf_group->max_layer_depth, layer_depth); ++(*frame_ind); @@ -56,29 +59,31 @@ static void set_multi_layer_params(const TWO_PASS *twopass, // Internal ARF. gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE; gf_group->arf_src_offset[*frame_ind] = m - start - 1; + gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx; gf_group->frame_disp_idx[*frame_ind] = m; gf_group->layer_depth[*frame_ind] = layer_depth; // Get the boost factor for intermediate ARF frames. - gf_group->arf_boost[*frame_ind] = - av1_calc_arf_boost(twopass, rc, frame_info, m, end - m, m - start); + gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost( + twopass, rc, frame_info, m, end - m, m - start, NULL, NULL); ++(*frame_ind); // Frames displayed before this internal ARF. set_multi_layer_params(twopass, gf_group, rc, frame_info, start, m, - frame_ind, 1, layer_depth + 1); + cur_frame_idx, frame_ind, 1, layer_depth + 1); // Overlay for internal ARF. gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE; gf_group->arf_src_offset[*frame_ind] = 0; + gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx; gf_group->frame_disp_idx[*frame_ind] = m; gf_group->arf_boost[*frame_ind] = 0; gf_group->layer_depth[*frame_ind] = layer_depth; ++(*frame_ind); // Frames displayed after this internal ARF. - set_multi_layer_params(twopass, gf_group, rc, frame_info, m, end, frame_ind, - arf_ind, layer_depth + 1); + set_multi_layer_params(twopass, gf_group, rc, frame_info, m, end, + cur_frame_idx, frame_ind, arf_ind, layer_depth + 1); } } @@ -96,6 +101,7 @@ static int construct_multi_layer_gf_structure( gf_group->update_type[frame_index] = first_frame_update_type; gf_group->arf_src_offset[frame_index] = 0; + gf_group->cur_frame_idx[frame_index] = 0; gf_group->layer_depth[frame_index] = first_frame_update_type == OVERLAY_UPDATE ? MAX_ARF_LAYERS + 1 : 0; gf_group->max_layer_depth = 0; @@ -106,6 +112,7 @@ static int construct_multi_layer_gf_structure( if (use_altref) { gf_group->update_type[frame_index] = ARF_UPDATE; gf_group->arf_src_offset[frame_index] = gf_interval - 1; + gf_group->cur_frame_idx[frame_index] = 0; gf_group->frame_disp_idx[frame_index] = gf_interval; gf_group->layer_depth[frame_index] = 1; gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost; @@ -113,9 +120,10 @@ static int construct_multi_layer_gf_structure( ++frame_index; } + int cur_frame_index = 0; // Rest of the frames. set_multi_layer_params(twopass, gf_group, rc, frame_info, 0, gf_interval, - &frame_index, 0, use_altref + 1); + &cur_frame_index, &frame_index, 0, use_altref + 1); // The end frame will be Overlay frame for an ARF GOP; otherwise set it to // be GF, for consistency, which will be updated in the next GOP. diff --git a/media/libaom/src/av1/encoder/gop_structure.h b/media/libaom/src/av1/encoder/gop_structure.h index 4637930211..0c775c7b49 100644 --- a/media/libaom/src/av1/encoder/gop_structure.h +++ b/media/libaom/src/av1/encoder/gop_structure.h @@ -12,7 +12,7 @@ #ifndef AOM_AV1_ENCODER_GOP_STRUCTURE_H_ #define AOM_AV1_ENCODER_GOP_STRUCTURE_H_ -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/encoder/ratectrl.h" #ifdef __cplusplus @@ -34,7 +34,8 @@ void av1_gop_setup_structure( int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc, FRAME_INFO *frame_info, int offset, int f_frames, - int b_frames); + int b_frames, int *num_fpstats_used, + int *num_fpstats_required); #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/hash.c b/media/libaom/src/av1/encoder/hash.c index c9348cef84..3091037eb1 100644 --- a/media/libaom/src/av1/encoder/hash.c +++ b/media/libaom/src/av1/encoder/hash.c @@ -61,8 +61,8 @@ void av1_crc_calculator_init(CRC_CALCULATOR *p_crc_calculator, uint32_t bits, crc_calculator_init_table(p_crc_calculator); } -uint32_t av1_get_crc_value(void *crc_calculator, uint8_t *p, int length) { - CRC_CALCULATOR *p_crc_calculator = (CRC_CALCULATOR *)crc_calculator; +uint32_t av1_get_crc_value(CRC_CALCULATOR *p_crc_calculator, uint8_t *p, + int length) { crc_calculator_reset(p_crc_calculator); crc_calculator_process_data(p_crc_calculator, p, length); return crc_calculator_get_crc(p_crc_calculator); diff --git a/media/libaom/src/av1/encoder/hash.h b/media/libaom/src/av1/encoder/hash.h index 826c004d6f..d8e8cc3a0b 100644 --- a/media/libaom/src/av1/encoder/hash.h +++ b/media/libaom/src/av1/encoder/hash.h @@ -32,7 +32,8 @@ typedef struct _crc_calculator { // calling av1_get_crc_value(). void av1_crc_calculator_init(CRC_CALCULATOR *p_crc_calculator, uint32_t bits, uint32_t truncPoly); -uint32_t av1_get_crc_value(void *crc_calculator, uint8_t *p, int length); +uint32_t av1_get_crc_value(CRC_CALCULATOR *p_crc_calculator, uint8_t *p, + int length); // CRC32C: POLY = 0x82f63b78; typedef struct _CRC32C { diff --git a/media/libaom/src/av1/encoder/hash_motion.c b/media/libaom/src/av1/encoder/hash_motion.c index 25fedf953b..310cde886b 100644 --- a/media/libaom/src/av1/encoder/hash_motion.c +++ b/media/libaom/src/av1/encoder/hash_motion.c @@ -17,14 +17,16 @@ #include "av1/encoder/hash.h" #include "av1/encoder/hash_motion.h" -static const int crc_bits = 16; -static const int block_size_bits = 3; +#define kSrcBits 16 +#define kBlockSizeBits 3 +#define kMaxAddr (1 << (kSrcBits + kBlockSizeBits)) // TODO(youzhou@microsoft.com): is higher than 8 bits screen content supported? // If yes, fix this function -static void get_pixels_in_1D_char_array_by_block_2x2(uint8_t *y_src, int stride, +static void get_pixels_in_1D_char_array_by_block_2x2(const uint8_t *y_src, + int stride, uint8_t *p_pixels_in1D) { - uint8_t *p_pel = y_src; + const uint8_t *p_pel = y_src; int index = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { @@ -34,10 +36,10 @@ static void get_pixels_in_1D_char_array_by_block_2x2(uint8_t *y_src, int stride, } } -static void get_pixels_in_1D_short_array_by_block_2x2(uint16_t *y_src, +static void get_pixels_in_1D_short_array_by_block_2x2(const uint16_t *y_src, int stride, uint16_t *p_pixels_in1D) { - uint16_t *p_pel = y_src; + const uint16_t *p_pel = y_src; int index = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { @@ -47,28 +49,28 @@ static void get_pixels_in_1D_short_array_by_block_2x2(uint16_t *y_src, } } -static int is_block_2x2_row_same_value(uint8_t *p) { +static int is_block_2x2_row_same_value(const uint8_t *p) { if (p[0] != p[1] || p[2] != p[3]) { return 0; } return 1; } -static int is_block16_2x2_row_same_value(uint16_t *p) { +static int is_block16_2x2_row_same_value(const uint16_t *p) { if (p[0] != p[1] || p[2] != p[3]) { return 0; } return 1; } -static int is_block_2x2_col_same_value(uint8_t *p) { +static int is_block_2x2_col_same_value(const uint8_t *p) { if ((p[0] != p[2]) || (p[1] != p[3])) { return 0; } return 1; } -static int is_block16_2x2_col_same_value(uint16_t *p) { +static int is_block16_2x2_col_same_value(const uint16_t *p) { if ((p[0] != p[2]) || (p[1] != p[3])) { return 0; } @@ -90,42 +92,32 @@ static int hash_block_size_to_index(int block_size) { } } -void av1_hash_table_init(hash_table *p_hash_table, MACROBLOCK *x) { - if (x->g_crc_initialized == 0) { - av1_crc_calculator_init(&x->crc_calculator1, 24, 0x5D6DCB); - av1_crc_calculator_init(&x->crc_calculator2, 24, 0x864CFB); - x->g_crc_initialized = 1; +void av1_hash_table_init(IntraBCHashInfo *intrabc_hash_info) { + if (!intrabc_hash_info->g_crc_initialized) { + av1_crc_calculator_init(&intrabc_hash_info->crc_calculator1, 24, 0x5D6DCB); + av1_crc_calculator_init(&intrabc_hash_info->crc_calculator2, 24, 0x864CFB); + intrabc_hash_info->g_crc_initialized = 1; } - p_hash_table->p_lookup_table = NULL; -#if CONFIG_DEBUG - p_hash_table->has_content = 0; -#endif + intrabc_hash_info->intrabc_hash_table.p_lookup_table = NULL; } void av1_hash_table_clear_all(hash_table *p_hash_table) { if (p_hash_table->p_lookup_table == NULL) { return; } - int max_addr = 1 << (crc_bits + block_size_bits); - for (int i = 0; i < max_addr; i++) { + for (int i = 0; i < kMaxAddr; i++) { if (p_hash_table->p_lookup_table[i] != NULL) { aom_vector_destroy(p_hash_table->p_lookup_table[i]); aom_free(p_hash_table->p_lookup_table[i]); p_hash_table->p_lookup_table[i] = NULL; } } -#if CONFIG_DEBUG - p_hash_table->has_content = 0; -#endif } void av1_hash_table_destroy(hash_table *p_hash_table) { av1_hash_table_clear_all(p_hash_table); aom_free(p_hash_table->p_lookup_table); p_hash_table->p_lookup_table = NULL; -#if CONFIG_DEBUG - p_hash_table->has_content = 0; -#endif } void av1_hash_table_create(hash_table *p_hash_table) { @@ -133,14 +125,10 @@ void av1_hash_table_create(hash_table *p_hash_table) { av1_hash_table_clear_all(p_hash_table); return; } - const int max_addr = 1 << (crc_bits + block_size_bits); p_hash_table->p_lookup_table = - (Vector **)aom_malloc(sizeof(p_hash_table->p_lookup_table[0]) * max_addr); + (Vector **)aom_malloc(sizeof(p_hash_table->p_lookup_table[0]) * kMaxAddr); memset(p_hash_table->p_lookup_table, 0, - sizeof(p_hash_table->p_lookup_table[0]) * max_addr); -#if CONFIG_DEBUG - p_hash_table->has_content = 0; -#endif + sizeof(p_hash_table->p_lookup_table[0]) * kMaxAddr); } static void hash_table_add_to_table(hash_table *p_hash_table, @@ -192,14 +180,16 @@ int32_t av1_has_exact_match(hash_table *p_hash_table, uint32_t hash_value1, return 0; } -void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture, +void av1_generate_block_2x2_hash_value(IntraBCHashInfo *intrabc_hash_info, + const YV12_BUFFER_CONFIG *picture, uint32_t *pic_block_hash[2], - int8_t *pic_block_same_info[3], - MACROBLOCK *x) { + int8_t *pic_block_same_info[3]) { const int width = 2; const int height = 2; const int x_end = picture->y_crop_width - width + 1; const int y_end = picture->y_crop_height - height + 1; + CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1; + CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2; const int length = width * 2; if (picture->flags & YV12_FLAG_HIGHBITDEPTH) { @@ -214,10 +204,10 @@ void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture, pic_block_same_info[0][pos] = is_block16_2x2_row_same_value(p); pic_block_same_info[1][pos] = is_block16_2x2_col_same_value(p); - pic_block_hash[0][pos] = av1_get_crc_value( - &x->crc_calculator1, (uint8_t *)p, length * sizeof(p[0])); - pic_block_hash[1][pos] = av1_get_crc_value( - &x->crc_calculator2, (uint8_t *)p, length * sizeof(p[0])); + pic_block_hash[0][pos] = + av1_get_crc_value(calc_1, (uint8_t *)p, length * sizeof(p[0])); + pic_block_hash[1][pos] = + av1_get_crc_value(calc_2, (uint8_t *)p, length * sizeof(p[0])); pos++; } pos += width - 1; @@ -234,9 +224,9 @@ void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture, pic_block_same_info[1][pos] = is_block_2x2_col_same_value(p); pic_block_hash[0][pos] = - av1_get_crc_value(&x->crc_calculator1, p, length * sizeof(p[0])); + av1_get_crc_value(calc_1, p, length * sizeof(p[0])); pic_block_hash[1][pos] = - av1_get_crc_value(&x->crc_calculator2, p, length * sizeof(p[0])); + av1_get_crc_value(calc_2, p, length * sizeof(p[0])); pos++; } pos += width - 1; @@ -244,13 +234,16 @@ void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture, } } -void av1_generate_block_hash_value(const YV12_BUFFER_CONFIG *picture, +void av1_generate_block_hash_value(IntraBCHashInfo *intrabc_hash_info, + const YV12_BUFFER_CONFIG *picture, int block_size, uint32_t *src_pic_block_hash[2], uint32_t *dst_pic_block_hash[2], int8_t *src_pic_block_same_info[3], - int8_t *dst_pic_block_same_info[3], - MACROBLOCK *x) { + int8_t *dst_pic_block_same_info[3]) { + CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1; + CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2; + const int pic_width = picture->y_crop_width; const int x_end = picture->y_crop_width - block_size + 1; const int y_end = picture->y_crop_height - block_size + 1; @@ -269,14 +262,14 @@ void av1_generate_block_hash_value(const YV12_BUFFER_CONFIG *picture, p[2] = src_pic_block_hash[0][pos + src_size * pic_width]; p[3] = src_pic_block_hash[0][pos + src_size * pic_width + src_size]; dst_pic_block_hash[0][pos] = - av1_get_crc_value(&x->crc_calculator1, (uint8_t *)p, length); + av1_get_crc_value(calc_1, (uint8_t *)p, length); p[0] = src_pic_block_hash[1][pos]; p[1] = src_pic_block_hash[1][pos + src_size]; p[2] = src_pic_block_hash[1][pos + src_size * pic_width]; p[3] = src_pic_block_hash[1][pos + src_size * pic_width + src_size]; dst_pic_block_hash[1][pos] = - av1_get_crc_value(&x->crc_calculator2, (uint8_t *)p, length); + av1_get_crc_value(calc_2, (uint8_t *)p, length); dst_pic_block_same_info[0][pos] = src_pic_block_same_info[0][pos] && @@ -327,8 +320,8 @@ void av1_add_to_hash_map_by_row_with_precal_data(hash_table *p_hash_table, 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; + add_value <<= kSrcBits; + const int crc_mask = (1 << kSrcBits) - 1; for (int x_pos = 0; x_pos < x_end; x_pos++) { for (int y_pos = 0; y_pos < y_end; y_pos++) { @@ -403,14 +396,19 @@ int av1_hash_is_vertical_perfect(const YV12_BUFFER_CONFIG *picture, return 1; } -void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, +void av1_get_block_hash_value(IntraBCHashInfo *intrabc_hash_info, + const 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]; + int use_highbitdepth) { 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; + add_value <<= kSrcBits; + const int crc_mask = (1 << kSrcBits) - 1; + + CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1; + CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2; + uint32_t **buf_1 = intrabc_hash_info->hash_value_buffer[0]; + uint32_t **buf_2 = intrabc_hash_info->hash_value_buffer[1]; // 2x2 subblock hash values in current CU int sub_block_in_width = (block_size >> 1); @@ -423,12 +421,10 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, get_pixels_in_1D_short_array_by_block_2x2( y16_src + y_pos * stride + x_pos, stride, pixel_to_hash); assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH); - x->hash_value_buffer[0][0][pos] = - av1_get_crc_value(&x->crc_calculator1, (uint8_t *)pixel_to_hash, - sizeof(pixel_to_hash)); - x->hash_value_buffer[1][0][pos] = - av1_get_crc_value(&x->crc_calculator2, (uint8_t *)pixel_to_hash, - sizeof(pixel_to_hash)); + buf_1[0][pos] = av1_get_crc_value(calc_1, (uint8_t *)pixel_to_hash, + sizeof(pixel_to_hash)); + buf_2[0][pos] = av1_get_crc_value(calc_2, (uint8_t *)pixel_to_hash, + sizeof(pixel_to_hash)); } } } else { @@ -439,10 +435,10 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, get_pixels_in_1D_char_array_by_block_2x2(y_src + y_pos * stride + x_pos, stride, pixel_to_hash); assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH); - x->hash_value_buffer[0][0][pos] = av1_get_crc_value( - &x->crc_calculator1, pixel_to_hash, sizeof(pixel_to_hash)); - x->hash_value_buffer[1][0][pos] = av1_get_crc_value( - &x->crc_calculator2, pixel_to_hash, sizeof(pixel_to_hash)); + buf_1[0][pos] = + av1_get_crc_value(calc_1, pixel_to_hash, sizeof(pixel_to_hash)); + buf_2[0][pos] = + av1_get_crc_value(calc_2, pixel_to_hash, sizeof(pixel_to_hash)); } } } @@ -454,6 +450,7 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, int dst_idx = 0; // 4x4 subblock hash values to current block hash values + uint32_t to_hash[4]; for (int sub_width = 4; sub_width <= block_size; sub_width *= 2) { src_idx = 1 - src_idx; dst_idx = 1 - dst_idx; @@ -467,24 +464,20 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, assert(srcPos + src_sub_block_in_width + 1 < AOM_BUFFER_SIZE_FOR_BLOCK_HASH); assert(dst_pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH); - to_hash[0] = x->hash_value_buffer[0][src_idx][srcPos]; - to_hash[1] = x->hash_value_buffer[0][src_idx][srcPos + 1]; - to_hash[2] = - x->hash_value_buffer[0][src_idx][srcPos + src_sub_block_in_width]; - to_hash[3] = x->hash_value_buffer[0][src_idx] - [srcPos + src_sub_block_in_width + 1]; + to_hash[0] = buf_1[src_idx][srcPos]; + to_hash[1] = buf_1[src_idx][srcPos + 1]; + to_hash[2] = buf_1[src_idx][srcPos + src_sub_block_in_width]; + to_hash[3] = buf_1[src_idx][srcPos + src_sub_block_in_width + 1]; - x->hash_value_buffer[0][dst_idx][dst_pos] = av1_get_crc_value( - &x->crc_calculator1, (uint8_t *)to_hash, sizeof(to_hash)); + buf_1[dst_idx][dst_pos] = + av1_get_crc_value(calc_1, (uint8_t *)to_hash, sizeof(to_hash)); - to_hash[0] = x->hash_value_buffer[1][src_idx][srcPos]; - to_hash[1] = x->hash_value_buffer[1][src_idx][srcPos + 1]; - to_hash[2] = - x->hash_value_buffer[1][src_idx][srcPos + src_sub_block_in_width]; - to_hash[3] = x->hash_value_buffer[1][src_idx] - [srcPos + src_sub_block_in_width + 1]; - x->hash_value_buffer[1][dst_idx][dst_pos] = av1_get_crc_value( - &x->crc_calculator2, (uint8_t *)to_hash, sizeof(to_hash)); + to_hash[0] = buf_2[src_idx][srcPos]; + to_hash[1] = buf_2[src_idx][srcPos + 1]; + to_hash[2] = buf_2[src_idx][srcPos + src_sub_block_in_width]; + to_hash[3] = buf_2[src_idx][srcPos + src_sub_block_in_width + 1]; + buf_2[dst_idx][dst_pos] = + av1_get_crc_value(calc_2, (uint8_t *)to_hash, sizeof(to_hash)); dst_pos++; } } @@ -493,6 +486,6 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, sub_block_in_width >>= 1; } - *hash_value1 = (x->hash_value_buffer[0][dst_idx][0] & crc_mask) + add_value; - *hash_value2 = x->hash_value_buffer[1][dst_idx][0]; + *hash_value1 = (buf_1[dst_idx][0] & crc_mask) + add_value; + *hash_value2 = buf_2[dst_idx][0]; } diff --git a/media/libaom/src/av1/encoder/hash_motion.h b/media/libaom/src/av1/encoder/hash_motion.h index 516e43dd8c..e4ea1f3948 100644 --- a/media/libaom/src/av1/encoder/hash_motion.h +++ b/media/libaom/src/av1/encoder/hash_motion.h @@ -16,6 +16,7 @@ #include "aom/aom_integer.h" #include "aom_scale/yv12config.h" +#include "av1/encoder/hash.h" #include "third_party/vector/vector.h" #ifdef __cplusplus extern "C" { @@ -35,12 +36,24 @@ typedef struct _block_hash { typedef struct _hash_table { Vector **p_lookup_table; -#if CONFIG_DEBUG - int has_content; -#endif } hash_table; -void av1_hash_table_init(hash_table *p_hash_table, struct macroblock *x); +struct intrabc_hash_info; + +typedef struct intrabc_hash_info { + // buffer for hash value calculation of a block + // used only in av1_get_block_hash_value() + // [first hash/second hash] + // [two buffers used ping-pong] + uint32_t *hash_value_buffer[2][2]; + hash_table intrabc_hash_table; + + CRC_CALCULATOR crc_calculator1; + CRC_CALCULATOR crc_calculator2; + int g_crc_initialized; +} IntraBCHashInfo; + +void av1_hash_table_init(IntraBCHashInfo *intra_bc_hash_info); void av1_hash_table_clear_all(hash_table *p_hash_table); void av1_hash_table_destroy(hash_table *p_hash_table); void av1_hash_table_create(hash_table *p_hash_table); @@ -50,17 +63,17 @@ Iterator av1_hash_get_first_iterator(hash_table *p_hash_table, uint32_t hash_value); int32_t av1_has_exact_match(hash_table *p_hash_table, uint32_t hash_value1, uint32_t hash_value2); -void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture, +void av1_generate_block_2x2_hash_value(IntraBCHashInfo *intra_bc_hash_info, + const YV12_BUFFER_CONFIG *picture, uint32_t *pic_block_hash[2], - int8_t *pic_block_same_info[3], - struct macroblock *x); -void av1_generate_block_hash_value(const YV12_BUFFER_CONFIG *picture, + int8_t *pic_block_same_info[3]); +void av1_generate_block_hash_value(IntraBCHashInfo *intra_bc_hash_info, + const YV12_BUFFER_CONFIG *picture, int block_size, uint32_t *src_pic_block_hash[2], uint32_t *dst_pic_block_hash[2], int8_t *src_pic_block_same_info[3], - int8_t *dst_pic_block_same_info[3], - struct macroblock *x); + int8_t *dst_pic_block_same_info[3]); void av1_add_to_hash_map_by_row_with_precal_data(hash_table *p_hash_table, uint32_t *pic_hash[2], int8_t *pic_is_same, @@ -75,9 +88,11 @@ int av1_hash_is_horizontal_perfect(const YV12_BUFFER_CONFIG *picture, // block_size x block_size has the same color in all columns int av1_hash_is_vertical_perfect(const YV12_BUFFER_CONFIG *picture, int block_size, int x_start, int y_start); -void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size, + +void av1_get_block_hash_value(IntraBCHashInfo *intrabc_hash_info, + const uint8_t *y_src, int stride, int block_size, uint32_t *hash_value1, uint32_t *hash_value2, - int use_highbitdepth, struct macroblock *x); + int use_highbitdepth); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/encoder/interp_search.c b/media/libaom/src/av1/encoder/interp_search.c new file mode 100644 index 0000000000..6b7317be77 --- /dev/null +++ b/media/libaom/src/av1/encoder/interp_search.c @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "av1/common/pred_common.h" +#include "av1/encoder/interp_search.h" +#include "av1/encoder/model_rd.h" +#include "av1/encoder/rdopt_utils.h" +#include "av1/encoder/reconinter_enc.h" + +// return mv_diff +static INLINE int is_interp_filter_good_match( + const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi, + int skip_level) { + const int is_comp = has_second_ref(mi); + int i; + + for (i = 0; i < 1 + is_comp; ++i) { + if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX; + } + + if (skip_level == 1 && is_comp) { + if (st->comp_type != mi->interinter_comp.type) return INT_MAX; + if (st->compound_idx != mi->compound_idx) return INT_MAX; + } + + int mv_diff = 0; + for (i = 0; i < 1 + is_comp; ++i) { + mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) + + abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col); + } + return mv_diff; +} + +static INLINE int save_interp_filter_search_stat( + MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse, + INTERPOLATION_FILTER_STATS *interp_filter_stats, + int interp_filter_stats_idx) { + if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) { + INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters, + { mbmi->mv[0], mbmi->mv[1] }, + { mbmi->ref_frame[0], + mbmi->ref_frame[1] }, + mbmi->interinter_comp.type, + mbmi->compound_idx, + rd, + pred_sse }; + interp_filter_stats[interp_filter_stats_idx] = stat; + interp_filter_stats_idx++; + } + return interp_filter_stats_idx; +} + +static INLINE int find_interp_filter_in_stats( + MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats, + int interp_filter_stats_idx, int skip_level) { + // [skip_levels][single or comp] + const int thr[2][2] = { { 0, 0 }, { 3, 7 } }; + const int is_comp = has_second_ref(mbmi); + + // Find good enough match. + // TODO(yunqing): Separate single-ref mode and comp mode stats for fast + // search. + int best = INT_MAX; + int match = -1; + for (int j = 0; j < interp_filter_stats_idx; ++j) { + const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j]; + const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level); + // Exact match is found. + if (mv_diff == 0) { + match = j; + break; + } else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) { + best = mv_diff; + match = j; + } + } + + if (match != -1) { + mbmi->interp_filters = interp_filter_stats[match].filters; + return match; + } + return -1; // no match result found +} + +int av1_find_interp_filter_match( + MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi, + const InterpFilter assign_filter, const int need_search, + INTERPOLATION_FILTER_STATS *interp_filter_stats, + int interp_filter_stats_idx) { + int match_found_idx = -1; + if (cpi->sf.interp_sf.use_interp_filter && need_search) + match_found_idx = find_interp_filter_in_stats( + mbmi, interp_filter_stats, interp_filter_stats_idx, + cpi->sf.interp_sf.use_interp_filter); + + if (!need_search || match_found_idx == -1) + set_default_interp_filters(mbmi, assign_filter); + return match_found_idx; +} + +static INLINE void swap_dst_buf(MACROBLOCKD *xd, const BUFFER_SET *dst_bufs[2], + int num_planes) { + const BUFFER_SET *buf0 = dst_bufs[0]; + dst_bufs[0] = dst_bufs[1]; + dst_bufs[1] = buf0; + restore_dst_buf(xd, *dst_bufs[0], num_planes); +} + +static INLINE int get_switchable_rate(MACROBLOCK *const x, + const int_interpfilters filters, + const int ctx[2]) { + int inter_filter_cost; + const InterpFilter filter0 = filters.as_filters.y_filter; + const InterpFilter filter1 = filters.as_filters.x_filter; + inter_filter_cost = x->switchable_interp_costs[ctx[0]][filter0]; + inter_filter_cost += x->switchable_interp_costs[ctx[1]][filter1]; + return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost; +} + +// Build inter predictor and calculate model rd +// for a given plane. +static INLINE void interp_model_rd_eval( + MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int plane_from, int plane_to, + RD_STATS *rd_stats, int is_skip_build_pred) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + RD_STATS tmp_rd_stats; + av1_init_rd_stats(&tmp_rd_stats); + + // Skip inter predictor if the predictor is already avilable. + if (!is_skip_build_pred) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + plane_from, plane_to); + } + + model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model + ? MODELRD_LEGACY + : MODELRD_TYPE_INTERP_FILTER]( + cpi, bsize, x, xd, plane_from, plane_to, &tmp_rd_stats.rate, + &tmp_rd_stats.dist, &tmp_rd_stats.skip, &tmp_rd_stats.sse, NULL, NULL, + NULL); + + av1_merge_rd_stats(rd_stats, &tmp_rd_stats); +} + +// calculate the rdcost of given interpolation_filter +static INLINE int64_t interpolation_filter_rd( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int64_t *const rd, + RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate, + const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2], + const int skip_pred) { + const AV1_COMMON *cm = &cpi->common; + const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + RD_STATS this_rd_stats_luma, this_rd_stats; + + // Initialize rd_stats structures to default values. + av1_init_rd_stats(&this_rd_stats_luma); + this_rd_stats = *rd_stats_luma; + const int_interpfilters last_best = mbmi->interp_filters; + mbmi->interp_filters = filter_sets[filter_idx]; + const int tmp_rs = + get_switchable_rate(x, mbmi->interp_filters, switchable_ctx); + + int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0); + if (min_rd > *rd) { + mbmi->interp_filters = last_best; + return 0; + } + + (void)tile_data; + + assert(skip_pred != 2); + assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0)); + assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0)); + assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0)); + assert((rd_stats_luma->skip == 0) || (rd_stats_luma->skip == 1)); + assert((rd_stats->skip == 0) || (rd_stats->skip == 1)); + assert((skip_pred >= 0) && + (skip_pred <= interp_search_flags->default_interp_skip_flags)); + + // When skip pred is equal to default_interp_skip_flags, + // skip both luma and chroma MC. + // For mono-chrome images: + // num_planes = 1 and cpi->default_interp_skip_flags = 1, + // skip_pred = 1: skip both luma and chroma + // skip_pred = 0: Evaluate luma and as num_planes=1, + // skip chroma evaluation + int tmp_skip_pred = + (skip_pred == interp_search_flags->default_interp_skip_flags) + ? INTERP_SKIP_LUMA_SKIP_CHROMA + : skip_pred; + + switch (tmp_skip_pred) { + case INTERP_EVAL_LUMA_EVAL_CHROMA: + // skip_pred = 0: Evaluate both luma and chroma. + // Luma MC + interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y, + &this_rd_stats_luma, 0); + this_rd_stats = this_rd_stats_luma; +#if CONFIG_COLLECT_RD_STATS == 3 + RD_STATS rd_stats_y; + av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, + INT64_MAX); + PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); +#endif // CONFIG_COLLECT_RD_STATS == 3 + AOM_FALLTHROUGH_INTENDED; + case INTERP_SKIP_LUMA_EVAL_CHROMA: + // skip_pred = 1: skip luma evaluation (retain previous best luma stats) + // and do chroma evaluation. + for (int plane = 1; plane < num_planes; ++plane) { + int64_t tmp_rd = + RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); + if (tmp_rd >= *rd) { + mbmi->interp_filters = last_best; + return 0; + } + interp_model_rd_eval(x, cpi, bsize, orig_dst, plane, plane, + &this_rd_stats, 0); + } + break; + case INTERP_SKIP_LUMA_SKIP_CHROMA: + // both luma and chroma evaluation is skipped + this_rd_stats = *rd_stats; + break; + case INTERP_EVAL_INVALID: + default: assert(0); return 0; + } + int64_t tmp_rd = + RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); + + if (tmp_rd < *rd) { + *rd = tmp_rd; + *switchable_rate = tmp_rs; + if (skip_pred != interp_search_flags->default_interp_skip_flags) { + if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) { + // Overwrite the data as current filter is the best one + *rd_stats_luma = this_rd_stats_luma; + *rd_stats = this_rd_stats; + // As luma MC data is computed, no need to recompute after the search + x->recalc_luma_mc_data = 0; + } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) { + // As luma MC data is not computed, update of luma data can be skipped + *rd_stats = this_rd_stats; + // As luma MC data is not recomputed and current filter is the best, + // indicate the possibility of recomputing MC data + // If current buffer contains valid MC data, toggle to indicate that + // luma MC data needs to be recomputed + x->recalc_luma_mc_data ^= 1; + } + swap_dst_buf(xd, dst_bufs, num_planes); + } + return 1; + } + mbmi->interp_filters = last_best; + return 0; +} + +static INLINE INTERP_PRED_TYPE is_pred_filter_search_allowed( + const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize, + int_interpfilters *af, int_interpfilters *lf) { + const AV1_COMMON *cm = &cpi->common; + const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; + const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; + const int bsl = mi_size_wide_log2[bsize]; + int is_horiz_eq = 0, is_vert_eq = 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; + + if (af->as_filters.x_filter != INTERP_INVALID) + is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter; + if (af->as_filters.y_filter != INTERP_INVALID) + is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter; + + INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + int pred_filter_enable = + cpi->sf.interp_sf.cb_pred_filter_search + ? (((mi_row + mi_col) >> bsl) + + get_chessboard_index(cm->current_frame.frame_number)) & + 0x1 + : 0; + pred_filter_enable &= is_horiz_eq || is_vert_eq; + // pred_filter_search = 0: pred_filter is disabled + // pred_filter_search = 1: pred_filter is enabled and only horz pred matching + // pred_filter_search = 2: pred_filter is enabled and only vert pred matching + // pred_filter_search = 3: pred_filter is enabled and + // both vert, horz pred matching + return pred_filter_enable * pred_filter_type; +} + +static DUAL_FILTER_TYPE find_best_interp_rd_facade( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, + RD_STATS *rd_stats, int *const switchable_rate, + const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], + const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) { + int tmp_skip_pred = skip_pred; + DUAL_FILTER_TYPE best_filt_type = REG_REG; + + // If no filter are set to be evaluated, return from function + if (allow_interp_mask == 0x0) return best_filt_type; + // For block width or height is 4, skip the pred evaluation of SHARP_SHARP + tmp_skip_pred = is_w4_or_h4 + ? cpi->interp_search_flags.default_interp_skip_flags + : skip_pred; + + // Loop over the all filter types and evaluate for only allowed filter types + for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) { + const int is_filter_allowed = + get_interp_filter_allowed_mask(allow_interp_mask, filt_type); + if (is_filter_allowed) + if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, + dst_bufs, filt_type, switchable_ctx, + tmp_skip_pred)) + best_filt_type = filt_type; + tmp_skip_pred = skip_pred; + } + return best_filt_type; +} + +static INLINE void pred_dual_interp_filter_rd( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, + RD_STATS *rd_stats, int *const switchable_rate, + const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], + const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af, + int_interpfilters *lf) { + (void)lf; + assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ); + assert(pred_filt_type < INTERP_PRED_TYPE_ALL); + uint16_t allowed_interp_mask = 0; + + if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) { + // pred_filter_search = 1: Only horizontal filter is matching + allowed_interp_mask = + av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter]; + } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) { + // pred_filter_search = 2: Only vertical filter is matching + allowed_interp_mask = + av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter]; + } else { + // pred_filter_search = 3: Both horizontal and vertical filter are matching + int filt_type = + af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS; + set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type); + } + // REG_REG is already been evaluated in the beginning + reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); + find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, rd_stats_y, + rd_stats, switchable_rate, dst_bufs, + switchable_ctx, skip_pred, allowed_interp_mask, 0); +} +// Evaluate dual filter type +// a) Using above, left block interp filter +// b) Find the best horizontal filter and +// then evaluate corresponding vertical filters. +static INLINE void fast_dual_interp_filter_rd( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, + RD_STATS *rd_stats, int *const switchable_rate, + const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], + const int skip_hor, const int skip_ver) { + const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; + int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); + int_interpfilters lf = af; + + if (!have_newmv_in_inter_mode(mbmi->mode)) { + pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf); + } + + if (pred_filter_type) { + pred_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, dst_bufs, + switchable_ctx, (skip_hor & skip_ver), + pred_filter_type, &af, &lf); + } else { + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + int best_dual_mode = 0; + int skip_pred = + bw <= 4 ? interp_search_flags->default_interp_skip_flags : skip_hor; + // TODO(any): Make use of find_best_interp_rd_facade() + // if speed impact is negligible + for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) { + if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, + dst_bufs, i, switchable_ctx, skip_pred)) { + best_dual_mode = i; + } + skip_pred = skip_hor; + } + // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes + skip_pred = + bh <= 4 ? interp_search_flags->default_interp_skip_flags : skip_ver; + for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2)); + i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) { + interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, dst_bufs, + i, switchable_ctx, skip_pred); + skip_pred = skip_ver; + } + } +} + +// Find the best interp filter if dual_interp_filter = 0 +static INLINE void find_best_non_dual_interp_filter( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, + RD_STATS *rd_stats, int *const switchable_rate, + const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], + const int skip_ver, const int skip_hor) { + const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; + int8_t i; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + + uint16_t interp_filter_search_mask = + interp_search_flags->interp_filter_search_mask; + + if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { + const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); + const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0); + const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1); + const int *switchable_interp_p0 = + cpi->frame_probs.switchable_interp_probs[update_type][ctx0]; + const int *switchable_interp_p1 = + cpi->frame_probs.switchable_interp_probs[update_type][ctx1]; + + static const int thr[7] = { 0, 8, 8, 8, 8, 0, 8 }; + const int thresh = thr[update_type]; + for (i = 0; i < SWITCHABLE_FILTERS; i++) { + // For non-dual case, the 2 dir's prob should be identical. + assert(switchable_interp_p0[i] == switchable_interp_p1[i]); + if (switchable_interp_p0[i] < thresh && + switchable_interp_p1[i] < thresh) { + DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i; + reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type); + } + } + } + + // Regular filter evaluation should have been done and hence the same should + // be the winner + assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int); + if ((skip_hor & skip_ver) != interp_search_flags->default_interp_skip_flags) { + INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; + int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); + int_interpfilters lf = af; + + pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf); + if (pred_filter_type) { + assert(af.as_filters.x_filter != INTERP_INVALID); + int filter_idx = SWITCHABLE * af.as_filters.x_filter; + // This assert tells that (filter_x == filter_y) for non-dual filter case + assert(filter_sets[filter_idx].as_filters.x_filter == + filter_sets[filter_idx].as_filters.y_filter); + if (cpi->sf.interp_sf.adaptive_interp_filter_search && + !(get_interp_filter_allowed_mask(interp_filter_search_mask, + filter_idx))) { + return; + } + if (filter_idx) { + interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, dst_bufs, + filter_idx, switchable_ctx, + (skip_hor & skip_ver)); + } + return; + } + } + // Reuse regular filter's modeled rd data for sharp filter for following + // cases + // 1) When bsize is 4x4 + // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical + // direction is full-pel + // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal + // direction is full-pel + // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction + // alone is full-pel + + if ((bsize == BLOCK_4X4) || + (block_size_wide[bsize] == 4 && + skip_ver == interp_search_flags->default_interp_skip_flags) || + (block_size_high[bsize] == 4 && + skip_hor == interp_search_flags->default_interp_skip_flags)) { + int skip_pred = skip_hor & skip_ver; + uint16_t allowed_interp_mask = 0; + + // REG_REG filter type is evaluated beforehand, hence skip it + set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP); + set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH); + if (cpi->sf.interp_sf.adaptive_interp_filter_search) + allowed_interp_mask &= interp_filter_search_mask; + + find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, dst_bufs, + switchable_ctx, skip_pred, allowed_interp_mask, + 1); + } else { + int skip_pred = (skip_hor & skip_ver); + for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE; + i += (SWITCHABLE_FILTERS + 1)) { + // This assert tells that (filter_x == filter_y) for non-dual filter case + assert(filter_sets[i].as_filters.x_filter == + filter_sets[i].as_filters.y_filter); + if (cpi->sf.interp_sf.adaptive_interp_filter_search && + !(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) { + continue; + } + interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + rd_stats_y, rd_stats, switchable_rate, dst_bufs, + i, switchable_ctx, skip_pred); + // In first iteration, smooth filter is evaluated. If smooth filter + // (which is less sharper) is the winner among regular and smooth filters, + // sharp filter evaluation is skipped + // TODO(any): Refine this gating based on modelled rd only (i.e., by not + // accounting switchable filter rate) + if (cpi->sf.interp_sf.skip_sharp_interp_filter_search && + skip_pred != interp_search_flags->default_interp_skip_flags) { + if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int) + break; + } + } + } +} + +static INLINE void calc_interp_skip_pred_flag(MACROBLOCK *const x, + const AV1_COMP *const cpi, + int *skip_hor, int *skip_ver) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int num_planes = av1_num_planes(cm); + const int is_compound = has_second_ref(mbmi); + assert(is_intrabc_block(mbmi) == 0); + for (int ref = 0; ref < 1 + is_compound; ++ref) { + const struct scale_factors *const sf = + get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]); + // TODO(any): Refine skip flag calculation considering scaling + if (av1_is_scaled(sf)) { + *skip_hor = 0; + *skip_ver = 0; + break; + } + const MV mv = mbmi->mv[ref].as_mv; + int skip_hor_plane = 0; + int skip_ver_plane = 0; + for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1)); + ++plane_idx) { + struct macroblockd_plane *const pd = &xd->plane[plane_idx]; + const int bw = pd->width; + const int bh = pd->height; + const MV mv_q4 = clamp_mv_to_umv_border_sb( + xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); + const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; + const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; + skip_hor_plane |= ((sub_x == 0) << plane_idx); + skip_ver_plane |= ((sub_y == 0) << plane_idx); + } + *skip_hor &= skip_hor_plane; + *skip_ver &= skip_ver_plane; + // It is not valid that "luma MV is sub-pel, whereas chroma MV is not" + assert(*skip_hor != 2); + assert(*skip_ver != 2); + } + // When compond prediction type is compound segment wedge, luma MC and chroma + // MC need to go hand in hand as mask generated during luma MC is reuired for + // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during + // vertical filter decision may be incorrect as temporary MC evaluation + // overwrites the mask. Make skip_ver as 0 for this case so that mask is + // populated during luma MC + if (is_compound && mbmi->compound_idx == 1 && + mbmi->interinter_comp.type == COMPOUND_DIFFWTD) { + assert(mbmi->comp_group_idx == 1); + if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0; + } +} + +int64_t av1_interpolation_filter_search( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst, + int64_t *const rd, int *const switchable_rate, int *skip_build_pred, + HandleInterModeArgs *args, int64_t ref_best_rd) { + const AV1_COMMON *cm = &cpi->common; + const InterpSearchFlags *interp_search_flags = &cpi->interp_search_flags; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int need_search = + av1_is_interp_needed(xd) && !cpi->sf.rt_sf.skip_interp_filter_search; + const int ref_frame = xd->mi[0]->ref_frame[0]; + RD_STATS rd_stats_luma, rd_stats; + + // Initialization of rd_stats structures with default values + av1_init_rd_stats(&rd_stats_luma); + av1_init_rd_stats(&rd_stats); + + int match_found_idx = -1; + const InterpFilter assign_filter = cm->features.interp_filter; + + match_found_idx = av1_find_interp_filter_match( + mbmi, cpi, assign_filter, need_search, args->interp_filter_stats, + args->interp_filter_stats_idx); + + if (match_found_idx != -1) { + *rd = args->interp_filter_stats[match_found_idx].rd; + x->pred_sse[ref_frame] = + args->interp_filter_stats[match_found_idx].pred_sse; + return 0; + } + + int switchable_ctx[2]; + switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0); + switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1); + *switchable_rate = + get_switchable_rate(x, mbmi->interp_filters, switchable_ctx); + + // Do MC evaluation for default filter_type. + // Luma MC + interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y, + &rd_stats_luma, *skip_build_pred); + +#if CONFIG_COLLECT_RD_STATS == 3 + RD_STATS rd_stats_y; + av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); + PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); +#endif // CONFIG_COLLECT_RD_STATS == 3 + // Chroma MC + if (num_planes > 1) { + interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_U, AOM_PLANE_V, + &rd_stats, *skip_build_pred); + } + *skip_build_pred = 1; + + av1_merge_rd_stats(&rd_stats, &rd_stats_luma); + + assert(rd_stats.rate >= 0); + + *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist); + x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); + + if (assign_filter != SWITCHABLE || match_found_idx != -1) { + return 0; + } + if (!need_search) { + int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); + assert(mbmi->interp_filters.as_int == filters.as_int); + (void)filters; + return 0; + } + if (args->modelled_rd != NULL) { + if (has_second_ref(mbmi)) { + const int ref_mv_idx = mbmi->ref_mv_idx; + MV_REFERENCE_FRAME *refs = mbmi->ref_frame; + const int mode0 = compound_ref0_mode(mbmi->mode); + const int mode1 = compound_ref1_mode(mbmi->mode); + const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]], + args->modelled_rd[mode1][ref_mv_idx][refs[1]]); + if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) { + return INT64_MAX; + } + } + } + + x->recalc_luma_mc_data = 0; + // skip_flag=xx (in binary form) + // Setting 0th flag corresonds to skipping luma MC and setting 1st bt + // corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip + // luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only" + // Skip_flag=2 is not a valid case + // skip_flag=3 corresponds to "Skip both luma and chroma MC" + int skip_hor = interp_search_flags->default_interp_skip_flags; + int skip_ver = interp_search_flags->default_interp_skip_flags; + calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver); + + // do interp_filter search + restore_dst_buf(xd, *tmp_dst, num_planes); + const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst }; + // Evaluate dual interp filters + if (cm->seq_params.enable_dual_filter) { + if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) { + fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd, + &rd_stats_luma, &rd_stats, switchable_rate, + dst_bufs, switchable_ctx, skip_hor, skip_ver); + } else { + // Use full interpolation filter search + uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK; + // REG_REG filter type is evaluated beforehand, so loop is repeated over + // REG_SMOOTH to SHARP_SHARP for full interpolation filter search + reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); + find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd, + &rd_stats_luma, &rd_stats, switchable_rate, + dst_bufs, switchable_ctx, + (skip_hor & skip_ver), allowed_interp_mask, 0); + } + } else { + // Evaluate non-dual interp filters + find_best_non_dual_interp_filter( + x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats, + switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor); + } + swap_dst_buf(xd, dst_bufs, num_planes); + // Recompute final MC data if required + if (x->recalc_luma_mc_data == 1) { + // Recomputing final luma MC data is required only if the same was skipped + // in either of the directions Condition below is necessary, but not + // sufficient + assert((skip_hor == 1) || (skip_ver == 1)); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, + AOM_PLANE_Y, AOM_PLANE_Y); + } + x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); + + // save search results + if (cpi->sf.interp_sf.use_interp_filter) { + assert(match_found_idx == -1); + args->interp_filter_stats_idx = save_interp_filter_search_stat( + mbmi, *rd, x->pred_sse[ref_frame], args->interp_filter_stats, + args->interp_filter_stats_idx); + } + return 0; +} diff --git a/media/libaom/src/av1/encoder/interp_search.h b/media/libaom/src/av1/encoder/interp_search.h new file mode 100644 index 0000000000..401e14f5bc --- /dev/null +++ b/media/libaom/src/av1/encoder/interp_search.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, 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_INTERP_FILTER_SEARCH_H_ +#define AOM_AV1_ENCODER_INTERP_FILTER_SEARCH_H_ + +#include "av1/encoder/block.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/rdopt_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_INTERP_FILTER_STATS 128 +#define DUAL_FILTER_SET_SIZE (SWITCHABLE_FILTERS * SWITCHABLE_FILTERS) + +typedef struct { + int_interpfilters filters; + int_mv mv[2]; + int8_t ref_frames[2]; + COMPOUND_TYPE comp_type; + int compound_idx; + int64_t rd; + unsigned int pred_sse; +} INTERPOLATION_FILTER_STATS; + +typedef struct { + // OBMC secondary prediction buffers and respective strides + uint8_t *above_pred_buf[MAX_MB_PLANE]; + int above_pred_stride[MAX_MB_PLANE]; + uint8_t *left_pred_buf[MAX_MB_PLANE]; + int left_pred_stride[MAX_MB_PLANE]; + int_mv (*single_newmv)[REF_FRAMES]; + // Pointer to array of motion vectors to use for each ref and their rates + // Should point to first of 2 arrays in 2D array + int (*single_newmv_rate)[REF_FRAMES]; + int (*single_newmv_valid)[REF_FRAMES]; + // Pointer to array of predicted rate-distortion + // Should point to first of 2 arrays in 2D array + int64_t (*modelled_rd)[MAX_REF_MV_SEARCH][REF_FRAMES]; + int ref_frame_cost; + int single_comp_cost; + int64_t (*simple_rd)[MAX_REF_MV_SEARCH][REF_FRAMES]; + int skip_motion_mode; + INTERINTRA_MODE *inter_intra_mode; + int single_ref_first_pass; + SimpleRDState *simple_rd_state; + // [comp_idx][saved stat_idx] + INTERPOLATION_FILTER_STATS interp_filter_stats[MAX_INTERP_FILTER_STATS]; + int interp_filter_stats_idx; +} HandleInterModeArgs; + +static const int_interpfilters filter_sets[DUAL_FILTER_SET_SIZE] = { + { 0x00000000 }, { 0x00010000 }, { 0x00020000 }, // y = 0 + { 0x00000001 }, { 0x00010001 }, { 0x00020001 }, // y = 1 + { 0x00000002 }, { 0x00010002 }, { 0x00020002 }, // y = 2 +}; + +int av1_find_interp_filter_match( + MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi, + const InterpFilter assign_filter, const int need_search, + INTERPOLATION_FILTER_STATS *interp_filter_stats, + int interp_filter_stats_idx); + +int64_t av1_interpolation_filter_search( + MACROBLOCK *const x, const AV1_COMP *const cpi, + const TileDataEnc *tile_data, BLOCK_SIZE bsize, + const BUFFER_SET *const tmp_dst, const BUFFER_SET *const orig_dst, + int64_t *const rd, int *const switchable_rate, int *skip_build_pred, + HandleInterModeArgs *args, int64_t ref_best_rd); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_INTERP_FILTER_SEARCH_H_ diff --git a/media/libaom/src/av1/encoder/intra_mode_search.c b/media/libaom/src/av1/encoder/intra_mode_search.c new file mode 100644 index 0000000000..43192a9452 --- /dev/null +++ b/media/libaom/src/av1/encoder/intra_mode_search.c @@ -0,0 +1,2132 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "av1/encoder/intra_mode_search.h" +#include "av1/encoder/model_rd.h" +#include "av1/encoder/palette.h" +#include "av1/common/pred_common.h" +#include "av1/common/reconintra.h" +#include "av1/encoder/tx_search.h" + +static const PREDICTION_MODE intra_rd_search_mode_order[INTRA_MODES] = { + DC_PRED, H_PRED, V_PRED, SMOOTH_PRED, PAETH_PRED, + SMOOTH_V_PRED, SMOOTH_H_PRED, D135_PRED, D203_PRED, D157_PRED, + D67_PRED, D113_PRED, D45_PRED, +}; + +static const UV_PREDICTION_MODE uv_rd_search_mode_order[UV_INTRA_MODES] = { + UV_DC_PRED, UV_CFL_PRED, UV_H_PRED, UV_V_PRED, + UV_SMOOTH_PRED, UV_PAETH_PRED, UV_SMOOTH_V_PRED, UV_SMOOTH_H_PRED, + UV_D135_PRED, UV_D203_PRED, UV_D157_PRED, UV_D67_PRED, + UV_D113_PRED, UV_D45_PRED, +}; + +#define BINS 32 +static const float intra_hog_model_bias[DIRECTIONAL_MODES] = { + 0.450578f, 0.695518f, -0.717944f, -0.639894f, + -0.602019f, -0.453454f, 0.055857f, -0.465480f, +}; + +static const float intra_hog_model_weights[BINS * DIRECTIONAL_MODES] = { + -3.076402f, -3.757063f, -3.275266f, -3.180665f, -3.452105f, -3.216593f, + -2.871212f, -3.134296f, -1.822324f, -2.401411f, -1.541016f, -1.195322f, + -0.434156f, 0.322868f, 2.260546f, 3.368715f, 3.989290f, 3.308487f, + 2.277893f, 0.923793f, 0.026412f, -0.385174f, -0.718622f, -1.408867f, + -1.050558f, -2.323941f, -2.225827f, -2.585453f, -3.054283f, -2.875087f, + -2.985709f, -3.447155f, 3.758139f, 3.204353f, 2.170998f, 0.826587f, + -0.269665f, -0.702068f, -1.085776f, -2.175249f, -1.623180f, -2.975142f, + -2.779629f, -3.190799f, -3.521900f, -3.375480f, -3.319355f, -3.897389f, + -3.172334f, -3.594528f, -2.879132f, -2.547777f, -2.921023f, -2.281844f, + -1.818988f, -2.041771f, -0.618268f, -1.396458f, -0.567153f, -0.285868f, + -0.088058f, 0.753494f, 2.092413f, 3.215266f, -3.300277f, -2.748658f, + -2.315784f, -2.423671f, -2.257283f, -2.269583f, -2.196660f, -2.301076f, + -2.646516f, -2.271319f, -2.254366f, -2.300102f, -2.217960f, -2.473300f, + -2.116866f, -2.528246f, -3.314712f, -1.701010f, -0.589040f, -0.088077f, + 0.813112f, 1.702213f, 2.653045f, 3.351749f, 3.243554f, 3.199409f, + 2.437856f, 1.468854f, 0.533039f, -0.099065f, -0.622643f, -2.200732f, + -4.228861f, -2.875263f, -1.273956f, -0.433280f, 0.803771f, 1.975043f, + 3.179528f, 3.939064f, 3.454379f, 3.689386f, 3.116411f, 1.970991f, + 0.798406f, -0.628514f, -1.252546f, -2.825176f, -4.090178f, -3.777448f, + -3.227314f, -3.479403f, -3.320569f, -3.159372f, -2.729202f, -2.722341f, + -3.054913f, -2.742923f, -2.612703f, -2.662632f, -2.907314f, -3.117794f, + -3.102660f, -3.970972f, -4.891357f, -3.935582f, -3.347758f, -2.721924f, + -2.219011f, -1.702391f, -0.866529f, -0.153743f, 0.107733f, 1.416882f, + 2.572884f, 3.607755f, 3.974820f, 3.997783f, 2.970459f, 0.791687f, + -1.478921f, -1.228154f, -1.216955f, -1.765932f, -1.951003f, -1.985301f, + -1.975881f, -1.985593f, -2.422371f, -2.419978f, -2.531288f, -2.951853f, + -3.071380f, -3.277027f, -3.373539f, -4.462010f, -0.967888f, 0.805524f, + 2.794130f, 3.685984f, 3.745195f, 3.252444f, 2.316108f, 1.399146f, + -0.136519f, -0.162811f, -1.004357f, -1.667911f, -1.964662f, -2.937579f, + -3.019533f, -3.942766f, -5.102767f, -3.882073f, -3.532027f, -3.451956f, + -2.944015f, -2.643064f, -2.529872f, -2.077290f, -2.809965f, -1.803734f, + -1.783593f, -1.662585f, -1.415484f, -1.392673f, -0.788794f, -1.204819f, + -1.998864f, -1.182102f, -0.892110f, -1.317415f, -1.359112f, -1.522867f, + -1.468552f, -1.779072f, -2.332959f, -2.160346f, -2.329387f, -2.631259f, + -2.744936f, -3.052494f, -2.787363f, -3.442548f, -4.245075f, -3.032172f, + -2.061609f, -1.768116f, -1.286072f, -0.706587f, -0.192413f, 0.386938f, + 0.716997f, 1.481393f, 2.216702f, 2.737986f, 3.109809f, 3.226084f, + 2.490098f, -0.095827f, -3.864816f, -3.507248f, -3.128925f, -2.908251f, + -2.883836f, -2.881411f, -2.524377f, -2.624478f, -2.399573f, -2.367718f, + -1.918255f, -1.926277f, -1.694584f, -1.723790f, -0.966491f, -1.183115f, + -1.430687f, 0.872896f, 2.766550f, 3.610080f, 3.578041f, 3.334928f, + 2.586680f, 1.895721f, 1.122195f, 0.488519f, -0.140689f, -0.799076f, + -1.222860f, -1.502437f, -1.900969f, -3.206816f, +}; + +static void generate_hog(const uint8_t *src, int stride, int rows, int cols, + float *hist) { + const float step = (float)PI / BINS; + float total = 0.1f; + src += stride; + for (int r = 1; r < rows - 1; ++r) { + for (int c = 1; c < cols - 1; ++c) { + const uint8_t *above = &src[c - stride]; + const uint8_t *below = &src[c + stride]; + const uint8_t *left = &src[c - 1]; + const uint8_t *right = &src[c + 1]; + // Calculate gradient using Sobel fitlers. + const int dx = (right[-stride] + 2 * right[0] + right[stride]) - + (left[-stride] + 2 * left[0] + left[stride]); + const int dy = (below[-1] + 2 * below[0] + below[1]) - + (above[-1] + 2 * above[0] + above[1]); + if (dx == 0 && dy == 0) continue; + const int temp = abs(dx) + abs(dy); + if (!temp) continue; + total += temp; + if (dx == 0) { + hist[0] += temp / 2; + hist[BINS - 1] += temp / 2; + } else { + const float angle = atanf(dy * 1.0f / dx); + int idx = (int)roundf(angle / step) + BINS / 2; + idx = AOMMIN(idx, BINS - 1); + idx = AOMMAX(idx, 0); + hist[idx] += temp; + } + } + src += stride; + } + + for (int i = 0; i < BINS; ++i) hist[i] /= total; +} + +static void generate_hog_hbd(const uint8_t *src8, int stride, int rows, + int cols, float *hist) { + const float step = (float)PI / BINS; + float total = 0.1f; + uint16_t *src = CONVERT_TO_SHORTPTR(src8); + src += stride; + for (int r = 1; r < rows - 1; ++r) { + for (int c = 1; c < cols - 1; ++c) { + const uint16_t *above = &src[c - stride]; + const uint16_t *below = &src[c + stride]; + const uint16_t *left = &src[c - 1]; + const uint16_t *right = &src[c + 1]; + // Calculate gradient using Sobel fitlers. + const int dx = (right[-stride] + 2 * right[0] + right[stride]) - + (left[-stride] + 2 * left[0] + left[stride]); + const int dy = (below[-1] + 2 * below[0] + below[1]) - + (above[-1] + 2 * above[0] + above[1]); + if (dx == 0 && dy == 0) continue; + const int temp = abs(dx) + abs(dy); + if (!temp) continue; + total += temp; + if (dx == 0) { + hist[0] += temp / 2; + hist[BINS - 1] += temp / 2; + } else { + const float angle = atanf(dy * 1.0f / dx); + int idx = (int)roundf(angle / step) + BINS / 2; + idx = AOMMIN(idx, BINS - 1); + idx = AOMMAX(idx, 0); + hist[idx] += temp; + } + } + src += stride; + } + + for (int i = 0; i < BINS; ++i) hist[i] /= total; +} + +static void prune_intra_mode_with_hog(const MACROBLOCK *x, BLOCK_SIZE bsize, + float th, + uint8_t *directional_mode_skip_mask) { + aom_clear_system_state(); + + const int bh = block_size_high[bsize]; + const int bw = block_size_wide[bsize]; + const MACROBLOCKD *xd = &x->e_mbd; + const int rows = + (xd->mb_to_bottom_edge >= 0) ? bh : (xd->mb_to_bottom_edge >> 3) + bh; + const int cols = + (xd->mb_to_right_edge >= 0) ? bw : (xd->mb_to_right_edge >> 3) + bw; + const int src_stride = x->plane[0].src.stride; + const uint8_t *src = x->plane[0].src.buf; + float hist[BINS] = { 0.0f }; + if (is_cur_buf_hbd(xd)) { + generate_hog_hbd(src, src_stride, rows, cols, hist); + } else { + generate_hog(src, src_stride, rows, cols, hist); + } + + for (int i = 0; i < DIRECTIONAL_MODES; ++i) { + float this_score = intra_hog_model_bias[i]; + const float *weights = &intra_hog_model_weights[i * BINS]; + for (int j = 0; j < BINS; ++j) { + this_score += weights[j] * hist[j]; + } + if (this_score < th) directional_mode_skip_mask[i + 1] = 1; + } + + aom_clear_system_state(); +} + +#undef BINS + +// Model based RD estimation for luma intra blocks. +static int64_t intra_model_yrd(const AV1_COMP *const cpi, MACROBLOCK *const x, + BLOCK_SIZE bsize, int mode_cost) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + RD_STATS this_rd_stats; + int row, col; + int64_t temp_sse, this_rd; + TX_SIZE tx_size = tx_size_from_tx_mode(bsize, x->tx_mode_search_type); + const int stepr = tx_size_high_unit[tx_size]; + const int stepc = tx_size_wide_unit[tx_size]; + const int max_blocks_wide = max_block_wide(xd, bsize, 0); + const int max_blocks_high = max_block_high(xd, bsize, 0); + mbmi->tx_size = tx_size; + // Prediction. + for (row = 0; row < max_blocks_high; row += stepr) { + for (col = 0; col < max_blocks_wide; col += stepc) { + av1_predict_intra_block_facade(cm, xd, 0, col, row, tx_size); + } + } + // RD estimation. + model_rd_sb_fn[cpi->sf.rt_sf.use_simple_rd_model ? MODELRD_LEGACY + : MODELRD_TYPE_INTRA]( + cpi, bsize, x, xd, 0, 0, &this_rd_stats.rate, &this_rd_stats.dist, + &this_rd_stats.skip, &temp_sse, NULL, NULL, NULL); + if (av1_is_directional_mode(mbmi->mode) && av1_use_angle_delta(bsize)) { + mode_cost += + x->angle_delta_cost[mbmi->mode - V_PRED] + [MAX_ANGLE_DELTA + mbmi->angle_delta[PLANE_TYPE_Y]]; + } + if (mbmi->mode == DC_PRED && + av1_filter_intra_allowed_bsize(cm, mbmi->sb_type)) { + if (mbmi->filter_intra_mode_info.use_filter_intra) { + const int mode = mbmi->filter_intra_mode_info.filter_intra_mode; + mode_cost += x->filter_intra_cost[mbmi->sb_type][1] + + x->filter_intra_mode_cost[mode]; + } else { + mode_cost += x->filter_intra_cost[mbmi->sb_type][0]; + } + } + this_rd = + RDCOST(x->rdmult, this_rd_stats.rate + mode_cost, this_rd_stats.dist); + return this_rd; +} + +// Update the intra model yrd and prune the current mode if the new estimate +// y_rd > 1.5 * best_model_rd. +static AOM_INLINE int model_intra_yrd_and_prune(const AV1_COMP *const cpi, + MACROBLOCK *x, BLOCK_SIZE bsize, + int mode_info_cost, + int64_t *best_model_rd) { + const int64_t this_model_rd = intra_model_yrd(cpi, x, bsize, mode_info_cost); + if (*best_model_rd != INT64_MAX && + this_model_rd > *best_model_rd + (*best_model_rd >> 1)) { + return 1; + } else if (this_model_rd < *best_model_rd) { + *best_model_rd = this_model_rd; + } + return 0; +} + +// Run RD calculation with given luma intra prediction angle., and return +// the RD cost. Update the best mode info. if the RD cost is the best so far. +static int64_t calc_rd_given_intra_angle( + const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int mode_cost, + int64_t best_rd_in, int8_t angle_delta, int max_angle_delta, int *rate, + RD_STATS *rd_stats, int *best_angle_delta, TX_SIZE *best_tx_size, + int64_t *best_rd, int64_t *best_model_rd, uint8_t *best_tx_type_map, + uint8_t *best_blk_skip, int skip_model_rd) { + RD_STATS tokenonly_rd_stats; + int64_t this_rd; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + const int n4 = bsize_to_num_blk(bsize); + assert(!is_inter_block(mbmi)); + mbmi->angle_delta[PLANE_TYPE_Y] = angle_delta; + if (!skip_model_rd) { + if (model_intra_yrd_and_prune(cpi, x, bsize, mode_cost, best_model_rd)) { + return INT64_MAX; + } + } + av1_pick_uniform_tx_size_type_yrd(cpi, x, &tokenonly_rd_stats, bsize, + best_rd_in); + if (tokenonly_rd_stats.rate == INT_MAX) return INT64_MAX; + + int this_rate = + mode_cost + tokenonly_rd_stats.rate + + x->angle_delta_cost[mbmi->mode - V_PRED][max_angle_delta + angle_delta]; + this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + + if (this_rd < *best_rd) { + memcpy(best_blk_skip, x->blk_skip, sizeof(best_blk_skip[0]) * n4); + av1_copy_array(best_tx_type_map, xd->tx_type_map, n4); + *best_rd = this_rd; + *best_angle_delta = mbmi->angle_delta[PLANE_TYPE_Y]; + *best_tx_size = mbmi->tx_size; + *rate = this_rate; + rd_stats->rate = tokenonly_rd_stats.rate; + rd_stats->dist = tokenonly_rd_stats.dist; + rd_stats->skip = tokenonly_rd_stats.skip; + } + return this_rd; +} + +static INLINE int write_uniform_cost(int n, int v) { + const int l = get_unsigned_bits(n); + const int m = (1 << l) - n; + if (l == 0) return 0; + if (v < m) + return av1_cost_literal(l - 1); + else + return av1_cost_literal(l); +} + +// Return the rate cost for luma prediction mode info. of intra blocks. +static int intra_mode_info_cost_y(const AV1_COMP *cpi, const MACROBLOCK *x, + const MB_MODE_INFO *mbmi, BLOCK_SIZE bsize, + int mode_cost) { + int total_rate = mode_cost; + const int use_palette = mbmi->palette_mode_info.palette_size[0] > 0; + const int use_filter_intra = mbmi->filter_intra_mode_info.use_filter_intra; + const int use_intrabc = mbmi->use_intrabc; + // Can only activate one mode. + assert(((mbmi->mode != DC_PRED) + use_palette + use_intrabc + + use_filter_intra) <= 1); + const int try_palette = av1_allow_palette( + cpi->common.features.allow_screen_content_tools, mbmi->sb_type); + if (try_palette && mbmi->mode == DC_PRED) { + const MACROBLOCKD *xd = &x->e_mbd; + const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); + const int mode_ctx = av1_get_palette_mode_ctx(xd); + total_rate += x->palette_y_mode_cost[bsize_ctx][mode_ctx][use_palette]; + if (use_palette) { + const uint8_t *const color_map = xd->plane[0].color_index_map; + int block_width, block_height, rows, cols; + av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, + &cols); + const int plt_size = mbmi->palette_mode_info.palette_size[0]; + int palette_mode_cost = + x->palette_y_size_cost[bsize_ctx][plt_size - PALETTE_MIN_SIZE] + + write_uniform_cost(plt_size, color_map[0]); + uint16_t color_cache[2 * PALETTE_MAX_SIZE]; + const int n_cache = av1_get_palette_cache(xd, 0, color_cache); + palette_mode_cost += + av1_palette_color_cost_y(&mbmi->palette_mode_info, color_cache, + n_cache, cpi->common.seq_params.bit_depth); + palette_mode_cost += + av1_cost_color_map(x, 0, bsize, mbmi->tx_size, PALETTE_MAP); + total_rate += palette_mode_cost; + } + } + if (av1_filter_intra_allowed(&cpi->common, mbmi)) { + total_rate += x->filter_intra_cost[mbmi->sb_type][use_filter_intra]; + if (use_filter_intra) { + total_rate += x->filter_intra_mode_cost[mbmi->filter_intra_mode_info + .filter_intra_mode]; + } + } + if (av1_is_directional_mode(mbmi->mode)) { + if (av1_use_angle_delta(bsize)) { + total_rate += x->angle_delta_cost[mbmi->mode - V_PRED] + [MAX_ANGLE_DELTA + + mbmi->angle_delta[PLANE_TYPE_Y]]; + } + } + if (av1_allow_intrabc(&cpi->common)) + total_rate += x->intrabc_cost[use_intrabc]; + return total_rate; +} + +// Return the rate cost for chroma prediction mode info. of intra blocks. +static int intra_mode_info_cost_uv(const AV1_COMP *cpi, const MACROBLOCK *x, + const MB_MODE_INFO *mbmi, BLOCK_SIZE bsize, + int mode_cost) { + int total_rate = mode_cost; + const int use_palette = mbmi->palette_mode_info.palette_size[1] > 0; + const UV_PREDICTION_MODE mode = mbmi->uv_mode; + // Can only activate one mode. + assert(((mode != UV_DC_PRED) + use_palette + mbmi->use_intrabc) <= 1); + + const int try_palette = av1_allow_palette( + cpi->common.features.allow_screen_content_tools, mbmi->sb_type); + if (try_palette && mode == UV_DC_PRED) { + const PALETTE_MODE_INFO *pmi = &mbmi->palette_mode_info; + total_rate += + x->palette_uv_mode_cost[pmi->palette_size[0] > 0][use_palette]; + if (use_palette) { + const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); + const int plt_size = pmi->palette_size[1]; + const MACROBLOCKD *xd = &x->e_mbd; + const uint8_t *const color_map = xd->plane[1].color_index_map; + int palette_mode_cost = + x->palette_uv_size_cost[bsize_ctx][plt_size - PALETTE_MIN_SIZE] + + write_uniform_cost(plt_size, color_map[0]); + uint16_t color_cache[2 * PALETTE_MAX_SIZE]; + const int n_cache = av1_get_palette_cache(xd, 1, color_cache); + palette_mode_cost += av1_palette_color_cost_uv( + pmi, color_cache, n_cache, cpi->common.seq_params.bit_depth); + palette_mode_cost += + av1_cost_color_map(x, 1, bsize, mbmi->tx_size, PALETTE_MAP); + total_rate += palette_mode_cost; + } + } + if (av1_is_directional_mode(get_uv_mode(mode))) { + if (av1_use_angle_delta(bsize)) { + total_rate += + x->angle_delta_cost[mode - V_PRED][mbmi->angle_delta[PLANE_TYPE_UV] + + MAX_ANGLE_DELTA]; + } + } + return total_rate; +} + +// Return 1 if an filter intra mode is selected; return 0 otherwise. +static int rd_pick_filter_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, + BLOCK_SIZE bsize, int mode_cost, + int64_t *best_rd, int64_t *best_model_rd, + PICK_MODE_CONTEXT *ctx) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + int filter_intra_selected_flag = 0; + FILTER_INTRA_MODE mode; + TX_SIZE best_tx_size = TX_8X8; + FILTER_INTRA_MODE_INFO filter_intra_mode_info; + uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; + (void)ctx; + av1_zero(filter_intra_mode_info); + mbmi->filter_intra_mode_info.use_filter_intra = 1; + mbmi->mode = DC_PRED; + mbmi->palette_mode_info.palette_size[0] = 0; + + for (mode = 0; mode < FILTER_INTRA_MODES; ++mode) { + int64_t this_rd; + RD_STATS tokenonly_rd_stats; + mbmi->filter_intra_mode_info.filter_intra_mode = mode; + + if (model_intra_yrd_and_prune(cpi, x, bsize, mode_cost, best_model_rd)) { + continue; + } + av1_pick_uniform_tx_size_type_yrd(cpi, x, &tokenonly_rd_stats, bsize, + *best_rd); + if (tokenonly_rd_stats.rate == INT_MAX) continue; + const int this_rate = + tokenonly_rd_stats.rate + + intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); + this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + + // Collect mode stats for multiwinner mode processing + const int txfm_search_done = 1; + store_winner_mode_stats( + &cpi->common, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + txfm_search_done); + if (this_rd < *best_rd) { + *best_rd = this_rd; + best_tx_size = mbmi->tx_size; + filter_intra_mode_info = mbmi->filter_intra_mode_info; + av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + *rate = this_rate; + *rate_tokenonly = tokenonly_rd_stats.rate; + *distortion = tokenonly_rd_stats.dist; + *skippable = tokenonly_rd_stats.skip; + filter_intra_selected_flag = 1; + } + } + + if (filter_intra_selected_flag) { + mbmi->mode = DC_PRED; + mbmi->tx_size = best_tx_size; + mbmi->filter_intra_mode_info = filter_intra_mode_info; + av1_copy_array(ctx->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); + return 1; + } else { + return 0; + } +} + +int av1_count_colors(const uint8_t *src, int stride, int rows, int cols, + int *val_count) { + const int max_pix_val = 1 << 8; + memset(val_count, 0, max_pix_val * sizeof(val_count[0])); + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + const int this_val = src[r * stride + c]; + assert(this_val < max_pix_val); + ++val_count[this_val]; + } + } + int n = 0; + for (int i = 0; i < max_pix_val; ++i) { + if (val_count[i]) ++n; + } + return n; +} + +int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols, + int bit_depth, int *val_count) { + assert(bit_depth <= 12); + const int max_pix_val = 1 << bit_depth; + const uint16_t *src = CONVERT_TO_SHORTPTR(src8); + memset(val_count, 0, max_pix_val * sizeof(val_count[0])); + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + const int this_val = src[r * stride + c]; + assert(this_val < max_pix_val); + if (this_val >= max_pix_val) return 0; + ++val_count[this_val]; + } + } + int n = 0; + for (int i = 0; i < max_pix_val; ++i) { + if (val_count[i]) ++n; + } + return n; +} + +// Extends 'color_map' array from 'orig_width x orig_height' to 'new_width x +// new_height'. Extra rows and columns are filled in by copying last valid +// row/column. +static AOM_INLINE void extend_palette_color_map(uint8_t *const color_map, + int orig_width, int orig_height, + int new_width, int new_height) { + int j; + assert(new_width >= orig_width); + assert(new_height >= orig_height); + if (new_width == orig_width && new_height == orig_height) return; + + for (j = orig_height - 1; j >= 0; --j) { + memmove(color_map + j * new_width, color_map + j * orig_width, orig_width); + // Copy last column to extra columns. + memset(color_map + j * new_width + orig_width, + color_map[j * new_width + orig_width - 1], new_width - orig_width); + } + // Copy last row to extra rows. + for (j = orig_height; j < new_height; ++j) { + memcpy(color_map + j * new_width, color_map + (orig_height - 1) * new_width, + new_width); + } +} + +// Bias toward using colors in the cache. +// TODO(huisu): Try other schemes to improve compression. +static AOM_INLINE void optimize_palette_colors(uint16_t *color_cache, + int n_cache, int n_colors, + int stride, int *centroids) { + if (n_cache <= 0) return; + for (int i = 0; i < n_colors * stride; i += stride) { + int min_diff = abs(centroids[i] - (int)color_cache[0]); + int idx = 0; + for (int j = 1; j < n_cache; ++j) { + const int this_diff = abs(centroids[i] - color_cache[j]); + if (this_diff < min_diff) { + min_diff = this_diff; + idx = j; + } + } + if (min_diff <= 1) centroids[i] = color_cache[idx]; + } +} + +// Given the base colors as specified in centroids[], calculate the RD cost +// of palette mode. +static AOM_INLINE void palette_rd_y( + const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, + BLOCK_SIZE bsize, int dc_mode_cost, const int *data, int *centroids, int n, + uint16_t *color_cache, int n_cache, MB_MODE_INFO *best_mbmi, + uint8_t *best_palette_color_map, int64_t *best_rd, int64_t *best_model_rd, + int *rate, int *rate_tokenonly, int64_t *distortion, int *skippable, + int *beat_best_rd, PICK_MODE_CONTEXT *ctx, uint8_t *blk_skip, + uint8_t *tx_type_map, int *beat_best_pallette_rd) { + optimize_palette_colors(color_cache, n_cache, n, 1, centroids); + const int num_unique_colors = av1_remove_duplicates(centroids, n); + if (num_unique_colors < PALETTE_MIN_SIZE) { + // Too few unique colors to create a palette. And DC_PRED will work + // well for that case anyway. So skip. + return; + } + PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + if (cpi->common.seq_params.use_highbitdepth) { + for (int i = 0; i < num_unique_colors; ++i) { + pmi->palette_colors[i] = clip_pixel_highbd( + (int)centroids[i], cpi->common.seq_params.bit_depth); + } + } else { + for (int i = 0; i < num_unique_colors; ++i) { + pmi->palette_colors[i] = clip_pixel(centroids[i]); + } + } + pmi->palette_size[0] = num_unique_colors; + MACROBLOCKD *const xd = &x->e_mbd; + uint8_t *const color_map = xd->plane[0].color_index_map; + int block_width, block_height, rows, cols; + av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, + &cols); + av1_calc_indices(data, centroids, color_map, rows * cols, num_unique_colors, + 1); + extend_palette_color_map(color_map, cols, rows, block_width, block_height); + + const int palette_mode_cost = + intra_mode_info_cost_y(cpi, x, mbmi, bsize, dc_mode_cost); + if (model_intra_yrd_and_prune(cpi, x, bsize, palette_mode_cost, + best_model_rd)) { + return; + } + + RD_STATS tokenonly_rd_stats; + av1_pick_uniform_tx_size_type_yrd(cpi, x, &tokenonly_rd_stats, bsize, + *best_rd); + if (tokenonly_rd_stats.rate == INT_MAX) return; + int this_rate = tokenonly_rd_stats.rate + palette_mode_cost; + int64_t this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(mbmi->sb_type)) { + tokenonly_rd_stats.rate -= tx_size_cost(x, bsize, mbmi->tx_size); + } + // Collect mode stats for multiwinner mode processing + const int txfm_search_done = 1; + store_winner_mode_stats( + &cpi->common, x, mbmi, NULL, NULL, NULL, THR_DC, color_map, bsize, + this_rd, cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + txfm_search_done); + if (this_rd < *best_rd) { + *best_rd = this_rd; + // Setting beat_best_rd flag because current mode rd is better than best_rd. + // This flag need to be updated only for palette evaluation in key frames + if (beat_best_rd) *beat_best_rd = 1; + memcpy(best_palette_color_map, color_map, + block_width * block_height * sizeof(color_map[0])); + *best_mbmi = *mbmi; + memcpy(blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + av1_copy_array(tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + if (rate) *rate = this_rate; + if (rate_tokenonly) *rate_tokenonly = tokenonly_rd_stats.rate; + if (distortion) *distortion = tokenonly_rd_stats.dist; + if (skippable) *skippable = tokenonly_rd_stats.skip; + if (beat_best_pallette_rd) *beat_best_pallette_rd = 1; + } +} + +static AOM_INLINE int perform_top_color_coarse_palette_search( + const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, + BLOCK_SIZE bsize, int dc_mode_cost, const int *data, + const int *const top_colors, int start_n, int end_n, int step_size, + uint16_t *color_cache, int n_cache, MB_MODE_INFO *best_mbmi, + uint8_t *best_palette_color_map, int64_t *best_rd, int64_t *best_model_rd, + int *rate, int *rate_tokenonly, int64_t *distortion, int *skippable, + int *beat_best_rd, PICK_MODE_CONTEXT *ctx, uint8_t *best_blk_skip, + uint8_t *tx_type_map) { + int centroids[PALETTE_MAX_SIZE]; + int n = start_n; + int top_color_winner = end_n + 1; + while (1) { + int beat_best_pallette_rd = 0; + for (int i = 0; i < n; ++i) centroids[i] = top_colors[i]; + palette_rd_y(cpi, x, mbmi, bsize, dc_mode_cost, data, centroids, n, + color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, + skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map, + &beat_best_pallette_rd); + // Break if current palette colors is not winning + if (beat_best_pallette_rd) top_color_winner = n; + n += step_size; + if (n > end_n) break; + } + return top_color_winner; +} + +static AOM_INLINE int perform_k_means_coarse_palette_search( + const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, + BLOCK_SIZE bsize, int dc_mode_cost, const int *data, int lb, int ub, + int start_n, int end_n, int step_size, uint16_t *color_cache, int n_cache, + MB_MODE_INFO *best_mbmi, uint8_t *best_palette_color_map, int64_t *best_rd, + int64_t *best_model_rd, int *rate, int *rate_tokenonly, int64_t *distortion, + int *skippable, int *beat_best_rd, PICK_MODE_CONTEXT *ctx, + uint8_t *best_blk_skip, uint8_t *tx_type_map, uint8_t *color_map, + int data_points) { + int centroids[PALETTE_MAX_SIZE]; + const int max_itr = 50; + int n = start_n; + int k_means_winner = end_n + 1; + while (1) { + int beat_best_pallette_rd = 0; + for (int i = 0; i < n; ++i) { + centroids[i] = lb + (2 * i + 1) * (ub - lb) / n / 2; + } + av1_k_means(data, centroids, color_map, data_points, n, 1, max_itr); + palette_rd_y(cpi, x, mbmi, bsize, dc_mode_cost, data, centroids, n, + color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, + skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map, + &beat_best_pallette_rd); + // Break if current palette colors is not winning + if (beat_best_pallette_rd) k_means_winner = n; + n += step_size; + if (n > end_n) break; + } + return k_means_winner; +} + +// Perform palette search for top colors from minimum palette colors (/maximum) +// with a step-size of 1 (/-1) +static AOM_INLINE int perform_top_color_palette_search( + const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, + BLOCK_SIZE bsize, int dc_mode_cost, const int *data, int *top_colors, + int start_n, int end_n, int step_size, uint16_t *color_cache, int n_cache, + MB_MODE_INFO *best_mbmi, uint8_t *best_palette_color_map, int64_t *best_rd, + int64_t *best_model_rd, int *rate, int *rate_tokenonly, int64_t *distortion, + int *skippable, int *beat_best_rd, PICK_MODE_CONTEXT *ctx, + uint8_t *best_blk_skip, uint8_t *tx_type_map) { + int centroids[PALETTE_MAX_SIZE]; + int n = start_n; + assert((step_size == -1) || (step_size == 1) || (step_size == 0) || + (step_size == 2)); + assert(IMPLIES(step_size == -1, start_n > end_n)); + assert(IMPLIES(step_size == 1, start_n < end_n)); + while (1) { + int beat_best_pallette_rd = 0; + for (int i = 0; i < n; ++i) centroids[i] = top_colors[i]; + palette_rd_y(cpi, x, mbmi, bsize, dc_mode_cost, data, centroids, n, + color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, + skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map, + &beat_best_pallette_rd); + // Break if current palette colors is not winning + if ((cpi->sf.intra_sf.prune_palette_search_level == 2) && + !beat_best_pallette_rd) + return n; + n += step_size; + if (n == end_n) break; + } + return n; +} +// Perform k-means based palette search from minimum palette colors (/maximum) +// with a step-size of 1 (/-1) +static AOM_INLINE int perform_k_means_palette_search( + const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, + BLOCK_SIZE bsize, int dc_mode_cost, const int *data, int lb, int ub, + int start_n, int end_n, int step_size, uint16_t *color_cache, int n_cache, + MB_MODE_INFO *best_mbmi, uint8_t *best_palette_color_map, int64_t *best_rd, + int64_t *best_model_rd, int *rate, int *rate_tokenonly, int64_t *distortion, + int *skippable, int *beat_best_rd, PICK_MODE_CONTEXT *ctx, + uint8_t *best_blk_skip, uint8_t *tx_type_map, uint8_t *color_map, + int data_points) { + int centroids[PALETTE_MAX_SIZE]; + const int max_itr = 50; + int n = start_n; + assert((step_size == -1) || (step_size == 1) || (step_size == 0) || + (step_size == 2)); + assert(IMPLIES(step_size == -1, start_n > end_n)); + assert(IMPLIES(step_size == 1, start_n < end_n)); + while (1) { + int beat_best_pallette_rd = 0; + for (int i = 0; i < n; ++i) { + centroids[i] = lb + (2 * i + 1) * (ub - lb) / n / 2; + } + av1_k_means(data, centroids, color_map, data_points, n, 1, max_itr); + palette_rd_y(cpi, x, mbmi, bsize, dc_mode_cost, data, centroids, n, + color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, + skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map, + &beat_best_pallette_rd); + // Break if current palette colors is not winning + if ((cpi->sf.intra_sf.prune_palette_search_level == 2) && + !beat_best_pallette_rd) + return n; + n += step_size; + if (n == end_n) break; + } + return n; +} + +#define START_N_STAGE2(x) \ + ((x == PALETTE_MIN_SIZE) ? PALETTE_MIN_SIZE + 1 \ + : AOMMAX(x - 1, PALETTE_MIN_SIZE)); +#define END_N_STAGE2(x, end_n) \ + ((x == end_n) ? x - 1 : AOMMIN(x + 1, PALETTE_MAX_SIZE)); + +static AOM_INLINE void update_start_end_stage_2(int *start_n_stage2, + int *end_n_stage2, + int *step_size_stage2, + int winner, int end_n) { + *start_n_stage2 = START_N_STAGE2(winner); + *end_n_stage2 = END_N_STAGE2(winner, end_n); + *step_size_stage2 = *end_n_stage2 - *start_n_stage2; +} + +// Start index and step size below are chosen to evaluate unique +// candidates in neighbor search, in case a winner candidate is found in +// coarse search. Example, +// 1) 8 colors (end_n = 8): 2,3,4,5,6,7,8. start_n is chosen as 2 and step +// size is chosen as 3. Therefore, coarse search will evaluate 2, 5 and 8. +// If winner is found at 5, then 4 and 6 are evaluated. Similarly, for 2 +// (3) and 8 (7). +// 2) 7 colors (end_n = 7): 2,3,4,5,6,7. If start_n is chosen as 2 (same +// as for 8 colors) then step size should also be 2, to cover all +// candidates. Coarse search will evaluate 2, 4 and 6. If winner is either +// 2 or 4, 3 will be evaluated. Instead, if start_n=3 and step_size=3, +// coarse search will evaluate 3 and 6. For the winner, unique neighbors +// (3: 2,4 or 6: 5,7) would be evaluated. + +// start index for coarse palette search for dominant colors and k-means +static const uint8_t start_n_lookup_table[PALETTE_MAX_SIZE + 1] = { 0, 0, 0, + 3, 3, 2, + 3, 3, 2 }; +// step size for coarse palette search for dominant colors and k-means +static const uint8_t step_size_lookup_table[PALETTE_MAX_SIZE + 1] = { 0, 0, 0, + 3, 3, 3, + 3, 3, 3 }; + +static void rd_pick_palette_intra_sby( + const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, + int dc_mode_cost, MB_MODE_INFO *best_mbmi, uint8_t *best_palette_color_map, + int64_t *best_rd, int64_t *best_model_rd, int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, int *beat_best_rd, + PICK_MODE_CONTEXT *ctx, uint8_t *best_blk_skip, uint8_t *tx_type_map) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + assert(av1_allow_palette(cpi->common.features.allow_screen_content_tools, + bsize)); + + const int src_stride = x->plane[0].src.stride; + const uint8_t *const src = x->plane[0].src.buf; + int block_width, block_height, rows, cols; + av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, + &cols); + const SequenceHeader *const seq_params = &cpi->common.seq_params; + const int is_hbd = seq_params->use_highbitdepth; + const int bit_depth = seq_params->bit_depth; + int count_buf[1 << 12]; // Maximum (1 << 12) color levels. + int colors; + if (is_hbd) { + colors = av1_count_colors_highbd(src, src_stride, rows, cols, bit_depth, + count_buf); + } else { + colors = av1_count_colors(src, src_stride, rows, cols, count_buf); + } + + uint8_t *const color_map = xd->plane[0].color_index_map; + if (colors > 1 && colors <= 64) { + int *const data = x->palette_buffer->kmeans_data_buf; + int centroids[PALETTE_MAX_SIZE]; + int lb, ub; + if (is_hbd) { + int *data_pt = data; + const uint16_t *src_pt = CONVERT_TO_SHORTPTR(src); + lb = ub = src_pt[0]; + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + const int val = src_pt[c]; + data_pt[c] = val; + lb = AOMMIN(lb, val); + ub = AOMMAX(ub, val); + } + src_pt += src_stride; + data_pt += cols; + } + } else { + int *data_pt = data; + const uint8_t *src_pt = src; + lb = ub = src[0]; + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + const int val = src_pt[c]; + data_pt[c] = val; + lb = AOMMIN(lb, val); + ub = AOMMAX(ub, val); + } + src_pt += src_stride; + data_pt += cols; + } + } + + mbmi->mode = DC_PRED; + mbmi->filter_intra_mode_info.use_filter_intra = 0; + + uint16_t color_cache[2 * PALETTE_MAX_SIZE]; + const int n_cache = av1_get_palette_cache(xd, 0, color_cache); + + // Find the dominant colors, stored in top_colors[]. + int top_colors[PALETTE_MAX_SIZE] = { 0 }; + for (int i = 0; i < AOMMIN(colors, PALETTE_MAX_SIZE); ++i) { + int max_count = 0; + for (int j = 0; j < (1 << bit_depth); ++j) { + if (count_buf[j] > max_count) { + max_count = count_buf[j]; + top_colors[i] = j; + } + } + assert(max_count > 0); + count_buf[top_colors[i]] = 0; + } + + // Try the dominant colors directly. + // TODO(huisu@google.com): Try to avoid duplicate computation in cases + // where the dominant colors and the k-means results are similar. + if ((cpi->sf.intra_sf.prune_palette_search_level == 1) && + (colors > PALETTE_MIN_SIZE)) { + const int end_n = AOMMIN(colors, PALETTE_MAX_SIZE); + assert(PALETTE_MAX_SIZE == 8); + assert(PALETTE_MIN_SIZE == 2); + // Choose the start index and step size for coarse search based on number + // of colors + const int start_n = start_n_lookup_table[end_n]; + const int step_size = step_size_lookup_table[end_n]; + // Perform top color coarse palette search to find the winner candidate + const int top_color_winner = perform_top_color_coarse_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, top_colors, start_n, end_n, + step_size, color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, skippable, + beat_best_rd, ctx, best_blk_skip, tx_type_map); + // Evaluate neighbors for the winner color (if winner is found) in the + // above coarse search for dominant colors + if (top_color_winner <= end_n) { + int start_n_stage2, end_n_stage2, step_size_stage2; + update_start_end_stage_2(&start_n_stage2, &end_n_stage2, + &step_size_stage2, top_color_winner, end_n); + // perform finer search for the winner candidate + perform_top_color_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, top_colors, start_n_stage2, + end_n_stage2 + step_size_stage2, step_size_stage2, color_cache, + n_cache, best_mbmi, best_palette_color_map, best_rd, best_model_rd, + rate, rate_tokenonly, distortion, skippable, beat_best_rd, ctx, + best_blk_skip, tx_type_map); + } + // K-means clustering. + // Perform k-means coarse palette search to find the winner candidate + const int k_means_winner = perform_k_means_coarse_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, lb, ub, start_n, end_n, + step_size, color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, skippable, + beat_best_rd, ctx, best_blk_skip, tx_type_map, color_map, + rows * cols); + // Evaluate neighbors for the winner color (if winner is found) in the + // above coarse search for k-means + if (k_means_winner <= end_n) { + int start_n_stage2, end_n_stage2, step_size_stage2; + update_start_end_stage_2(&start_n_stage2, &end_n_stage2, + &step_size_stage2, k_means_winner, end_n); + // perform finer search for the winner candidate + perform_k_means_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, lb, ub, start_n_stage2, + end_n_stage2 + step_size_stage2, step_size_stage2, color_cache, + n_cache, best_mbmi, best_palette_color_map, best_rd, best_model_rd, + rate, rate_tokenonly, distortion, skippable, beat_best_rd, ctx, + best_blk_skip, tx_type_map, color_map, rows * cols); + } + } else { + const int start_n = AOMMIN(colors, PALETTE_MAX_SIZE), + end_n = PALETTE_MIN_SIZE; + // Perform top color palette search from start_n + const int top_color_winner = perform_top_color_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, top_colors, start_n, + end_n - 1, -1, color_cache, n_cache, best_mbmi, + best_palette_color_map, best_rd, best_model_rd, rate, rate_tokenonly, + distortion, skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map); + + if (top_color_winner > end_n) { + // Perform top color palette search in reverse order for the remaining + // colors + perform_top_color_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, top_colors, end_n, + top_color_winner, 1, color_cache, n_cache, best_mbmi, + best_palette_color_map, best_rd, best_model_rd, rate, + rate_tokenonly, distortion, skippable, beat_best_rd, ctx, + best_blk_skip, tx_type_map); + } + // K-means clustering. + if (colors == PALETTE_MIN_SIZE) { + // Special case: These colors automatically become the centroids. + assert(colors == 2); + centroids[0] = lb; + centroids[1] = ub; + palette_rd_y(cpi, x, mbmi, bsize, dc_mode_cost, data, centroids, colors, + color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, + skippable, beat_best_rd, ctx, best_blk_skip, tx_type_map, + NULL); + } else { + // Perform k-means palette search from start_n + const int k_means_winner = perform_k_means_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, lb, ub, start_n, end_n - 1, + -1, color_cache, n_cache, best_mbmi, best_palette_color_map, + best_rd, best_model_rd, rate, rate_tokenonly, distortion, skippable, + beat_best_rd, ctx, best_blk_skip, tx_type_map, color_map, + rows * cols); + if (k_means_winner > end_n) { + // Perform k-means palette search in reverse order for the remaining + // colors + perform_k_means_palette_search( + cpi, x, mbmi, bsize, dc_mode_cost, data, lb, ub, end_n, + k_means_winner, 1, color_cache, n_cache, best_mbmi, + best_palette_color_map, best_rd, best_model_rd, rate, + rate_tokenonly, distortion, skippable, beat_best_rd, ctx, + best_blk_skip, tx_type_map, color_map, rows * cols); + } + } + } + } + + if (best_mbmi->palette_mode_info.palette_size[0] > 0) { + memcpy(color_map, best_palette_color_map, + block_width * block_height * sizeof(best_palette_color_map[0])); + } + *mbmi = *best_mbmi; +} + +static AOM_INLINE void rd_pick_palette_intra_sbuv( + const AV1_COMP *const cpi, MACROBLOCK *x, int dc_mode_cost, + uint8_t *best_palette_color_map, MB_MODE_INFO *const best_mbmi, + int64_t *best_rd, int *rate, int *rate_tokenonly, int64_t *distortion, + int *skippable) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + assert(av1_allow_palette(cpi->common.features.allow_screen_content_tools, + mbmi->sb_type)); + PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + const BLOCK_SIZE bsize = mbmi->sb_type; + const SequenceHeader *const seq_params = &cpi->common.seq_params; + int this_rate; + int64_t this_rd; + int colors_u, colors_v, colors; + const int src_stride = x->plane[1].src.stride; + const uint8_t *const src_u = x->plane[1].src.buf; + const uint8_t *const src_v = x->plane[2].src.buf; + uint8_t *const color_map = xd->plane[1].color_index_map; + RD_STATS tokenonly_rd_stats; + int plane_block_width, plane_block_height, rows, cols; + av1_get_block_dimensions(bsize, 1, xd, &plane_block_width, + &plane_block_height, &rows, &cols); + + mbmi->uv_mode = UV_DC_PRED; + + int count_buf[1 << 12]; // Maximum (1 << 12) color levels. + if (seq_params->use_highbitdepth) { + colors_u = av1_count_colors_highbd(src_u, src_stride, rows, cols, + seq_params->bit_depth, count_buf); + colors_v = av1_count_colors_highbd(src_v, src_stride, rows, cols, + seq_params->bit_depth, count_buf); + } else { + colors_u = av1_count_colors(src_u, src_stride, rows, cols, count_buf); + colors_v = av1_count_colors(src_v, src_stride, rows, cols, count_buf); + } + + uint16_t color_cache[2 * PALETTE_MAX_SIZE]; + const int n_cache = av1_get_palette_cache(xd, 1, color_cache); + + colors = colors_u > colors_v ? colors_u : colors_v; + if (colors > 1 && colors <= 64) { + int r, c, n, i, j; + const int max_itr = 50; + int lb_u, ub_u, val_u; + int lb_v, ub_v, val_v; + int *const data = x->palette_buffer->kmeans_data_buf; + int centroids[2 * PALETTE_MAX_SIZE]; + + uint16_t *src_u16 = CONVERT_TO_SHORTPTR(src_u); + uint16_t *src_v16 = CONVERT_TO_SHORTPTR(src_v); + if (seq_params->use_highbitdepth) { + lb_u = src_u16[0]; + ub_u = src_u16[0]; + lb_v = src_v16[0]; + ub_v = src_v16[0]; + } else { + lb_u = src_u[0]; + ub_u = src_u[0]; + lb_v = src_v[0]; + ub_v = src_v[0]; + } + + for (r = 0; r < rows; ++r) { + for (c = 0; c < cols; ++c) { + if (seq_params->use_highbitdepth) { + val_u = src_u16[r * src_stride + c]; + val_v = src_v16[r * src_stride + c]; + data[(r * cols + c) * 2] = val_u; + data[(r * cols + c) * 2 + 1] = val_v; + } else { + val_u = src_u[r * src_stride + c]; + val_v = src_v[r * src_stride + c]; + data[(r * cols + c) * 2] = val_u; + data[(r * cols + c) * 2 + 1] = val_v; + } + if (val_u < lb_u) + lb_u = val_u; + else if (val_u > ub_u) + ub_u = val_u; + if (val_v < lb_v) + lb_v = val_v; + else if (val_v > ub_v) + ub_v = val_v; + } + } + + for (n = colors > PALETTE_MAX_SIZE ? PALETTE_MAX_SIZE : colors; n >= 2; + --n) { + for (i = 0; i < n; ++i) { + centroids[i * 2] = lb_u + (2 * i + 1) * (ub_u - lb_u) / n / 2; + centroids[i * 2 + 1] = lb_v + (2 * i + 1) * (ub_v - lb_v) / n / 2; + } + av1_k_means(data, centroids, color_map, rows * cols, n, 2, max_itr); + optimize_palette_colors(color_cache, n_cache, n, 2, centroids); + // Sort the U channel colors in ascending order. + for (i = 0; i < 2 * (n - 1); i += 2) { + int min_idx = i; + int min_val = centroids[i]; + for (j = i + 2; j < 2 * n; j += 2) + if (centroids[j] < min_val) min_val = centroids[j], min_idx = j; + if (min_idx != i) { + int temp_u = centroids[i], temp_v = centroids[i + 1]; + centroids[i] = centroids[min_idx]; + centroids[i + 1] = centroids[min_idx + 1]; + centroids[min_idx] = temp_u, centroids[min_idx + 1] = temp_v; + } + } + av1_calc_indices(data, centroids, color_map, rows * cols, n, 2); + extend_palette_color_map(color_map, cols, rows, plane_block_width, + plane_block_height); + pmi->palette_size[1] = n; + for (i = 1; i < 3; ++i) { + for (j = 0; j < n; ++j) { + if (seq_params->use_highbitdepth) + pmi->palette_colors[i * PALETTE_MAX_SIZE + j] = clip_pixel_highbd( + (int)centroids[j * 2 + i - 1], seq_params->bit_depth); + else + pmi->palette_colors[i * PALETTE_MAX_SIZE + j] = + clip_pixel((int)centroids[j * 2 + i - 1]); + } + } + + av1_txfm_uvrd(cpi, x, &tokenonly_rd_stats, bsize, *best_rd); + if (tokenonly_rd_stats.rate == INT_MAX) continue; + this_rate = tokenonly_rd_stats.rate + + intra_mode_info_cost_uv(cpi, x, mbmi, bsize, dc_mode_cost); + this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + if (this_rd < *best_rd) { + *best_rd = this_rd; + *best_mbmi = *mbmi; + memcpy(best_palette_color_map, color_map, + plane_block_width * plane_block_height * + sizeof(best_palette_color_map[0])); + *rate = this_rate; + *distortion = tokenonly_rd_stats.dist; + *rate_tokenonly = tokenonly_rd_stats.rate; + *skippable = tokenonly_rd_stats.skip; + } + } + } + if (best_mbmi->palette_mode_info.palette_size[1] > 0) { + memcpy(color_map, best_palette_color_map, + plane_block_width * plane_block_height * + sizeof(best_palette_color_map[0])); + } +} + +void av1_restore_uv_color_map(const AV1_COMP *const cpi, MACROBLOCK *x) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + const BLOCK_SIZE bsize = mbmi->sb_type; + int src_stride = x->plane[1].src.stride; + const uint8_t *const src_u = x->plane[1].src.buf; + const uint8_t *const src_v = x->plane[2].src.buf; + int *const data = x->palette_buffer->kmeans_data_buf; + int centroids[2 * PALETTE_MAX_SIZE]; + uint8_t *const color_map = xd->plane[1].color_index_map; + int r, c; + const uint16_t *const src_u16 = CONVERT_TO_SHORTPTR(src_u); + const uint16_t *const src_v16 = CONVERT_TO_SHORTPTR(src_v); + int plane_block_width, plane_block_height, rows, cols; + av1_get_block_dimensions(bsize, 1, xd, &plane_block_width, + &plane_block_height, &rows, &cols); + + for (r = 0; r < rows; ++r) { + for (c = 0; c < cols; ++c) { + if (cpi->common.seq_params.use_highbitdepth) { + data[(r * cols + c) * 2] = src_u16[r * src_stride + c]; + data[(r * cols + c) * 2 + 1] = src_v16[r * src_stride + c]; + } else { + data[(r * cols + c) * 2] = src_u[r * src_stride + c]; + data[(r * cols + c) * 2 + 1] = src_v[r * src_stride + c]; + } + } + } + + for (r = 1; r < 3; ++r) { + for (c = 0; c < pmi->palette_size[1]; ++c) { + centroids[c * 2 + r - 1] = pmi->palette_colors[r * PALETTE_MAX_SIZE + c]; + } + } + + av1_calc_indices(data, centroids, color_map, rows * cols, + pmi->palette_size[1], 2); + extend_palette_color_map(color_map, cols, rows, plane_block_width, + plane_block_height); +} + +static AOM_INLINE void choose_intra_uv_mode( + const AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize, + TX_SIZE max_tx_size, int *rate_uv, int *rate_uv_tokenonly, int64_t *dist_uv, + int *skip_uv, UV_PREDICTION_MODE *mode_uv) { + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + // Use an estimated rd for uv_intra based on DC_PRED if the + // appropriate speed flag is set. + init_sbuv_mode(mbmi); + if (!xd->is_chroma_ref) { + *rate_uv = 0; + *rate_uv_tokenonly = 0; + *dist_uv = 0; + *skip_uv = 1; + *mode_uv = UV_DC_PRED; + return; + } + + // Only store reconstructed luma when there's chroma RDO. When there's no + // chroma RDO, the reconstructed luma will be stored in encode_superblock(). + xd->cfl.store_y = store_cfl_required_rdo(cm, x); + if (xd->cfl.store_y) { + // Restore reconstructed luma values. + av1_encode_intra_block_plane(cpi, x, mbmi->sb_type, AOM_PLANE_Y, + DRY_RUN_NORMAL, + cpi->optimize_seg_arr[mbmi->segment_id]); + xd->cfl.store_y = 0; + } + av1_rd_pick_intra_sbuv_mode(cpi, x, rate_uv, rate_uv_tokenonly, dist_uv, + skip_uv, bsize, max_tx_size); + *mode_uv = mbmi->uv_mode; +} + +// Run RD calculation with given chroma intra prediction angle., and return +// the RD cost. Update the best mode info. if the RD cost is the best so far. +static int64_t pick_intra_angle_routine_sbuv( + const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, + int rate_overhead, int64_t best_rd_in, int *rate, RD_STATS *rd_stats, + int *best_angle_delta, int64_t *best_rd) { + MB_MODE_INFO *mbmi = x->e_mbd.mi[0]; + assert(!is_inter_block(mbmi)); + int this_rate; + int64_t this_rd; + RD_STATS tokenonly_rd_stats; + + if (!av1_txfm_uvrd(cpi, x, &tokenonly_rd_stats, bsize, best_rd_in)) + return INT64_MAX; + this_rate = tokenonly_rd_stats.rate + + intra_mode_info_cost_uv(cpi, x, mbmi, bsize, rate_overhead); + this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + if (this_rd < *best_rd) { + *best_rd = this_rd; + *best_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; + *rate = this_rate; + rd_stats->rate = tokenonly_rd_stats.rate; + rd_stats->dist = tokenonly_rd_stats.dist; + rd_stats->skip = tokenonly_rd_stats.skip; + } + return this_rd; +} + +// With given chroma directional intra prediction mode, pick the best angle +// delta. Return true if a RD cost that is smaller than the input one is found. +static int rd_pick_intra_angle_sbuv(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int rate_overhead, + int64_t best_rd, int *rate, + RD_STATS *rd_stats) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + int i, angle_delta, best_angle_delta = 0; + int64_t this_rd, best_rd_in, rd_cost[2 * (MAX_ANGLE_DELTA + 2)]; + + rd_stats->rate = INT_MAX; + rd_stats->skip = 0; + rd_stats->dist = INT64_MAX; + for (i = 0; i < 2 * (MAX_ANGLE_DELTA + 2); ++i) rd_cost[i] = INT64_MAX; + + for (angle_delta = 0; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { + for (i = 0; i < 2; ++i) { + best_rd_in = (best_rd == INT64_MAX) + ? INT64_MAX + : (best_rd + (best_rd >> ((angle_delta == 0) ? 3 : 5))); + mbmi->angle_delta[PLANE_TYPE_UV] = (1 - 2 * i) * angle_delta; + this_rd = pick_intra_angle_routine_sbuv(cpi, x, bsize, rate_overhead, + best_rd_in, rate, rd_stats, + &best_angle_delta, &best_rd); + rd_cost[2 * angle_delta + i] = this_rd; + if (angle_delta == 0) { + if (this_rd == INT64_MAX) return 0; + rd_cost[1] = this_rd; + break; + } + } + } + + assert(best_rd != INT64_MAX); + for (angle_delta = 1; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { + int64_t rd_thresh; + for (i = 0; i < 2; ++i) { + int skip_search = 0; + rd_thresh = best_rd + (best_rd >> 5); + if (rd_cost[2 * (angle_delta + 1) + i] > rd_thresh && + rd_cost[2 * (angle_delta - 1) + i] > rd_thresh) + skip_search = 1; + if (!skip_search) { + mbmi->angle_delta[PLANE_TYPE_UV] = (1 - 2 * i) * angle_delta; + pick_intra_angle_routine_sbuv(cpi, x, bsize, rate_overhead, best_rd, + rate, rd_stats, &best_angle_delta, + &best_rd); + } + } + } + + mbmi->angle_delta[PLANE_TYPE_UV] = best_angle_delta; + return rd_stats->rate != INT_MAX; +} + +#define PLANE_SIGN_TO_JOINT_SIGN(plane, a, b) \ + (plane == CFL_PRED_U ? a * CFL_SIGNS + b - 1 : b * CFL_SIGNS + a - 1) +static int cfl_rd_pick_alpha(MACROBLOCK *const x, const AV1_COMP *const cpi, + TX_SIZE tx_size, int64_t best_rd) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const MACROBLOCKD_PLANE *pd = &xd->plane[AOM_PLANE_U]; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(mbmi->sb_type, pd->subsampling_x, pd->subsampling_y); + + assert(is_cfl_allowed(xd) && cpi->oxcf.enable_cfl_intra); + assert(plane_bsize < BLOCK_SIZES_ALL); + if (!xd->lossless[mbmi->segment_id]) { + assert(block_size_wide[plane_bsize] == tx_size_wide[tx_size]); + assert(block_size_high[plane_bsize] == tx_size_high[tx_size]); + } + + xd->cfl.use_dc_pred_cache = 1; + const int64_t mode_rd = + RDCOST(x->rdmult, + x->intra_uv_mode_cost[CFL_ALLOWED][mbmi->mode][UV_CFL_PRED], 0); + int64_t best_rd_uv[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; + int best_c[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; +#if CONFIG_DEBUG + int best_rate_uv[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; +#endif // CONFIG_DEBUG + + const int skip_trellis = 0; + for (int plane = 0; plane < CFL_PRED_PLANES; plane++) { + RD_STATS rd_stats; + av1_init_rd_stats(&rd_stats); + for (int joint_sign = 0; joint_sign < CFL_JOINT_SIGNS; joint_sign++) { + best_rd_uv[joint_sign][plane] = INT64_MAX; + best_c[joint_sign][plane] = 0; + } + // Collect RD stats for an alpha value of zero in this plane. + // Skip i == CFL_SIGN_ZERO as (0, 0) is invalid. + for (int i = CFL_SIGN_NEG; i < CFL_SIGNS; i++) { + const int8_t joint_sign = + PLANE_SIGN_TO_JOINT_SIGN(plane, CFL_SIGN_ZERO, i); + if (i == CFL_SIGN_NEG) { + mbmi->cfl_alpha_idx = 0; + mbmi->cfl_alpha_signs = joint_sign; + av1_txfm_rd_in_plane( + x, cpi, &rd_stats, best_rd, 0, plane + 1, plane_bsize, tx_size, + cpi->sf.rd_sf.use_fast_coef_costing, FTXS_NONE, skip_trellis); + if (rd_stats.rate == INT_MAX) break; + } + const int alpha_rate = x->cfl_cost[joint_sign][plane][0]; + best_rd_uv[joint_sign][plane] = + RDCOST(x->rdmult, rd_stats.rate + alpha_rate, rd_stats.dist); +#if CONFIG_DEBUG + best_rate_uv[joint_sign][plane] = rd_stats.rate; +#endif // CONFIG_DEBUG + } + } + + int8_t best_joint_sign = -1; + + for (int plane = 0; plane < CFL_PRED_PLANES; plane++) { + for (int pn_sign = CFL_SIGN_NEG; pn_sign < CFL_SIGNS; pn_sign++) { + int progress = 0; + for (int c = 0; c < CFL_ALPHABET_SIZE; c++) { + int flag = 0; + RD_STATS rd_stats; + if (c > 2 && progress < c) break; + av1_init_rd_stats(&rd_stats); + for (int i = 0; i < CFL_SIGNS; i++) { + const int8_t joint_sign = PLANE_SIGN_TO_JOINT_SIGN(plane, pn_sign, i); + if (i == 0) { + mbmi->cfl_alpha_idx = (c << CFL_ALPHABET_SIZE_LOG2) + c; + mbmi->cfl_alpha_signs = joint_sign; + av1_txfm_rd_in_plane( + x, cpi, &rd_stats, best_rd, 0, plane + 1, plane_bsize, tx_size, + cpi->sf.rd_sf.use_fast_coef_costing, FTXS_NONE, skip_trellis); + if (rd_stats.rate == INT_MAX) break; + } + const int alpha_rate = x->cfl_cost[joint_sign][plane][c]; + int64_t this_rd = + RDCOST(x->rdmult, rd_stats.rate + alpha_rate, rd_stats.dist); + if (this_rd >= best_rd_uv[joint_sign][plane]) continue; + best_rd_uv[joint_sign][plane] = this_rd; + best_c[joint_sign][plane] = c; +#if CONFIG_DEBUG + best_rate_uv[joint_sign][plane] = rd_stats.rate; +#endif // CONFIG_DEBUG + flag = 2; + if (best_rd_uv[joint_sign][!plane] == INT64_MAX) continue; + this_rd += mode_rd + best_rd_uv[joint_sign][!plane]; + if (this_rd >= best_rd) continue; + best_rd = this_rd; + best_joint_sign = joint_sign; + } + progress += flag; + } + } + } + + int best_rate_overhead = INT_MAX; + uint8_t ind = 0; + if (best_joint_sign >= 0) { + const int u = best_c[best_joint_sign][CFL_PRED_U]; + const int v = best_c[best_joint_sign][CFL_PRED_V]; + ind = (u << CFL_ALPHABET_SIZE_LOG2) + v; + best_rate_overhead = x->cfl_cost[best_joint_sign][CFL_PRED_U][u] + + x->cfl_cost[best_joint_sign][CFL_PRED_V][v]; +#if CONFIG_DEBUG + xd->cfl.rate = x->intra_uv_mode_cost[CFL_ALLOWED][mbmi->mode][UV_CFL_PRED] + + best_rate_overhead + + best_rate_uv[best_joint_sign][CFL_PRED_U] + + best_rate_uv[best_joint_sign][CFL_PRED_V]; +#endif // CONFIG_DEBUG + } else { + best_joint_sign = 0; + } + + mbmi->cfl_alpha_idx = ind; + mbmi->cfl_alpha_signs = best_joint_sign; + xd->cfl.use_dc_pred_cache = 0; + xd->cfl.dc_pred_is_cached[0] = 0; + xd->cfl.dc_pred_is_cached[1] = 0; + return best_rate_overhead; +} + +int64_t av1_rd_pick_intra_sbuv_mode(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, + BLOCK_SIZE bsize, TX_SIZE max_tx_size) { + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + MB_MODE_INFO best_mbmi = *mbmi; + int64_t best_rd = INT64_MAX, this_rd; + + for (int mode_idx = 0; mode_idx < UV_INTRA_MODES; ++mode_idx) { + int this_rate; + RD_STATS tokenonly_rd_stats; + UV_PREDICTION_MODE mode = uv_rd_search_mode_order[mode_idx]; + const int is_directional_mode = av1_is_directional_mode(get_uv_mode(mode)); + if (!(cpi->sf.intra_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; + if (mode == UV_CFL_PRED) { + if (!is_cfl_allowed(xd) || !cpi->oxcf.enable_cfl_intra) continue; + assert(!is_directional_mode); + const TX_SIZE uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); + cfl_alpha_rate = cfl_rd_pick_alpha(x, cpi, uv_tx_size, best_rd); + if (cfl_alpha_rate == INT_MAX) continue; + } + mbmi->angle_delta[PLANE_TYPE_UV] = 0; + if (is_directional_mode && av1_use_angle_delta(mbmi->sb_type) && + cpi->oxcf.enable_angle_delta) { + const int rate_overhead = + x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][mode]; + if (!rd_pick_intra_angle_sbuv(cpi, x, bsize, rate_overhead, best_rd, + &this_rate, &tokenonly_rd_stats)) + continue; + } else { + if (!av1_txfm_uvrd(cpi, x, &tokenonly_rd_stats, bsize, best_rd)) { + continue; + } + } + const int mode_cost = + x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][mode] + + cfl_alpha_rate; + this_rate = tokenonly_rd_stats.rate + + intra_mode_info_cost_uv(cpi, x, mbmi, bsize, mode_cost); + if (mode == UV_CFL_PRED) { + assert(is_cfl_allowed(xd) && cpi->oxcf.enable_cfl_intra); +#if CONFIG_DEBUG + if (!xd->lossless[mbmi->segment_id]) + assert(xd->cfl.rate == tokenonly_rd_stats.rate + mode_cost); +#endif // CONFIG_DEBUG + } + this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); + + if (this_rd < best_rd) { + best_mbmi = *mbmi; + best_rd = this_rd; + *rate = this_rate; + *rate_tokenonly = tokenonly_rd_stats.rate; + *distortion = tokenonly_rd_stats.dist; + *skippable = tokenonly_rd_stats.skip; + } + } + + const int try_palette = + cpi->oxcf.enable_palette && + av1_allow_palette(cpi->common.features.allow_screen_content_tools, + mbmi->sb_type); + if (try_palette) { + uint8_t *best_palette_color_map = x->palette_buffer->best_palette_color_map; + rd_pick_palette_intra_sbuv( + cpi, x, + x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][UV_DC_PRED], + best_palette_color_map, &best_mbmi, &best_rd, rate, rate_tokenonly, + distortion, skippable); + } + + *mbmi = best_mbmi; + // Make sure we actually chose a mode + assert(best_rd < INT64_MAX); + return best_rd; +} + +int av1_search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *this_rd_cost, PICK_MODE_CONTEXT *ctx, + BLOCK_SIZE bsize, MB_MODE_INFO *const mbmi, + PALETTE_MODE_INFO *const pmi, + unsigned int *ref_costs_single, + IntraModeSearchState *intra_search_state, + int64_t best_rd) { + const AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *const xd = &x->e_mbd; + int rate2 = 0; + int64_t distortion2 = 0, best_rd_palette = best_rd, this_rd, + best_model_rd_palette = INT64_MAX; + int skippable = 0; + TX_SIZE uv_tx = TX_4X4; + uint8_t *const best_palette_color_map = + x->palette_buffer->best_palette_color_map; + uint8_t *const color_map = xd->plane[0].color_index_map; + MB_MODE_INFO best_mbmi_palette = *mbmi; + uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; + uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; + const int *const intra_mode_cost = x->mbmode_cost[size_group_lookup[bsize]]; + const int rows = block_size_high[bsize]; + const int cols = block_size_wide[bsize]; + + mbmi->mode = DC_PRED; + mbmi->uv_mode = UV_DC_PRED; + mbmi->ref_frame[0] = INTRA_FRAME; + mbmi->ref_frame[1] = NONE_FRAME; + RD_STATS rd_stats_y; + av1_invalid_rd_stats(&rd_stats_y); + rd_pick_palette_intra_sby( + cpi, x, bsize, intra_mode_cost[DC_PRED], &best_mbmi_palette, + best_palette_color_map, &best_rd_palette, &best_model_rd_palette, + &rd_stats_y.rate, NULL, &rd_stats_y.dist, &rd_stats_y.skip, NULL, ctx, + best_blk_skip, best_tx_type_map); + if (rd_stats_y.rate == INT_MAX || pmi->palette_size[0] == 0) { + this_rd_cost->rdcost = INT64_MAX; + return skippable; + } + + memcpy(x->blk_skip, best_blk_skip, + sizeof(best_blk_skip[0]) * bsize_to_num_blk(bsize)); + av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); + memcpy(color_map, best_palette_color_map, + rows * cols * sizeof(best_palette_color_map[0])); + + skippable = rd_stats_y.skip; + distortion2 = rd_stats_y.dist; + rate2 = rd_stats_y.rate + ref_costs_single[INTRA_FRAME]; + if (num_planes > 1) { + uv_tx = av1_get_tx_size(AOM_PLANE_U, xd); + if (intra_search_state->rate_uv_intra == INT_MAX) { + choose_intra_uv_mode( + cpi, x, bsize, uv_tx, &intra_search_state->rate_uv_intra, + &intra_search_state->rate_uv_tokenonly, &intra_search_state->dist_uvs, + &intra_search_state->skip_uvs, &intra_search_state->mode_uv); + intra_search_state->pmi_uv = *pmi; + intra_search_state->uv_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; + } + mbmi->uv_mode = intra_search_state->mode_uv; + pmi->palette_size[1] = intra_search_state->pmi_uv.palette_size[1]; + if (pmi->palette_size[1] > 0) { + memcpy(pmi->palette_colors + PALETTE_MAX_SIZE, + intra_search_state->pmi_uv.palette_colors + PALETTE_MAX_SIZE, + 2 * PALETTE_MAX_SIZE * sizeof(pmi->palette_colors[0])); + } + mbmi->angle_delta[PLANE_TYPE_UV] = intra_search_state->uv_angle_delta; + skippable = skippable && intra_search_state->skip_uvs; + distortion2 += intra_search_state->dist_uvs; + rate2 += intra_search_state->rate_uv_intra; + } + + if (skippable) { + rate2 -= rd_stats_y.rate; + if (num_planes > 1) rate2 -= intra_search_state->rate_uv_tokenonly; + rate2 += x->skip_cost[av1_get_skip_context(xd)][1]; + } else { + rate2 += x->skip_cost[av1_get_skip_context(xd)][0]; + } + this_rd = RDCOST(x->rdmult, rate2, distortion2); + this_rd_cost->rate = rate2; + this_rd_cost->dist = distortion2; + this_rd_cost->rdcost = this_rd; + return skippable; +} + +// Given selected prediction mode, search for the best tx type and size. +static AOM_INLINE int intra_block_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, const int *bmode_costs, + int64_t *best_rd, int *rate, + int *rate_tokenonly, int64_t *distortion, + int *skippable, MB_MODE_INFO *best_mbmi, + PICK_MODE_CONTEXT *ctx) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + RD_STATS rd_stats; + // In order to improve txfm search avoid rd based breakouts during winner + // mode evaluation. Hence passing ref_best_rd as a maximum value + av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats, bsize, INT64_MAX); + if (rd_stats.rate == INT_MAX) return 0; + int this_rate_tokenonly = rd_stats.rate; + if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(mbmi->sb_type)) { + // av1_pick_uniform_tx_size_type_yrd above includes the cost of the tx_size + // in the tokenonly rate, but for intra blocks, tx_size is always coded + // (prediction granularity), so we account for it in the full rate, + // not the tokenonly rate. + this_rate_tokenonly -= tx_size_cost(x, bsize, mbmi->tx_size); + } + const int this_rate = + rd_stats.rate + + intra_mode_info_cost_y(cpi, x, mbmi, bsize, bmode_costs[mbmi->mode]); + const int64_t this_rd = RDCOST(x->rdmult, this_rate, rd_stats.dist); + if (this_rd < *best_rd) { + *best_mbmi = *mbmi; + *best_rd = this_rd; + *rate = this_rate; + *rate_tokenonly = this_rate_tokenonly; + *distortion = rd_stats.dist; + *skippable = rd_stats.skip; + av1_copy_array(ctx->blk_skip, x->blk_skip, ctx->num_4x4_blk); + av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + return 1; + } + return 0; +} + +// With given luma directional intra prediction mode, pick the best angle delta +// Return the RD cost corresponding to the best angle delta. +static int64_t rd_pick_intra_angle_sby(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, RD_STATS *rd_stats, + BLOCK_SIZE bsize, int mode_cost, + int64_t best_rd, int64_t *best_model_rd, + int skip_model_rd_for_zero_deg) { + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + + int best_angle_delta = 0; + int64_t rd_cost[2 * (MAX_ANGLE_DELTA + 2)]; + TX_SIZE best_tx_size = mbmi->tx_size; + uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; + uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; + + for (int i = 0; i < 2 * (MAX_ANGLE_DELTA + 2); ++i) rd_cost[i] = INT64_MAX; + + int first_try = 1; + for (int angle_delta = 0; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { + for (int i = 0; i < 2; ++i) { + const int64_t best_rd_in = + (best_rd == INT64_MAX) ? INT64_MAX + : (best_rd + (best_rd >> (first_try ? 3 : 5))); + const int64_t this_rd = calc_rd_given_intra_angle( + cpi, x, bsize, mode_cost, best_rd_in, (1 - 2 * i) * angle_delta, + MAX_ANGLE_DELTA, rate, rd_stats, &best_angle_delta, &best_tx_size, + &best_rd, best_model_rd, best_tx_type_map, best_blk_skip, + (skip_model_rd_for_zero_deg & !angle_delta)); + rd_cost[2 * angle_delta + i] = this_rd; + if (first_try && this_rd == INT64_MAX) return best_rd; + first_try = 0; + if (angle_delta == 0) { + rd_cost[1] = this_rd; + break; + } + } + } + + assert(best_rd != INT64_MAX); + for (int angle_delta = 1; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { + for (int i = 0; i < 2; ++i) { + int skip_search = 0; + const int64_t rd_thresh = best_rd + (best_rd >> 5); + if (rd_cost[2 * (angle_delta + 1) + i] > rd_thresh && + rd_cost[2 * (angle_delta - 1) + i] > rd_thresh) + skip_search = 1; + if (!skip_search) { + calc_rd_given_intra_angle( + cpi, x, bsize, mode_cost, best_rd, (1 - 2 * i) * angle_delta, + MAX_ANGLE_DELTA, rate, rd_stats, &best_angle_delta, &best_tx_size, + &best_rd, best_model_rd, best_tx_type_map, best_blk_skip, 0); + } + } + } + + if (rd_stats->rate != INT_MAX) { + mbmi->tx_size = best_tx_size; + mbmi->angle_delta[PLANE_TYPE_Y] = best_angle_delta; + const int n4 = bsize_to_num_blk(bsize); + memcpy(x->blk_skip, best_blk_skip, sizeof(best_blk_skip[0]) * n4); + av1_copy_array(xd->tx_type_map, best_tx_type_map, n4); + } + return best_rd; +} + +int64_t av1_handle_intra_mode(IntraModeSearchState *intra_search_state, + const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int ref_frame_cost, + const PICK_MODE_CONTEXT *ctx, int disable_skip, + RD_STATS *rd_stats, RD_STATS *rd_stats_y, + RD_STATS *rd_stats_uv, int64_t best_rd, + int64_t *best_intra_rd, int8_t best_mbmode_skip) { + const AV1_COMMON *cm = &cpi->common; + const SPEED_FEATURES *const sf = &cpi->sf; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(mbmi->ref_frame[0] == INTRA_FRAME); + const PREDICTION_MODE mode = mbmi->mode; + const int mode_cost = + x->mbmode_cost[size_group_lookup[bsize]][mode] + ref_frame_cost; + const int intra_cost_penalty = av1_get_intra_cost_penalty( + cm->quant_params.base_qindex, cm->quant_params.y_dc_delta_q, + cm->seq_params.bit_depth); + const int skip_ctx = av1_get_skip_context(xd); + + int known_rate = mode_cost; + known_rate += ref_frame_cost; + if (mode != DC_PRED && mode != PAETH_PRED) known_rate += intra_cost_penalty; + known_rate += AOMMIN(x->skip_cost[skip_ctx][0], x->skip_cost[skip_ctx][1]); + const int64_t known_rd = RDCOST(x->rdmult, known_rate, 0); + if (known_rd > best_rd) { + intra_search_state->skip_intra_modes = 1; + return INT64_MAX; + } + + const int is_directional_mode = av1_is_directional_mode(mode); + if (is_directional_mode && av1_use_angle_delta(bsize) && + cpi->oxcf.enable_angle_delta) { + if (sf->intra_sf.intra_pruning_with_hog && + !intra_search_state->angle_stats_ready) { + prune_intra_mode_with_hog(x, bsize, + cpi->sf.intra_sf.intra_pruning_with_hog_thresh, + intra_search_state->directional_mode_skip_mask); + intra_search_state->angle_stats_ready = 1; + } + if (intra_search_state->directional_mode_skip_mask[mode]) return INT64_MAX; + av1_init_rd_stats(rd_stats_y); + rd_stats_y->rate = INT_MAX; + int64_t model_rd = INT64_MAX; + int rate_dummy; + rd_pick_intra_angle_sby(cpi, x, &rate_dummy, rd_stats_y, bsize, mode_cost, + best_rd, &model_rd, 0); + + } else { + av1_init_rd_stats(rd_stats_y); + mbmi->angle_delta[PLANE_TYPE_Y] = 0; + av1_pick_uniform_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, best_rd); + } + + // Pick filter intra modes. + if (mode == DC_PRED && av1_filter_intra_allowed_bsize(cm, bsize)) { + int try_filter_intra = 0; + int64_t best_rd_so_far = INT64_MAX; + if (rd_stats_y->rate != INT_MAX) { + const int tmp_rate = + rd_stats_y->rate + x->filter_intra_cost[bsize][0] + mode_cost; + best_rd_so_far = RDCOST(x->rdmult, tmp_rate, rd_stats_y->dist); + try_filter_intra = (best_rd_so_far / 2) <= best_rd; + } else { + try_filter_intra = !best_mbmode_skip; + } + + if (try_filter_intra) { + RD_STATS rd_stats_y_fi; + int filter_intra_selected_flag = 0; + TX_SIZE best_tx_size = mbmi->tx_size; + FILTER_INTRA_MODE best_fi_mode = FILTER_DC_PRED; + uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; + memcpy(best_blk_skip, x->blk_skip, + sizeof(best_blk_skip[0]) * ctx->num_4x4_blk); + uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; + av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + mbmi->filter_intra_mode_info.use_filter_intra = 1; + for (FILTER_INTRA_MODE fi_mode = FILTER_DC_PRED; + fi_mode < FILTER_INTRA_MODES; ++fi_mode) { + mbmi->filter_intra_mode_info.filter_intra_mode = fi_mode; + av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y_fi, bsize, + best_rd); + if (rd_stats_y_fi.rate == INT_MAX) continue; + const int this_rate_tmp = + rd_stats_y_fi.rate + + intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); + const int64_t this_rd_tmp = + RDCOST(x->rdmult, this_rate_tmp, rd_stats_y_fi.dist); + + if (this_rd_tmp != INT64_MAX && this_rd_tmp / 2 > best_rd) { + break; + } + if (this_rd_tmp < best_rd_so_far) { + best_tx_size = mbmi->tx_size; + av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + memcpy(best_blk_skip, x->blk_skip, + sizeof(best_blk_skip[0]) * ctx->num_4x4_blk); + best_fi_mode = fi_mode; + *rd_stats_y = rd_stats_y_fi; + filter_intra_selected_flag = 1; + best_rd_so_far = this_rd_tmp; + } + } + + mbmi->tx_size = best_tx_size; + av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); + memcpy(x->blk_skip, best_blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + + if (filter_intra_selected_flag) { + mbmi->filter_intra_mode_info.use_filter_intra = 1; + mbmi->filter_intra_mode_info.filter_intra_mode = best_fi_mode; + } else { + mbmi->filter_intra_mode_info.use_filter_intra = 0; + } + } + } + + if (rd_stats_y->rate == INT_MAX) return INT64_MAX; + + const int mode_cost_y = + intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); + av1_init_rd_stats(rd_stats); + av1_init_rd_stats(rd_stats_uv); + const int num_planes = av1_num_planes(cm); + if (num_planes > 1) { + PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + const int try_palette = + cpi->oxcf.enable_palette && + av1_allow_palette(cm->features.allow_screen_content_tools, + mbmi->sb_type); + const TX_SIZE uv_tx = av1_get_tx_size(AOM_PLANE_U, xd); + if (intra_search_state->rate_uv_intra == INT_MAX) { + const int rate_y = + rd_stats_y->skip ? x->skip_cost[skip_ctx][1] : rd_stats_y->rate; + const int64_t rdy = + RDCOST(x->rdmult, rate_y + mode_cost_y, rd_stats_y->dist); + if (best_rd < (INT64_MAX / 2) && rdy > (best_rd + (best_rd >> 2))) { + intra_search_state->skip_intra_modes = 1; + return INT64_MAX; + } + choose_intra_uv_mode( + cpi, x, bsize, uv_tx, &intra_search_state->rate_uv_intra, + &intra_search_state->rate_uv_tokenonly, &intra_search_state->dist_uvs, + &intra_search_state->skip_uvs, &intra_search_state->mode_uv); + if (try_palette) intra_search_state->pmi_uv = *pmi; + intra_search_state->uv_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; + + const int uv_rate = intra_search_state->rate_uv_tokenonly; + const int64_t uv_dist = intra_search_state->dist_uvs; + const int64_t uv_rd = RDCOST(x->rdmult, uv_rate, uv_dist); + if (uv_rd > best_rd) { + intra_search_state->skip_intra_modes = 1; + return INT64_MAX; + } + } + + rd_stats_uv->rate = intra_search_state->rate_uv_tokenonly; + rd_stats_uv->dist = intra_search_state->dist_uvs; + rd_stats_uv->skip = intra_search_state->skip_uvs; + rd_stats->skip = rd_stats_y->skip && rd_stats_uv->skip; + mbmi->uv_mode = intra_search_state->mode_uv; + if (try_palette) { + pmi->palette_size[1] = intra_search_state->pmi_uv.palette_size[1]; + memcpy(pmi->palette_colors + PALETTE_MAX_SIZE, + intra_search_state->pmi_uv.palette_colors + PALETTE_MAX_SIZE, + 2 * PALETTE_MAX_SIZE * sizeof(pmi->palette_colors[0])); + } + mbmi->angle_delta[PLANE_TYPE_UV] = intra_search_state->uv_angle_delta; + } + + rd_stats->rate = rd_stats_y->rate + mode_cost_y; + if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(bsize)) { + // av1_pick_uniform_tx_size_type_yrd above includes the cost of the tx_size + // in the tokenonly rate, but for intra blocks, tx_size is always coded + // (prediction granularity), so we account for it in the full rate, + // not the tokenonly rate. + rd_stats_y->rate -= tx_size_cost(x, bsize, mbmi->tx_size); + } + if (num_planes > 1 && xd->is_chroma_ref) { + const int uv_mode_cost = + x->intra_uv_mode_cost[is_cfl_allowed(xd)][mode][mbmi->uv_mode]; + rd_stats->rate += + rd_stats_uv->rate + + intra_mode_info_cost_uv(cpi, x, mbmi, bsize, uv_mode_cost); + } + if (mode != DC_PRED && mode != PAETH_PRED) { + rd_stats->rate += intra_cost_penalty; + } + + // Intra block is always coded as non-skip + rd_stats->skip = 0; + rd_stats->dist = rd_stats_y->dist + rd_stats_uv->dist; + // Add in the cost of the no skip flag. + rd_stats->rate += x->skip_cost[skip_ctx][0]; + // Calculate the final RD estimate for this mode. + const int64_t this_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); + // Keep record of best intra rd + if (this_rd < *best_intra_rd) { + *best_intra_rd = this_rd; + intra_search_state->best_intra_mode = mode; + } + + if (sf->intra_sf.skip_intra_in_interframe) { + if (best_rd < (INT64_MAX / 2) && this_rd > (best_rd + (best_rd >> 1))) + intra_search_state->skip_intra_modes = 1; + } + + if (!disable_skip) { + for (int i = 0; i < REFERENCE_MODES; ++i) { + intra_search_state->best_pred_rd[i] = + AOMMIN(intra_search_state->best_pred_rd[i], this_rd); + } + } + return this_rd; +} + +// This function is used only for intra_only frames +int64_t av1_rd_pick_intra_sby_mode(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, + BLOCK_SIZE bsize, int64_t best_rd, + PICK_MODE_CONTEXT *ctx) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(!is_inter_block(mbmi)); + int64_t best_model_rd = INT64_MAX; + int is_directional_mode; + uint8_t directional_mode_skip_mask[INTRA_MODES] = { 0 }; + // Flag to check rd of any intra mode is better than best_rd passed to this + // function + int beat_best_rd = 0; + const int *bmode_costs; + PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + const int try_palette = + cpi->oxcf.enable_palette && + av1_allow_palette(cpi->common.features.allow_screen_content_tools, + mbmi->sb_type); + uint8_t *best_palette_color_map = + try_palette ? x->palette_buffer->best_palette_color_map : NULL; + const MB_MODE_INFO *above_mi = xd->above_mbmi; + const MB_MODE_INFO *left_mi = xd->left_mbmi; + const PREDICTION_MODE A = av1_above_block_mode(above_mi); + const PREDICTION_MODE L = av1_left_block_mode(left_mi); + const int above_ctx = intra_mode_context[A]; + const int left_ctx = intra_mode_context[L]; + bmode_costs = x->y_mode_costs[above_ctx][left_ctx]; + + mbmi->angle_delta[PLANE_TYPE_Y] = 0; + if (cpi->sf.intra_sf.intra_pruning_with_hog) { + prune_intra_mode_with_hog(x, bsize, + cpi->sf.intra_sf.intra_pruning_with_hog_thresh, + directional_mode_skip_mask); + } + mbmi->filter_intra_mode_info.use_filter_intra = 0; + pmi->palette_size[0] = 0; + + // Set params for mode evaluation + set_mode_eval_params(cpi, x, MODE_EVAL); + + MB_MODE_INFO best_mbmi = *mbmi; + av1_zero(x->winner_mode_stats); + x->winner_mode_count = 0; + + /* Y Search for intra prediction mode */ + for (int mode_idx = INTRA_MODE_START; mode_idx < INTRA_MODE_END; ++mode_idx) { + RD_STATS this_rd_stats; + int this_rate, this_rate_tokenonly, s; + int64_t this_distortion, this_rd; + mbmi->mode = intra_rd_search_mode_order[mode_idx]; + if ((!cpi->oxcf.enable_smooth_intra || + cpi->sf.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; + mbmi->angle_delta[PLANE_TYPE_Y] = 0; + + if (model_intra_yrd_and_prune(cpi, x, bsize, bmode_costs[mbmi->mode], + &best_model_rd)) { + continue; + } + + is_directional_mode = av1_is_directional_mode(mbmi->mode); + if (is_directional_mode && directional_mode_skip_mask[mbmi->mode]) continue; + if (is_directional_mode && av1_use_angle_delta(bsize) && + cpi->oxcf.enable_angle_delta) { + this_rd_stats.rate = INT_MAX; + rd_pick_intra_angle_sby(cpi, x, &this_rate, &this_rd_stats, bsize, + bmode_costs[mbmi->mode], best_rd, &best_model_rd, + 1); + } else { + av1_pick_uniform_tx_size_type_yrd(cpi, x, &this_rd_stats, bsize, best_rd); + } + this_rate_tokenonly = this_rd_stats.rate; + this_distortion = this_rd_stats.dist; + s = this_rd_stats.skip; + + if (this_rate_tokenonly == INT_MAX) continue; + + if (!xd->lossless[mbmi->segment_id] && + block_signals_txsize(mbmi->sb_type)) { + // av1_pick_uniform_tx_size_type_yrd above includes the cost of the + // tx_size in the tokenonly rate, but for intra blocks, tx_size is always + // coded (prediction granularity), so we account for it in the full rate, + // not the tokenonly rate. + this_rate_tokenonly -= tx_size_cost(x, bsize, mbmi->tx_size); + } + this_rate = + this_rd_stats.rate + + intra_mode_info_cost_y(cpi, x, mbmi, bsize, bmode_costs[mbmi->mode]); + this_rd = RDCOST(x->rdmult, this_rate, this_distortion); + // Collect mode stats for multiwinner mode processing + const int txfm_search_done = 1; + store_winner_mode_stats( + &cpi->common, x, mbmi, NULL, NULL, NULL, 0, NULL, bsize, this_rd, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + txfm_search_done); + if (this_rd < best_rd) { + best_mbmi = *mbmi; + best_rd = this_rd; + // Setting beat_best_rd flag because current mode rd is better than + // best_rd passed to this function + beat_best_rd = 1; + *rate = this_rate; + *rate_tokenonly = this_rate_tokenonly; + *distortion = this_distortion; + *skippable = s; + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + } + } + + if (try_palette) { + rd_pick_palette_intra_sby( + cpi, x, bsize, bmode_costs[DC_PRED], &best_mbmi, best_palette_color_map, + &best_rd, &best_model_rd, rate, rate_tokenonly, distortion, skippable, + &beat_best_rd, ctx, ctx->blk_skip, ctx->tx_type_map); + } + + if (beat_best_rd && av1_filter_intra_allowed_bsize(&cpi->common, bsize)) { + if (rd_pick_filter_intra_sby(cpi, x, rate, rate_tokenonly, distortion, + skippable, bsize, bmode_costs[DC_PRED], + &best_rd, &best_model_rd, ctx)) { + best_mbmi = *mbmi; + } + } + // No mode is identified with less rd value than best_rd passed to this + // function. In such cases winner mode processing is not necessary and return + // best_rd as INT64_MAX to indicate best mode is not identified + if (!beat_best_rd) return INT64_MAX; + + // In multi-winner mode processing, perform tx search for few best modes + // identified during mode evaluation. Winner mode processing uses best tx + // configuration for tx search. + if (cpi->sf.winner_mode_sf.enable_multiwinner_mode_process) { + int best_mode_idx = 0; + int block_width, block_height; + uint8_t *color_map_dst = xd->plane[PLANE_TYPE_Y].color_index_map; + av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width, + &block_height, NULL, NULL); + + for (int mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++) { + *mbmi = x->winner_mode_stats[mode_idx].mbmi; + if (is_winner_mode_processing_enabled(cpi, mbmi, mbmi->mode)) { + // Restore color_map of palette mode before winner mode processing + if (mbmi->palette_mode_info.palette_size[0] > 0) { + uint8_t *color_map_src = + x->winner_mode_stats[mode_idx].color_index_map; + memcpy(color_map_dst, color_map_src, + block_width * block_height * sizeof(*color_map_src)); + } + // Set params for winner mode evaluation + set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); + + // Winner mode processing + // If previous searches use only the default tx type/no R-D optimization + // of quantized coeffs, do an extra search for the best tx type/better + // R-D optimization of quantized coeffs + if (intra_block_yrd(cpi, x, bsize, bmode_costs, &best_rd, rate, + rate_tokenonly, distortion, skippable, &best_mbmi, + ctx)) + best_mode_idx = mode_idx; + } + } + // Copy color_map of palette mode for final winner mode + if (best_mbmi.palette_mode_info.palette_size[0] > 0) { + uint8_t *color_map_src = + x->winner_mode_stats[best_mode_idx].color_index_map; + memcpy(color_map_dst, color_map_src, + block_width * block_height * sizeof(*color_map_src)); + } + } else { + // If previous searches use only the default tx type/no R-D optimization of + // quantized coeffs, do an extra search for the best tx type/better R-D + // optimization of quantized coeffs + if (is_winner_mode_processing_enabled(cpi, mbmi, best_mbmi.mode)) { + // Set params for winner mode evaluation + set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); + *mbmi = best_mbmi; + intra_block_yrd(cpi, x, bsize, bmode_costs, &best_rd, rate, + rate_tokenonly, distortion, skippable, &best_mbmi, ctx); + } + } + *mbmi = best_mbmi; + av1_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk); + return best_rd; +} diff --git a/media/libaom/src/av1/encoder/intra_mode_search.h b/media/libaom/src/av1/encoder/intra_mode_search.h new file mode 100644 index 0000000000..4b5d31c3ec --- /dev/null +++ b/media/libaom/src/av1/encoder/intra_mode_search.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, 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_INTRA_MODE_SEARCH_H_ +#define AOM_AV1_ENCODER_INTRA_MODE_SEARCH_H_ + +#include "av1/encoder/encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct IntraModeSearchState { + int skip_intra_modes; + PREDICTION_MODE best_intra_mode; + int angle_stats_ready; + uint8_t directional_mode_skip_mask[INTRA_MODES]; + int rate_uv_intra; + int rate_uv_tokenonly; + int64_t dist_uvs; + int skip_uvs; + UV_PREDICTION_MODE mode_uv; + PALETTE_MODE_INFO pmi_uv; + int8_t uv_angle_delta; + int64_t best_pred_rd[REFERENCE_MODES]; +} IntraModeSearchState; + +void av1_restore_uv_color_map(const AV1_COMP *const cpi, MACROBLOCK *x); +int av1_search_palette_mode(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *this_rd_cost, PICK_MODE_CONTEXT *ctx, + BLOCK_SIZE bsize, MB_MODE_INFO *const mbmi, + PALETTE_MODE_INFO *const pmi, + unsigned int *ref_costs_single, + IntraModeSearchState *intra_search_state, + int64_t best_rd); + +int64_t av1_rd_pick_intra_sbuv_mode(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, + BLOCK_SIZE bsize, TX_SIZE max_tx_size); + +int64_t av1_handle_intra_mode(IntraModeSearchState *intra_search_state, + const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int ref_frame_cost, + const PICK_MODE_CONTEXT *ctx, int disable_skip, + RD_STATS *rd_stats, RD_STATS *rd_stats_y, + RD_STATS *rd_stats_uv, int64_t best_rd, + int64_t *best_intra_rd, int8_t best_mbmode_skip); + +int64_t av1_rd_pick_intra_sby_mode(const AV1_COMP *const cpi, MACROBLOCK *x, + int *rate, int *rate_tokenonly, + int64_t *distortion, int *skippable, + BLOCK_SIZE bsize, int64_t best_rd, + PICK_MODE_CONTEXT *ctx); +#endif // AOM_AV1_ENCODER_INTRA_MODE_SEARCH_H_ diff --git a/media/libaom/src/av1/encoder/level.c b/media/libaom/src/av1/encoder/level.c index 6a6ceb263c..3403a3a84b 100644 --- a/media/libaom/src/av1/encoder/level.c +++ b/media/libaom/src/av1/encoder/level.c @@ -507,18 +507,19 @@ void av1_decoder_model_init(const AV1_COMP *const cpi, AV1_LEVEL level, dfg_interval_queue->head = 0; dfg_interval_queue->size = 0; - if (cm->timing_info_present) { + if (seq_params->timing_info_present) { decoder_model->num_ticks_per_picture = - cm->timing_info.num_ticks_per_picture; + seq_params->timing_info.num_ticks_per_picture; decoder_model->display_clock_tick = - cm->timing_info.num_units_in_display_tick / cm->timing_info.time_scale; + seq_params->timing_info.num_units_in_display_tick / + seq_params->timing_info.time_scale; } else { decoder_model->num_ticks_per_picture = 1; decoder_model->display_clock_tick = 1.0 / cpi->framerate; } decoder_model->initial_display_delay = - cm->op_params[op_index].initial_display_delay; + seq_params->op_params[op_index].initial_display_delay; decoder_model->initial_presentation_delay = INVALID_TIME; decoder_model->decode_rate = av1_level_defs[level].max_decode_rate; } @@ -688,7 +689,8 @@ void av1_decoder_model_process_frame(const AV1_COMP *const cpi, void av1_init_level_info(AV1_COMP *cpi) { for (int op_index = 0; op_index < MAX_NUM_OPERATING_POINTS; ++op_index) { - AV1LevelInfo *const this_level_info = cpi->level_info[op_index]; + AV1LevelInfo *const this_level_info = + cpi->level_params.level_info[op_index]; if (!this_level_info) continue; memset(this_level_info, 0, sizeof(*this_level_info)); AV1LevelSpec *const level_spec = &this_level_info->level_spec; @@ -903,14 +905,14 @@ static TARGET_LEVEL_FAIL_ID check_level_constraints( return fail_id; } -static void get_tile_stats(const AV1_COMP *const cpi, int *max_tile_size, - int *max_superres_tile_width, +static void get_tile_stats(const AV1_COMMON *const cm, + const TileDataEnc *const tile_data, + int *max_tile_size, int *max_superres_tile_width, 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; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; const int superres_scale_denominator = cm->superres_scale_denominator; *max_tile_size = 0; @@ -922,7 +924,7 @@ static void get_tile_stats(const AV1_COMP *const cpi, int *max_tile_size, 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; + &tile_data[tile_row * cm->tiles.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 = @@ -944,7 +946,8 @@ static void get_tile_stats(const AV1_COMP *const cpi, int *max_tile_size, *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; + const int is_right_most_tile = + tile_info->mi_col_end == cm->mi_params.mi_cols; if (!is_right_most_tile) { if (av1_superres_scaled(cm)) *tile_width_valid &= tile_width >= 128; @@ -1045,14 +1048,16 @@ static void scan_past_frames(const FrameWindowBuffer *const buffer, 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 AV1LevelParams *const level_params = &cpi->level_params; + const int upscaled_width = cm->superres_upscaled_width; const int width = cm->width; const int height = cm->height; - const int tile_cols = cm->tile_cols; - const int tile_rows = cm->tile_rows; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.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 frame_header_count = level_params->frame_header_count; const int show_frame = cm->show_frame; const int show_existing_frame = cm->show_existing_frame; @@ -1061,14 +1066,14 @@ void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start, int min_cropped_tile_height; int max_superres_tile_width; int tile_width_is_valid; - get_tile_stats(cpi, &max_tile_size, &max_superres_tile_width, + get_tile_stats(cm, cpi->tile_data, &max_tile_size, &max_superres_tile_width, &min_cropped_tile_width, &min_cropped_tile_height, &tile_width_is_valid); aom_clear_system_state(); const double compression_ratio = av1_get_compression_ratio(cm, size); const double total_time_encoded = - (cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) / + (cpi->time_stamps.prev_end_seen - cpi->time_stamps.first_ever) / (double)TICKS_PER_SEC; const int temporal_layer_id = cm->temporal_layer_id; @@ -1081,11 +1086,11 @@ void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start, 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) || - !((cpi->keep_level_stats >> i) & 1)) { + !((level_params->keep_level_stats >> i) & 1)) { continue; } - AV1LevelInfo *const level_info = cpi->level_info[i]; + AV1LevelInfo *const level_info = level_params->level_info[i]; assert(level_info != NULL); AV1LevelStats *const level_stats = &level_info->level_stats; @@ -1135,7 +1140,7 @@ void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start, } // Check whether target level is met. - const AV1_LEVEL target_level = cpi->target_seq_level_idx[i]; + const AV1_LEVEL target_level = level_params->target_seq_level_idx[i]; if (target_level < SEQ_LEVELS) { assert(is_valid_seq_level_idx(target_level)); const int tier = seq_params->tier[i]; @@ -1153,15 +1158,16 @@ void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start, } } -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; +aom_codec_err_t av1_get_seq_level_idx(const SequenceHeader *seq_params, + const AV1LevelParams *level_params, + int *seq_level_idx) { const int is_still_picture = seq_params->still_picture; const BITSTREAM_PROFILE profile = seq_params->profile; for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) { seq_level_idx[op] = (int)SEQ_LEVEL_MAX; - if (!((cpi->keep_level_stats >> op) & 1)) continue; + if (!((level_params->keep_level_stats >> op) & 1)) continue; const int tier = seq_params->tier[op]; - const AV1LevelInfo *const level_info = cpi->level_info[op]; + const AV1LevelInfo *const level_info = level_params->level_info[op]; assert(level_info != NULL); for (int level = 0; level < SEQ_LEVELS; ++level) { if (!is_valid_seq_level_idx(level)) continue; diff --git a/media/libaom/src/av1/encoder/level.h b/media/libaom/src/av1/encoder/level.h index 72118ece7f..5e0cce2007 100644 --- a/media/libaom/src/av1/encoder/level.h +++ b/media/libaom/src/av1/encoder/level.h @@ -155,6 +155,19 @@ typedef struct { DECODER_MODEL decoder_models[SEQ_LEVELS]; } AV1LevelInfo; +typedef struct AV1LevelParams { + // Specifies the level that the coded video sequence conforms to for each + // operating point. + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; + // Bit mask to indicate whether to keep level stats for corresponding + // operating points. + uint32_t keep_level_stats; + // Level information for each operating point. + AV1LevelInfo *level_info[MAX_NUM_OPERATING_POINTS]; + // Count the number of OBU_FRAME and OBU_FRAME_HEADER for level calculation. + int frame_header_count; +} AV1LevelParams; + static INLINE int is_in_operating_point(int operating_point, int temporal_layer_id, int spatial_layer_id) { @@ -170,7 +183,8 @@ 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, +aom_codec_err_t av1_get_seq_level_idx(const SequenceHeader *seq_params, + const AV1LevelParams *level_params, int *seq_level_idx); // Print the status of the decoder model(for debugging). diff --git a/media/libaom/src/av1/encoder/lookahead.c b/media/libaom/src/av1/encoder/lookahead.c index 818b3c393c..0f7c819893 100644 --- a/media/libaom/src/av1/encoder/lookahead.c +++ b/media/libaom/src/av1/encoder/lookahead.c @@ -13,6 +13,7 @@ #include "config/aom_config.h" +#include "aom_scale/yv12config.h" #include "av1/common/common.h" #include "av1/encoder/encoder.h" #include "av1/encoder/extend.h" @@ -44,11 +45,13 @@ 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, int is_scale) { + const int border_in_pixels, int byte_alignment, int num_lap_buffers) { struct lookahead_ctx *ctx = NULL; + int lag_in_frames = AOMMAX(1, depth); - // Clamp the lookahead queue depth - depth = clamp(depth, 1, MAX_LAG_BUFFERS); + // Add the lags to depth and clamp + depth += num_lap_buffers; + depth = clamp(depth, 1, MAX_TOTAL_BUFFERS); // Allocate memory to keep previous source frames available. depth += MAX_PRE_FRAMES; @@ -56,25 +59,24 @@ struct lookahead_ctx *av1_lookahead_init( // Allocate the lookahead structures ctx = calloc(1, sizeof(*ctx)); if (ctx) { - const int legacy_byte_alignment = 0; unsigned int i; ctx->max_sz = depth; + ctx->read_ctxs[ENCODE_STAGE].pop_sz = ctx->max_sz - MAX_PRE_FRAMES; + ctx->read_ctxs[ENCODE_STAGE].valid = 1; + if (num_lap_buffers) { + ctx->read_ctxs[LAP_STAGE].pop_sz = lag_in_frames; + ctx->read_ctxs[LAP_STAGE].valid = 1; + } ctx->buf = calloc(depth, sizeof(*ctx->buf)); if (!ctx->buf) goto fail; - for (i = 0; i < depth; i++) - 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 fail; - } 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 fail; - } + for (i = 0; i < depth; i++) { + aom_free_frame_buffer(&ctx->buf[i].img); + if (aom_realloc_frame_buffer(&ctx->buf[i].img, width, height, + subsampling_x, subsampling_y, + use_highbitdepth, border_in_pixels, + byte_alignment, NULL, NULL, NULL)) + goto fail; + } } return ctx; fail: @@ -82,17 +84,10 @@ fail: return NULL; } -#define USE_PARTIAL_COPY 0 - int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, int64_t ts_start, int64_t ts_end, int use_highbitdepth, aom_enc_frame_flags_t flags) { struct lookahead_entry *buf; -#if USE_PARTIAL_COPY - int row, col, active_end; - int mb_rows = (src->y_height + 15) >> 4; - int mb_cols = (src->y_width + 15) >> 4; -#endif int width = src->y_crop_width; int height = src->y_crop_height; int uv_width = src->uv_crop_width; @@ -101,8 +96,13 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, int subsampling_y = src->subsampling_y; int larger_dimensions, new_dimensions; - if (ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz) return 1; - ctx->sz++; + assert(ctx->read_ctxs[ENCODE_STAGE].valid == 1); + if (ctx->read_ctxs[ENCODE_STAGE].sz + 1 + MAX_PRE_FRAMES > ctx->max_sz) + return 1; + ctx->read_ctxs[ENCODE_STAGE].sz++; + if (ctx->read_ctxs[LAP_STAGE].valid) { + ctx->read_ctxs[LAP_STAGE].sz++; + } buf = pop(ctx, &ctx->write_idx); new_dimensions = width != buf->img.y_crop_width || @@ -114,68 +114,25 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, uv_height > buf->img.uv_height; assert(!larger_dimensions || new_dimensions); -#if USE_PARTIAL_COPY - // TODO(jkoleszar): This is disabled for now, as - // av1_copy_and_extend_frame_with_rect is not subsampling/alpha aware. - - // Only do this partial copy if the following conditions are all met: - // 1. Lookahead queue has has size of 1. - // 2. Active map is provided. - // 3. This is not a key frame, golden nor altref frame. - if (!new_dimensions && ctx->max_sz == 1 && active_map && !flags) { - for (row = 0; row < mb_rows; ++row) { - col = 0; - - while (1) { - // Find the first active macroblock in this row. - for (; col < mb_cols; ++col) { - if (active_map[col]) break; - } - - // No more active macroblock in this row. - if (col == mb_cols) break; - - // Find the end of active region in this row. - active_end = col; - - for (; active_end < mb_cols; ++active_end) { - if (!active_map[active_end]) break; - } - - // Only copy this active region. - av1_copy_and_extend_frame_with_rect(src, &buf->img, row << 4, col << 4, - 16, (active_end - col) << 4); - - // Start again from the end of this active region. - col = active_end; - } - - active_map += mb_cols; - } - } else { -#endif - if (larger_dimensions) { - YV12_BUFFER_CONFIG new_img; - memset(&new_img, 0, sizeof(new_img)); - if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x, - subsampling_y, use_highbitdepth, - AOM_BORDER_IN_PIXELS, 0)) - return 1; - aom_free_frame_buffer(&buf->img); - buf->img = new_img; - } else if (new_dimensions) { - buf->img.y_crop_width = src->y_crop_width; - buf->img.y_crop_height = src->y_crop_height; - buf->img.uv_crop_width = src->uv_crop_width; - buf->img.uv_crop_height = src->uv_crop_height; - buf->img.subsampling_x = src->subsampling_x; - buf->img.subsampling_y = src->subsampling_y; - } - // Partial copy not implemented yet - av1_copy_and_extend_frame(src, &buf->img); -#if USE_PARTIAL_COPY + if (larger_dimensions) { + YV12_BUFFER_CONFIG new_img; + memset(&new_img, 0, sizeof(new_img)); + if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x, + subsampling_y, use_highbitdepth, + AOM_BORDER_IN_PIXELS, 0)) + return 1; + aom_free_frame_buffer(&buf->img); + buf->img = new_img; + } else if (new_dimensions) { + buf->img.y_crop_width = src->y_crop_width; + buf->img.y_crop_height = src->y_crop_height; + buf->img.uv_crop_width = src->uv_crop_width; + buf->img.uv_crop_height = src->uv_crop_height; + buf->img.subsampling_x = src->subsampling_x; + buf->img.subsampling_y = src->subsampling_y; } -#endif + // Partial copy not implemented yet + av1_copy_and_extend_frame(src, &buf->img); buf->ts_start = ts_start; buf->ts_end = ts_end; @@ -185,32 +142,41 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, return 0; } -struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, - int drain) { +struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain, + COMPRESSOR_STAGE stage) { struct lookahead_entry *buf = NULL; - - if (ctx && ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) { - buf = pop(ctx, &ctx->read_idx); - ctx->sz--; + if (ctx) { + struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; + assert(read_ctx->valid == 1); + if (read_ctx->sz && (drain || read_ctx->sz == read_ctx->pop_sz)) { + buf = pop(ctx, &read_ctx->read_idx); + read_ctx->sz--; + } } return buf; } -struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, - int index) { +struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, int index, + COMPRESSOR_STAGE stage) { struct lookahead_entry *buf = NULL; + struct read_ctx *read_ctx = NULL; + if (ctx == NULL) { + return buf; + } + read_ctx = &ctx->read_ctxs[stage]; + assert(read_ctx->valid == 1); if (index >= 0) { // Forward peek - if (index < ctx->sz) { - index += ctx->read_idx; + if (index < read_ctx->sz) { + index += read_ctx->read_idx; if (index >= ctx->max_sz) index -= ctx->max_sz; buf = ctx->buf + index; } } else if (index < 0) { // Backward peek if (-index <= MAX_PRE_FRAMES) { - index += (int)(ctx->read_idx); + index += (int)(read_ctx->read_idx); if (index < 0) index += (int)(ctx->max_sz); buf = ctx->buf + index; } @@ -219,4 +185,21 @@ struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, return buf; } -unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx) { return ctx->sz; } +unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx, + COMPRESSOR_STAGE stage) { + struct read_ctx *read_ctx = NULL; + assert(ctx != NULL); + + read_ctx = &ctx->read_ctxs[stage]; + assert(read_ctx->valid == 1); + return read_ctx->sz; +} + +int av1_lookahead_pop_sz(struct lookahead_ctx *ctx, COMPRESSOR_STAGE stage) { + struct read_ctx *read_ctx = NULL; + assert(ctx != NULL); + + read_ctx = &ctx->read_ctxs[stage]; + assert(read_ctx->valid == 1); + return read_ctx->pop_sz; +} diff --git a/media/libaom/src/av1/encoder/lookahead.h b/media/libaom/src/av1/encoder/lookahead.h index 3b2d94b08e..03693d383f 100644 --- a/media/libaom/src/av1/encoder/lookahead.h +++ b/media/libaom/src/av1/encoder/lookahead.h @@ -19,7 +19,10 @@ extern "C" { #endif -#define MAX_LAG_BUFFERS 25 +#define MAX_LAG_BUFFERS 35 +#define MAX_LAP_BUFFERS 35 +#define MAX_TOTAL_BUFFERS (MAX_LAG_BUFFERS + MAX_LAP_BUFFERS) +#define LAP_LAG_IN_FRAMES 17 struct lookahead_entry { YV12_BUFFER_CONFIG img; @@ -31,12 +34,20 @@ struct lookahead_entry { // The max of past frames we want to keep in the queue. #define MAX_PRE_FRAMES 1 +enum { ENCODE_STAGE, LAP_STAGE, MAX_STAGES } UENUM1BYTE(COMPRESSOR_STAGE); + +struct read_ctx { + int sz; /* Number of buffers currently in the queue */ + int read_idx; /* Read index */ + int pop_sz; /* Size to check for pop condition */ + int valid; /* Is this ctx valid? */ +}; + struct lookahead_ctx { - int max_sz; /* Absolute size of the queue */ - int sz; /* Number of buffers currently in the queue */ - int read_idx; /* Read index */ - int write_idx; /* Write index */ - struct lookahead_entry *buf; /* Buffer list */ + int max_sz; /* Absolute size of the queue */ + int write_idx; /* Write index */ + struct read_ctx read_ctxs[MAX_STAGES]; /* Read context */ + struct lookahead_entry *buf; /* Buffer list */ }; /**\brief Initializes the lookahead stage @@ -47,7 +58,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, int is_scale); + const int border_in_pixels, int byte_alignment, int num_lap_buffers); /**\brief Destroys the lookahead stage */ @@ -82,7 +93,8 @@ int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, * \retval NULL, if drain set and queue is empty * \retval NULL, if drain not set and queue not of the configured depth */ -struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain); +struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain, + COMPRESSOR_STAGE stage); /**\brief Get a future source buffer to encode * @@ -91,14 +103,17 @@ struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain); * * \retval NULL, if no buffer exists at the specified index */ -struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, - int index); +struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, int index, + COMPRESSOR_STAGE stage); /**\brief Get the number of frames currently in the lookahead queue * * \param[in] ctx Pointer to the lookahead context */ -unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx); +unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx, + COMPRESSOR_STAGE stage); + +int av1_lookahead_pop_sz(struct lookahead_ctx *ctx, COMPRESSOR_STAGE stage); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/encoder/mbgraph.c b/media/libaom/src/av1/encoder/mbgraph.c deleted file mode 100644 index 0cb628682f..0000000000 --- a/media/libaom/src/av1/encoder/mbgraph.c +++ /dev/null @@ -1,401 +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 - -#include "config/av1_rtcd.h" -#include "config/aom_dsp_rtcd.h" - -#include "aom_dsp/aom_dsp_common.h" -#include "aom_mem/aom_mem.h" -#include "aom_ports/system_state.h" -#include "av1/common/blockd.h" -#include "av1/common/reconinter.h" -#include "av1/common/reconintra.h" -#include "av1/encoder/mcomp.h" -#include "av1/encoder/reconinter_enc.h" -#include "av1/encoder/segmentation.h" - -static unsigned int do_16x16_motion_iteration(AV1_COMP *cpi, const MV *ref_mv, - int mb_row, int mb_col) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv; - const aom_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[BLOCK_16X16]; - - const MvLimits tmp_mv_limits = x->mv_limits; - MV ref_full; - int cost_list[5]; - - // Further step/diamond searches as necessary - int step_param = mv_sf->reduce_first_step_size; - step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2); - - av1_set_mv_search_range(&x->mv_limits, ref_mv); - - ref_full.col = ref_mv->col >> 3; - ref_full.row = ref_mv->row >> 3; - - /*cpi->sf.search_method == HEX*/ - av1_hex_search(x, &ref_full, step_param, x->errorperbit, 0, - cond_cost_list(cpi, cost_list), &v_fn_ptr, 0, ref_mv); - - // Try sub-pixel MC - // if (bestsme > error_thresh && bestsme < INT_MAX) - if (cpi->common.cur_frame_force_integer_mv == 1) { - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - } else { - int distortion; - unsigned int sse; - cpi->find_fractional_mv_step( - x, &cpi->common, mb_row, mb_col, ref_mv, - cpi->common.allow_high_precision_mv, x->errorperbit, &v_fn_ptr, 0, - mv_sf->subpel_iters_per_step, cond_cost_list(cpi, cost_list), NULL, - NULL, &distortion, &sse, NULL, NULL, 0, 0, 0, 0, 0, 1); - } - - if (has_second_ref(xd->mi[0])) - xd->mi[0]->mode = NEW_NEWMV; - else - xd->mi[0]->mode = NEWMV; - - xd->mi[0]->mv[0] = x->best_mv; - xd->mi[0]->ref_frame[1] = NONE_FRAME; - - av1_enc_build_inter_predictor(&cpi->common, xd, mb_row, mb_col, NULL, - BLOCK_16X16, AOM_PLANE_Y, AOM_PLANE_Y); - - /* restore UMV window */ - x->mv_limits = tmp_mv_limits; - - return aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride, - xd->plane[0].dst.buf, xd->plane[0].dst.stride); -} - -static int do_16x16_motion_search(AV1_COMP *cpi, const MV *ref_mv, int mb_row, - int mb_col) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - unsigned int err, tmp_err; - MV best_mv; - - // Try zero MV first - // FIXME should really use something like near/nearest MV and/or MV prediction - err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride, - xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride); - best_mv.col = best_mv.row = 0; - - // Test last reference frame using the previous best mv as the - // starting point (best reference) for the search - tmp_err = do_16x16_motion_iteration(cpi, ref_mv, mb_row, mb_col); - if (tmp_err < err) { - err = tmp_err; - best_mv = x->best_mv.as_mv; - } - - // If the current best reference mv is not centered on 0,0 then do a 0,0 - // based search as well. - if (ref_mv->row != 0 || ref_mv->col != 0) { - MV zero_ref_mv = kZeroMv; - - tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, mb_row, mb_col); - if (tmp_err < err) { - err = tmp_err; - best_mv = x->best_mv.as_mv; - } - } - - x->best_mv.as_mv = best_mv; - return err; -} - -static int do_16x16_zerozero_search(AV1_COMP *cpi, int_mv *dst_mv) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - unsigned int err; - - // Try zero MV first - // FIXME should really use something like near/nearest MV and/or MV prediction - err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride, - xd->plane[0].pre[0].buf, xd->plane[0].pre[0].stride); - - dst_mv->as_int = 0; - - return err; -} -static int find_best_16x16_intra(AV1_COMP *cpi, PREDICTION_MODE *pbest_mode) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - PREDICTION_MODE best_mode = -1, mode; - unsigned int best_err = INT_MAX; - - // calculate SATD for each intra prediction mode; - // we're intentionally not doing 4x4, we just want a rough estimate - for (mode = INTRA_MODE_START; mode < INTRA_MODE_END; mode++) { - unsigned int err; - - xd->mi[0]->mode = mode; - av1_predict_intra_block(cm, xd, 16, 16, TX_16X16, mode, 0, 0, - FILTER_INTRA_MODES, x->plane[0].src.buf, - x->plane[0].src.stride, xd->plane[0].dst.buf, - xd->plane[0].dst.stride, 0, 0, 0); - err = aom_sad16x16(x->plane[0].src.buf, x->plane[0].src.stride, - xd->plane[0].dst.buf, xd->plane[0].dst.stride); - - // find best - if (err < best_err) { - best_err = err; - best_mode = mode; - } - } - - if (pbest_mode) *pbest_mode = best_mode; - - return best_err; -} - -static void update_mbgraph_mb_stats(AV1_COMP *cpi, MBGRAPH_MB_STATS *stats, - YV12_BUFFER_CONFIG *buf, int mb_y_offset, - YV12_BUFFER_CONFIG *golden_ref, - const MV *prev_golden_ref_mv, - YV12_BUFFER_CONFIG *alt_ref, int mb_row, - int mb_col) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - int intra_error; - AV1_COMMON *cm = &cpi->common; - - // FIXME in practice we're completely ignoring chroma here - x->plane[0].src.buf = buf->y_buffer + mb_y_offset; - x->plane[0].src.stride = buf->y_stride; - - xd->plane[0].dst.buf = cm->cur_frame->buf.y_buffer + mb_y_offset; - xd->plane[0].dst.stride = cm->cur_frame->buf.y_stride; - - // do intra 16x16 prediction - intra_error = find_best_16x16_intra(cpi, &stats->ref[INTRA_FRAME].m.mode); - if (intra_error <= 0) intra_error = 1; - stats->ref[INTRA_FRAME].err = intra_error; - - // Golden frame MV search, if it exists and is different than last frame - if (golden_ref) { - int g_motion_error; - xd->plane[0].pre[0].buf = golden_ref->y_buffer + mb_y_offset; - xd->plane[0].pre[0].stride = golden_ref->y_stride; - g_motion_error = - do_16x16_motion_search(cpi, prev_golden_ref_mv, mb_row, mb_col); - stats->ref[GOLDEN_FRAME].m.mv = x->best_mv; - stats->ref[GOLDEN_FRAME].err = g_motion_error; - } else { - stats->ref[GOLDEN_FRAME].err = INT_MAX; - stats->ref[GOLDEN_FRAME].m.mv.as_int = 0; - } - - // Do an Alt-ref frame MV search, if it exists and is different than - // last/golden frame. - if (alt_ref) { - int a_motion_error; - xd->plane[0].pre[0].buf = alt_ref->y_buffer + mb_y_offset; - xd->plane[0].pre[0].stride = alt_ref->y_stride; - a_motion_error = - do_16x16_zerozero_search(cpi, &stats->ref[ALTREF_FRAME].m.mv); - - stats->ref[ALTREF_FRAME].err = a_motion_error; - } else { - stats->ref[ALTREF_FRAME].err = INT_MAX; - stats->ref[ALTREF_FRAME].m.mv.as_int = 0; - } -} - -static void update_mbgraph_frame_stats(AV1_COMP *cpi, - MBGRAPH_FRAME_STATS *stats, - YV12_BUFFER_CONFIG *buf, - YV12_BUFFER_CONFIG *golden_ref, - YV12_BUFFER_CONFIG *alt_ref) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - AV1_COMMON *const cm = &cpi->common; - - int mb_col, mb_row, offset = 0; - int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0; - MV gld_top_mv = kZeroMv; - MB_MODE_INFO mi_local; - - av1_zero(mi_local); - // Set up limit values for motion vectors to prevent them extending outside - // the UMV borders. - x->mv_limits.row_min = -BORDER_MV_PIXELS_B16; - x->mv_limits.row_max = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16; - xd->up_available = 0; - xd->plane[0].dst.stride = buf->y_stride; - xd->plane[0].pre[0].stride = buf->y_stride; - xd->plane[1].dst.stride = buf->uv_stride; - xd->mi[0] = &mi_local; - mi_local.sb_type = BLOCK_16X16; - mi_local.ref_frame[0] = LAST_FRAME; - mi_local.ref_frame[1] = NONE_FRAME; - - for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) { - MV gld_left_mv = gld_top_mv; - int mb_y_in_offset = mb_y_offset; - int arf_y_in_offset = arf_y_offset; - int gld_y_in_offset = gld_y_offset; - - // Set up limit values for motion vectors to prevent them extending outside - // the UMV borders. - x->mv_limits.col_min = -BORDER_MV_PIXELS_B16; - x->mv_limits.col_max = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16; - xd->left_available = 0; - - for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { - MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col]; - - update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset, golden_ref, - &gld_left_mv, alt_ref, mb_row, mb_col); - gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv; - if (mb_col == 0) { - gld_top_mv = gld_left_mv; - } - xd->left_available = 1; - mb_y_in_offset += 16; - gld_y_in_offset += 16; - arf_y_in_offset += 16; - x->mv_limits.col_min -= 16; - x->mv_limits.col_max -= 16; - } - xd->up_available = 1; - mb_y_offset += buf->y_stride * 16; - gld_y_offset += golden_ref->y_stride * 16; - if (alt_ref) arf_y_offset += alt_ref->y_stride * 16; - x->mv_limits.row_min -= 16; - x->mv_limits.row_max -= 16; - offset += cm->mb_cols; - } -} - -// void separate_arf_mbs_byzz -static void separate_arf_mbs(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - int mb_col, mb_row, offset, i; - int mi_row, mi_col; - int ncnt[4] = { 0 }; - int n_frames = cpi->mbgraph_n_frames; - - int *arf_not_zz; - - CHECK_MEM_ERROR( - cm, arf_not_zz, - aom_calloc(cm->mb_rows * cm->mb_cols * sizeof(*arf_not_zz), 1)); - - // We are not interested in results beyond the alt ref itself. - if (n_frames > cpi->rc.frames_till_gf_update_due) - n_frames = cpi->rc.frames_till_gf_update_due; - - // defer cost to reference frames - for (i = n_frames - 1; i >= 0; i--) { - MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; - - for (offset = 0, mb_row = 0; mb_row < cm->mb_rows; - offset += cm->mb_cols, mb_row++) { - for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) { - MBGRAPH_MB_STATS *mb_stats = &frame_stats->mb_stats[offset + mb_col]; - - int altref_err = mb_stats->ref[ALTREF_FRAME].err; - int intra_err = mb_stats->ref[INTRA_FRAME].err; - int golden_err = mb_stats->ref[GOLDEN_FRAME].err; - - // Test for altref vs intra and gf and that its mv was 0,0. - if (altref_err > 1000 || altref_err > intra_err || - altref_err > golden_err) { - arf_not_zz[offset + mb_col]++; - } - } - } - } - - // arf_not_zz is indexed by MB, but this loop is indexed by MI to avoid out - // of bound access in segmentation_map - for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) { - for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) { - // If any of the blocks in the sequence failed then the MB - // goes in segment 0 - if (arf_not_zz[mi_row / 2 * cm->mb_cols + mi_col / 2]) { - ncnt[0]++; - cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 0; - } else { - cpi->segmentation_map[mi_row * cm->mi_cols + mi_col] = 1; - ncnt[1]++; - } - } - } - - // Only bother with segmentation if over 10% of the MBs in static segment - // if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) ) - if (1) { - // Note % of blocks that are marked as static - if (cm->MBs) - cpi->static_mb_pct = (ncnt[1] * 100) / (cm->mi_rows * cm->mi_cols); - - // This error case should not be reachable as this function should - // never be called with the common data structure uninitialized. - else - cpi->static_mb_pct = 0; - - av1_enable_segmentation(&cm->seg); - } else { - cpi->static_mb_pct = 0; - av1_disable_segmentation(&cm->seg); - } - - // Free localy allocated storage - aom_free(arf_not_zz); -} - -void av1_update_mbgraph_stats(AV1_COMP *cpi) { - AV1_COMMON *const cm = &cpi->common; - int i, n_frames = av1_lookahead_depth(cpi->lookahead); - YV12_BUFFER_CONFIG *golden_ref = &get_ref_frame_buf(cm, GOLDEN_FRAME)->buf; - - assert(golden_ref != NULL); - - // we need to look ahead beyond where the ARF transitions into - // being a GF - so exit if we don't look ahead beyond that - if (n_frames <= cpi->rc.frames_till_gf_update_due) return; - - if (n_frames > MAX_LAG_BUFFERS) n_frames = MAX_LAG_BUFFERS; - - cpi->mbgraph_n_frames = n_frames; - for (i = 0; i < n_frames; i++) { - MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; - memset(frame_stats->mb_stats, 0, - cm->mb_rows * cm->mb_cols * sizeof(*cpi->mbgraph_stats[i].mb_stats)); - } - - // do motion search to find contribution of each reference to data - // later on in this GF group - // FIXME really, the GF/last MC search should be done forward, and - // the ARF MC search backwards, to get optimal results for MV caching - for (i = 0; i < n_frames; i++) { - MBGRAPH_FRAME_STATS *frame_stats = &cpi->mbgraph_stats[i]; - struct lookahead_entry *q_cur = av1_lookahead_peek(cpi->lookahead, i); - - assert(q_cur != NULL); - - update_mbgraph_frame_stats(cpi, frame_stats, &q_cur->img, golden_ref, - cpi->source); - } - - aom_clear_system_state(); - - separate_arf_mbs(cpi); -} diff --git a/media/libaom/src/av1/encoder/mbgraph.h b/media/libaom/src/av1/encoder/mbgraph.h deleted file mode 100644 index ba08476f7a..0000000000 --- a/media/libaom/src/av1/encoder/mbgraph.h +++ /dev/null @@ -1,41 +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. - */ - -#ifndef AOM_AV1_ENCODER_MBGRAPH_H_ -#define AOM_AV1_ENCODER_MBGRAPH_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - struct { - int err; - union { - int_mv mv; - PREDICTION_MODE mode; - } m; - } ref[REF_FRAMES]; -} MBGRAPH_MB_STATS; - -typedef struct { - MBGRAPH_MB_STATS *mb_stats; -} MBGRAPH_FRAME_STATS; - -struct AV1_COMP; - -void av1_update_mbgraph_stats(struct AV1_COMP *cpi); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // AOM_AV1_ENCODER_MBGRAPH_H_ diff --git a/media/libaom/src/av1/encoder/mcomp.c b/media/libaom/src/av1/encoder/mcomp.c index 921d52ac44..43f7f5c6c9 100644 --- a/media/libaom/src/av1/encoder/mcomp.c +++ b/media/libaom/src/av1/encoder/mcomp.c @@ -19,37 +19,120 @@ #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/av1_common_int.h" #include "av1/common/common.h" +#include "av1/common/filter.h" #include "av1/common/mvref_common.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" #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" -// #define NEW_DIAMOND_SEARCH - -static INLINE const uint8_t *get_buf_from_mv(const struct buf_2d *buf, - const MV *mv) { - return &buf->buf[mv->row * buf->stride + mv->col]; +static INLINE void init_mv_cost_params(MV_COST_PARAMS *mv_cost_params, + const MACROBLOCK *x, const MV *ref_mv) { + mv_cost_params->ref_mv = ref_mv; + mv_cost_params->full_ref_mv = get_fullmv_from_mv(ref_mv); + mv_cost_params->error_per_bit = x->errorperbit; + mv_cost_params->sad_per_bit = x->sadperbit; + mv_cost_params->mvjcost = x->nmv_vec_cost; + mv_cost_params->mvcost[0] = x->mv_cost_stack[0]; + mv_cost_params->mvcost[1] = x->mv_cost_stack[1]; + mv_cost_params->mv_cost_type = x->mv_cost_type; } -void av1_set_mv_search_range(MvLimits *mv_limits, const MV *mv) { - int col_min = (mv->col >> 3) - MAX_FULL_PEL_VAL + (mv->col & 7 ? 1 : 0); - int row_min = (mv->row >> 3) - MAX_FULL_PEL_VAL + (mv->row & 7 ? 1 : 0); - int col_max = (mv->col >> 3) + MAX_FULL_PEL_VAL; - int row_max = (mv->row >> 3) + MAX_FULL_PEL_VAL; +static INLINE void init_ms_buffers(MSBuffers *ms_buffers, const MACROBLOCK *x) { + ms_buffers->ref = &x->e_mbd.plane[0].pre[0]; + ms_buffers->src = &x->plane[0].src; - col_min = AOMMAX(col_min, (MV_LOW >> 3) + 1); - row_min = AOMMAX(row_min, (MV_LOW >> 3) + 1); - col_max = AOMMIN(col_max, (MV_UPP >> 3) - 1); - row_max = AOMMIN(row_max, (MV_UPP >> 3) - 1); + av1_set_ms_compound_refs(ms_buffers, NULL, NULL, 0, 0); + + ms_buffers->wsrc = x->wsrc_buf; + ms_buffers->obmc_mask = x->mask_buf; +} + +void av1_make_default_fullpel_ms_params( + FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const struct AV1_COMP *cpi, + const MACROBLOCK *x, BLOCK_SIZE bsize, const MV *ref_mv, + const search_site_config *search_sites) { + // High level params + ms_params->bsize = bsize; + ms_params->vfp = &cpi->fn_ptr[bsize]; + + init_ms_buffers(&ms_params->ms_buffers, x); + + ms_params->search_method = cpi->sf.mv_sf.search_method; + ms_params->search_sites = search_sites; + + ms_params->mesh_patterns[0] = cpi->sf.mv_sf.mesh_patterns; + ms_params->mesh_patterns[1] = cpi->sf.mv_sf.intrabc_mesh_patterns; + ms_params->force_mesh_thresh = cpi->sf.mv_sf.exhaustive_searches_thresh; + ms_params->prune_mesh_search = cpi->sf.mv_sf.prune_mesh_search; + ms_params->run_mesh_search = 0; + + ms_params->is_intra_mode = 0; + + ms_params->fast_obmc_search = cpi->sf.mv_sf.obmc_full_pixel_search_level; + + ms_params->mv_limits = x->mv_limits; + av1_set_mv_search_range(&ms_params->mv_limits, ref_mv); + + // Mvcost params + init_mv_cost_params(&ms_params->mv_cost_params, x, ref_mv); +} + +void av1_make_default_subpel_ms_params(SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct AV1_COMP *cpi, + const MACROBLOCK *x, BLOCK_SIZE bsize, + const MV *ref_mv, const int *cost_list) { + const AV1_COMMON *cm = &cpi->common; + // High level params + ms_params->allow_hp = cm->features.allow_high_precision_mv; + ms_params->forced_stop = cpi->sf.mv_sf.subpel_force_stop; + ms_params->iters_per_step = cpi->sf.mv_sf.subpel_iters_per_step; + ms_params->cost_list = cond_cost_list_const(cpi, cost_list); + + av1_set_subpel_mv_search_range(&ms_params->mv_limits, &x->mv_limits, ref_mv); + + // Mvcost params + init_mv_cost_params(&ms_params->mv_cost_params, x, ref_mv); + + // Subpel variance params + ms_params->var_params.vfp = &cpi->fn_ptr[bsize]; + ms_params->var_params.subpel_search_type = + cpi->sf.mv_sf.use_accurate_subpel_search; + ms_params->var_params.w = block_size_wide[bsize]; + ms_params->var_params.h = block_size_high[bsize]; + + // Ref and src buffers + MSBuffers *ms_buffers = &ms_params->var_params.ms_buffers; + init_ms_buffers(ms_buffers, x); +} + +static INLINE int get_offset_from_fullmv(const FULLPEL_MV *mv, int stride) { + return mv->row * stride + mv->col; +} + +static INLINE const uint8_t *get_buf_from_fullmv(const struct buf_2d *buf, + const FULLPEL_MV *mv) { + return &buf->buf[get_offset_from_fullmv(mv, buf->stride)]; +} + +void av1_set_mv_search_range(FullMvLimits *mv_limits, const MV *mv) { + int col_min = + GET_MV_RAWPEL(mv->col) - MAX_FULL_PEL_VAL + (mv->col & 7 ? 1 : 0); + int row_min = + GET_MV_RAWPEL(mv->row) - MAX_FULL_PEL_VAL + (mv->row & 7 ? 1 : 0); + int col_max = GET_MV_RAWPEL(mv->col) + MAX_FULL_PEL_VAL; + int row_max = GET_MV_RAWPEL(mv->row) + MAX_FULL_PEL_VAL; + + col_min = AOMMAX(col_min, GET_MV_RAWPEL(MV_LOW) + 1); + row_min = AOMMAX(row_min, GET_MV_RAWPEL(MV_LOW) + 1); + col_max = AOMMIN(col_max, GET_MV_RAWPEL(MV_UPP) - 1); + row_max = AOMMIN(row_max, GET_MV_RAWPEL(MV_UPP) - 1); // Get intersection of UMV window and valid MV window to reduce # of checks // in diamond search. @@ -70,948 +153,242 @@ int av1_init_search_range(int size) { return sr; } +// ============================================================================ +// Cost of motion vectors +// ============================================================================ +// TODO(any): Adaptively adjust the regularization strength based on image size +// and motion activity instead of using hard-coded values. It seems like we +// roughly half the lambda for each increase in resolution +// These are multiplier used to perform regularization in motion compensation +// when x->mv_cost_type is set to MV_COST_L1. +// LOWRES +#define SSE_LAMBDA_LOWRES 2 // Used by mv_cost_err_fn +#define SAD_LAMBDA_LOWRES 32 // Used by mvsad_err_cost during full pixel search +// MIDRES +#define SSE_LAMBDA_MIDRES 0 // Used by mv_cost_err_fn +#define SAD_LAMBDA_MIDRES 15 // Used by mvsad_err_cost during full pixel search +// HDRES +#define SSE_LAMBDA_HDRES 1 // Used by mv_cost_err_fn +#define SAD_LAMBDA_HDRES 8 // Used by mvsad_err_cost during full pixel search + +// Returns the rate of encoding the current motion vector based on the +// joint_cost and comp_cost. joint_costs covers the cost of transmitting +// JOINT_MV, and comp_cost covers the cost of transmitting the actual motion +// vector. static INLINE int mv_cost(const MV *mv, const int *joint_cost, - int *const comp_cost[2]) { + const int *const comp_cost[2]) { return joint_cost[av1_get_mv_joint(mv)] + comp_cost[0][mv->row] + comp_cost[1][mv->col]; } -int av1_mv_bit_cost(const MV *mv, const MV *ref, const int *mvjcost, +#define CONVERT_TO_CONST_MVCOST(ptr) ((const int *const *)(ptr)) +// Returns the cost of encoding the motion vector diff := *mv - *ref. The cost +// is defined as the rate required to encode diff * weight, rounded to the +// nearest 2 ** 7. +// This is NOT used during motion compensation. +int av1_mv_bit_cost(const MV *mv, const MV *ref_mv, const int *mvjcost, int *mvcost[2], int weight) { - const MV diff = { mv->row - ref->row, mv->col - ref->col }; - return ROUND_POWER_OF_TWO(mv_cost(&diff, mvjcost, mvcost) * weight, 7); -} - -#define PIXEL_TRANSFORM_ERROR_SCALE 4 -static int mv_err_cost(const MV *mv, const MV *ref, const int *mvjcost, - int *mvcost[2], int error_per_bit) { - if (mvcost) { - const MV diff = { mv->row - ref->row, mv->col - ref->col }; - return (int)ROUND_POWER_OF_TWO_64( - (int64_t)mv_cost(&diff, mvjcost, mvcost) * error_per_bit, - RDDIV_BITS + AV1_PROB_COST_SHIFT - RD_EPB_SHIFT + - PIXEL_TRANSFORM_ERROR_SCALE); - } - return 0; -} - -static int mvsad_err_cost(const MACROBLOCK *x, const MV *mv, const MV *ref, - int sad_per_bit) { - const MV diff = { (mv->row - ref->row) * 8, (mv->col - ref->col) * 8 }; + const MV diff = { mv->row - ref_mv->row, mv->col - ref_mv->col }; return ROUND_POWER_OF_TWO( - (unsigned)mv_cost(&diff, x->nmv_vec_cost, x->mv_cost_stack) * sad_per_bit, - AV1_PROB_COST_SHIFT); + mv_cost(&diff, mvjcost, CONVERT_TO_CONST_MVCOST(mvcost)) * weight, 7); } +// Returns the cost of using the current mv during the motion search. This is +// used when var is used as the error metric. +#define PIXEL_TRANSFORM_ERROR_SCALE 4 +static INLINE int mv_err_cost(const MV *mv, const MV *ref_mv, + const int *mvjcost, const int *const mvcost[2], + int error_per_bit, MV_COST_TYPE mv_cost_type) { + const MV diff = { mv->row - ref_mv->row, mv->col - ref_mv->col }; + const MV abs_diff = { abs(diff.row), abs(diff.col) }; + + switch (mv_cost_type) { + case MV_COST_ENTROPY: + if (mvcost) { + return (int)ROUND_POWER_OF_TWO_64( + (int64_t)mv_cost(&diff, mvjcost, mvcost) * error_per_bit, + RDDIV_BITS + AV1_PROB_COST_SHIFT - RD_EPB_SHIFT + + PIXEL_TRANSFORM_ERROR_SCALE); + } + return 0; + case MV_COST_L1_LOWRES: + return (SSE_LAMBDA_LOWRES * (abs_diff.row + abs_diff.col)) >> 3; + case MV_COST_L1_MIDRES: + return (SSE_LAMBDA_MIDRES * (abs_diff.row + abs_diff.col)) >> 3; + case MV_COST_L1_HDRES: + return (SSE_LAMBDA_HDRES * (abs_diff.row + abs_diff.col)) >> 3; + case MV_COST_NONE: return 0; + default: assert(0 && "Invalid rd_cost_type"); return 0; + } +} + +static INLINE int mv_err_cost_(const MV *mv, + const MV_COST_PARAMS *mv_cost_params) { + return mv_err_cost(mv, mv_cost_params->ref_mv, mv_cost_params->mvjcost, + mv_cost_params->mvcost, mv_cost_params->error_per_bit, + mv_cost_params->mv_cost_type); +} + +// Returns the cost of using the current mv during the motion search. This is +// only used during full pixel motion search when sad is used as the error +// metric +static INLINE int mvsad_err_cost(const FULLPEL_MV *mv, const FULLPEL_MV *ref_mv, + const int *mvjcost, const int *const mvcost[2], + int sad_per_bit, MV_COST_TYPE mv_cost_type) { + const MV diff = { GET_MV_SUBPEL(mv->row - ref_mv->row), + GET_MV_SUBPEL(mv->col - ref_mv->col) }; + + switch (mv_cost_type) { + case MV_COST_ENTROPY: + return ROUND_POWER_OF_TWO( + (unsigned)mv_cost(&diff, mvjcost, CONVERT_TO_CONST_MVCOST(mvcost)) * + sad_per_bit, + AV1_PROB_COST_SHIFT); + case MV_COST_L1_LOWRES: + return (SAD_LAMBDA_LOWRES * (abs(diff.row) + abs(diff.col))) >> 3; + case MV_COST_L1_MIDRES: + return (SAD_LAMBDA_MIDRES * (abs(diff.row) + abs(diff.col))) >> 3; + case MV_COST_L1_HDRES: + return (SAD_LAMBDA_HDRES * (abs(diff.row) + abs(diff.col))) >> 3; + case MV_COST_NONE: return 0; + default: assert(0 && "Invalid rd_cost_type"); return 0; + } +} + +static INLINE int mvsad_err_cost_(const FULLPEL_MV *mv, + const MV_COST_PARAMS *mv_cost_params) { + return mvsad_err_cost(mv, &mv_cost_params->full_ref_mv, + mv_cost_params->mvjcost, mv_cost_params->mvcost, + mv_cost_params->sad_per_bit, + mv_cost_params->mv_cost_type); +} + +// ============================================================================= +// Fullpixel Motion Search: Translational +// ============================================================================= +#define MAX_PATTERN_SCALES 11 +#define MAX_PATTERN_CANDIDATES 8 // max number of candidates per scale +#define PATTERN_CANDIDATES_REF 3 // number of refinement candidates + void av1_init_dsmotion_compensation(search_site_config *cfg, int stride) { - int len, ss_count = 1; + int ss_count = 0; + int stage_index = MAX_MVSEARCH_STEPS - 1; - cfg->ss[0].mv.col = cfg->ss[0].mv.row = 0; - cfg->ss[0].offset = 0; + cfg->ss[stage_index][0].mv.col = cfg->ss[stage_index][0].mv.row = 0; + cfg->ss[stage_index][0].offset = 0; cfg->stride = stride; - for (len = MAX_FIRST_STEP; len > 0; len /= 2) { - // Generate offsets for 4 search sites per step. - const MV ss_mvs[] = { { -len, 0 }, { len, 0 }, { 0, -len }, { 0, len } }; - int i; - for (i = 0; i < 4; ++i) { - search_site *const ss = &cfg->ss[ss_count++]; - ss->mv = ss_mvs[i]; - ss->offset = ss->mv.row * stride + ss->mv.col; - } - } + for (int radius = MAX_FIRST_STEP; radius > 0; radius /= 2) { + int num_search_pts = 8; + const FULLPEL_MV ss_mvs[13] = { + { 0, 0 }, { -radius, 0 }, { radius, 0 }, + { 0, -radius }, { 0, radius }, { -radius, -radius }, + { radius, radius }, { -radius, radius }, { radius, -radius }, + }; + + int i; + for (i = 0; i <= num_search_pts; ++i) { + search_site *const ss = &cfg->ss[stage_index][i]; + ss->mv = ss_mvs[i]; + ss->offset = get_offset_from_fullmv(&ss->mv, stride); + } + cfg->searches_per_step[stage_index] = num_search_pts; + cfg->radius[stage_index] = radius; + --stage_index; + ++ss_count; + } + cfg->ss_count = ss_count; +} + +void av1_init_motion_fpf(search_site_config *cfg, int stride) { + int ss_count = 0; + int stage_index = MAX_MVSEARCH_STEPS - 1; + + cfg->ss[stage_index][0].mv.col = cfg->ss[stage_index][0].mv.row = 0; + cfg->ss[stage_index][0].offset = 0; + cfg->stride = stride; + + for (int radius = MAX_FIRST_STEP; radius > 0; radius /= 2) { + // Generate offsets for 8 search sites per step. + int tan_radius = AOMMAX((int)(0.41 * radius), 1); + int num_search_pts = 12; + if (radius == 1) num_search_pts = 8; + + const FULLPEL_MV ss_mvs[13] = { + { 0, 0 }, + { -radius, 0 }, + { radius, 0 }, + { 0, -radius }, + { 0, radius }, + { -radius, -tan_radius }, + { radius, tan_radius }, + { -tan_radius, radius }, + { tan_radius, -radius }, + { -radius, tan_radius }, + { radius, -tan_radius }, + { tan_radius, radius }, + { -tan_radius, -radius }, + }; + + int i; + for (i = 0; i <= num_search_pts; ++i) { + search_site *const ss = &cfg->ss[stage_index][i]; + ss->mv = ss_mvs[i]; + ss->offset = get_offset_from_fullmv(&ss->mv, stride); + } + cfg->searches_per_step[stage_index] = num_search_pts; + cfg->radius[stage_index] = radius; + --stage_index; + ++ss_count; + } cfg->ss_count = ss_count; - cfg->searches_per_step = 4; } void av1_init3smotion_compensation(search_site_config *cfg, int stride) { - int len, ss_count = 1; - - cfg->ss[0].mv.col = cfg->ss[0].mv.row = 0; - cfg->ss[0].offset = 0; + int ss_count = 0; + int stage_index = 0; cfg->stride = stride; + int radius = 1; + for (stage_index = 0; stage_index < 15; ++stage_index) { + int tan_radius = AOMMAX((int)(0.41 * radius), 1); + int num_search_pts = 12; + if (radius <= 5) { + tan_radius = radius; + num_search_pts = 8; + } + const FULLPEL_MV ss_mvs[13] = { + { 0, 0 }, + { -radius, 0 }, + { radius, 0 }, + { 0, -radius }, + { 0, radius }, + { -radius, -tan_radius }, + { radius, tan_radius }, + { -tan_radius, radius }, + { tan_radius, -radius }, + { -radius, tan_radius }, + { radius, -tan_radius }, + { tan_radius, radius }, + { -tan_radius, -radius }, + }; - for (len = MAX_FIRST_STEP; len > 0; len /= 2) { - // Generate offsets for 8 search sites per step. - const MV ss_mvs[8] = { { -len, 0 }, { len, 0 }, { 0, -len }, - { 0, len }, { -len, -len }, { -len, len }, - { len, -len }, { len, len } }; - int i; - for (i = 0; i < 8; ++i) { - search_site *const ss = &cfg->ss[ss_count++]; + for (int i = 0; i <= num_search_pts; ++i) { + search_site *const ss = &cfg->ss[stage_index][i]; ss->mv = ss_mvs[i]; - ss->offset = ss->mv.row * stride + ss->mv.col; + ss->offset = get_offset_from_fullmv(&ss->mv, stride); } + cfg->searches_per_step[stage_index] = num_search_pts; + cfg->radius[stage_index] = radius; + ++ss_count; + if (stage_index < 12) + radius = (int)AOMMAX((radius * 1.5 + 0.5), radius + 1); } - cfg->ss_count = ss_count; - cfg->searches_per_step = 8; } -/* - * To avoid the penalty for crossing cache-line read, preload the reference - * area in a small buffer, which is aligned to make sure there won't be crossing - * cache-line read while reading from this buffer. This reduced the cpu - * cycles spent on reading ref data in sub-pixel filter functions. - * TODO: Currently, since sub-pixel search range here is -3 ~ 3, copy 22 rows x - * 32 cols area that is enough for 16x16 macroblock. Later, for SPLITMV, we - * could reduce the area. - */ - -// convert motion vector component to offset for sv[a]f calc -static INLINE int sp(int x) { return x & 7; } - -static INLINE const uint8_t *pre(const uint8_t *buf, int stride, int r, int c) { - const int offset = (r >> 3) * stride + (c >> 3); - return buf + offset; -} - -/* checks if (r, c) has better score than previous best */ -#define CHECK_BETTER(v, r, c) \ - if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \ - MV this_mv = { r, c }; \ - v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \ - if (second_pred == NULL) { \ - thismse = vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \ - src_address, src_stride, &sse); \ - } else if (mask) { \ - thismse = vfp->msvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \ - src_address, src_stride, second_pred, mask, \ - mask_stride, invert_mask, &sse); \ - } else { \ - thismse = vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \ - src_address, src_stride, &sse, second_pred); \ - } \ - v += thismse; \ - if (v < besterr) { \ - besterr = v; \ - br = r; \ - bc = c; \ - *distortion = thismse; \ - *sse1 = sse; \ - } \ - } else { \ - v = INT_MAX; \ - } - -#define CHECK_BETTER0(v, r, c) CHECK_BETTER(v, r, c) - -/* checks if (r, c) has better score than previous best */ -#define CHECK_BETTER1(v, r, c) \ - if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \ - MV this_mv = { r, c }; \ - thismse = upsampled_pref_error( \ - xd, cm, mi_row, mi_col, &this_mv, vfp, src_address, src_stride, \ - pre(y, y_stride, r, c), y_stride, sp(c), sp(r), second_pred, mask, \ - mask_stride, invert_mask, w, h, &sse, use_accurate_subpel_search); \ - v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \ - v += thismse; \ - if (v < besterr) { \ - besterr = v; \ - br = r; \ - bc = c; \ - *distortion = thismse; \ - *sse1 = sse; \ - } \ - } else { \ - v = INT_MAX; \ - } - -#define FIRST_LEVEL_CHECKS \ - { \ - unsigned int left, right, up, down, diag; \ - CHECK_BETTER(left, tr, tc - hstep); \ - CHECK_BETTER(right, tr, tc + hstep); \ - CHECK_BETTER(up, tr - hstep, tc); \ - CHECK_BETTER(down, tr + hstep, tc); \ - whichdir = (left < right ? 0 : 1) + (up < down ? 0 : 2); \ - switch (whichdir) { \ - case 0: CHECK_BETTER(diag, tr - hstep, tc - hstep); break; \ - case 1: CHECK_BETTER(diag, tr - hstep, tc + hstep); break; \ - case 2: CHECK_BETTER(diag, tr + hstep, tc - hstep); break; \ - case 3: CHECK_BETTER(diag, tr + hstep, tc + hstep); break; \ - } \ - } - -#define SECOND_LEVEL_CHECKS \ - { \ - int kr, kc; \ - unsigned int second; \ - if (tr != br && tc != bc) { \ - kr = br - tr; \ - kc = bc - tc; \ - CHECK_BETTER(second, tr + kr, tc + 2 * kc); \ - CHECK_BETTER(second, tr + 2 * kr, tc + kc); \ - } else if (tr == br && tc != bc) { \ - kc = bc - tc; \ - CHECK_BETTER(second, tr + hstep, tc + 2 * kc); \ - CHECK_BETTER(second, tr - hstep, tc + 2 * kc); \ - switch (whichdir) { \ - case 0: \ - case 1: CHECK_BETTER(second, tr + hstep, tc + kc); break; \ - case 2: \ - case 3: CHECK_BETTER(second, tr - hstep, tc + kc); break; \ - } \ - } else if (tr != br && tc == bc) { \ - kr = br - tr; \ - CHECK_BETTER(second, tr + 2 * kr, tc + hstep); \ - CHECK_BETTER(second, tr + 2 * kr, tc - hstep); \ - switch (whichdir) { \ - case 0: \ - case 2: CHECK_BETTER(second, tr + kr, tc + hstep); break; \ - case 1: \ - case 3: CHECK_BETTER(second, tr + kr, tc - hstep); break; \ - } \ - } \ - } - -// TODO(yunqingwang): SECOND_LEVEL_CHECKS_BEST was a rewrote of -// SECOND_LEVEL_CHECKS, and SECOND_LEVEL_CHECKS should be rewritten -// later in the same way. -#define SECOND_LEVEL_CHECKS_BEST(k) \ - { \ - unsigned int second; \ - int br0 = br; \ - int bc0 = bc; \ - assert(tr == br || tc == bc); \ - if (tr == br && tc != bc) { \ - kc = bc - tc; \ - } else if (tr != br && tc == bc) { \ - kr = br - tr; \ - } \ - CHECK_BETTER##k(second, br0 + kr, bc0); \ - CHECK_BETTER##k(second, br0, bc0 + kc); \ - if (br0 != br || bc0 != bc) { \ - CHECK_BETTER##k(second, br0 + kr, bc0 + kc); \ - } \ - } - -#define SETUP_SUBPEL_SEARCH \ - const uint8_t *const src_address = x->plane[0].src.buf; \ - const int src_stride = x->plane[0].src.stride; \ - const MACROBLOCKD *xd = &x->e_mbd; \ - unsigned int besterr = INT_MAX; \ - unsigned int sse; \ - unsigned int whichdir; \ - int thismse; \ - MV *bestmv = &x->best_mv.as_mv; \ - const unsigned int halfiters = iters_per_step; \ - const unsigned int quarteriters = iters_per_step; \ - const unsigned int eighthiters = iters_per_step; \ - const int y_stride = xd->plane[0].pre[0].stride; \ - const int offset = bestmv->row * y_stride + bestmv->col; \ - const uint8_t *const y = xd->plane[0].pre[0].buf; \ - \ - int br = bestmv->row * 8; \ - int bc = bestmv->col * 8; \ - int hstep = 4; \ - int minc, maxc, minr, maxr; \ - int tr = br; \ - int tc = bc; \ - \ - set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, \ - ref_mv); \ - \ - bestmv->row *= 8; \ - bestmv->col *= 8; - -static unsigned int setup_center_error( - const MACROBLOCKD *xd, const MV *bestmv, const MV *ref_mv, - int error_per_bit, const aom_variance_fn_ptr_t *vfp, - const uint8_t *const src, const int src_stride, const uint8_t *const y, - int y_stride, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, int offset, int *mvjcost, - int *mvcost[2], unsigned int *sse1, int *distortion) { - unsigned int besterr; - if (second_pred != NULL) { -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - DECLARE_ALIGNED(16, uint16_t, comp_pred16[MAX_SB_SQUARE]); - uint8_t *comp_pred = CONVERT_TO_BYTEPTR(comp_pred16); - if (mask) { - aom_highbd_comp_mask_pred(comp_pred, second_pred, w, h, y + offset, - y_stride, mask, mask_stride, invert_mask); - } else { - aom_highbd_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, - y_stride); - } - besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); - } else { - DECLARE_ALIGNED(16, uint8_t, comp_pred[MAX_SB_SQUARE]); - if (mask) { - aom_comp_mask_pred(comp_pred, second_pred, w, h, y + offset, y_stride, - mask, mask_stride, invert_mask); - } else { - aom_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride); - } - besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); - } -#else - (void)xd; - DECLARE_ALIGNED(16, uint8_t, comp_pred[MAX_SB_SQUARE]); - if (mask) { - aom_comp_mask_pred(comp_pred, second_pred, w, h, y + offset, y_stride, - mask, mask_stride, invert_mask); - } else { - aom_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride); - } - besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); -#endif - } else { - besterr = vfp->vf(y + offset, y_stride, src, src_stride, sse1); - } - *distortion = besterr; - besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit); - return besterr; -} - -static INLINE int divide_and_round(int n, int d) { - return ((n < 0) ^ (d < 0)) ? ((n - d / 2) / d) : ((n + d / 2) / d); -} - -static INLINE int is_cost_list_wellbehaved(int *cost_list) { - return cost_list[0] < cost_list[1] && cost_list[0] < cost_list[2] && - cost_list[0] < cost_list[3] && cost_list[0] < cost_list[4]; -} - -// Returns surface minima estimate at given precision in 1/2^n bits. -// Assume a model for the cost surface: S = A(x - x0)^2 + B(y - y0)^2 + C -// For a given set of costs S0, S1, S2, S3, S4 at points -// (y, x) = (0, 0), (0, -1), (1, 0), (0, 1) and (-1, 0) respectively, -// the solution for the location of the minima (x0, y0) is given by: -// x0 = 1/2 (S1 - S3)/(S1 + S3 - 2*S0), -// y0 = 1/2 (S4 - S2)/(S4 + S2 - 2*S0). -// The code below is an integerized version of that. -static AOM_INLINE void get_cost_surf_min(int *cost_list, int *ir, int *ic, - int bits) { - *ic = divide_and_round((cost_list[1] - cost_list[3]) * (1 << (bits - 1)), - (cost_list[1] - 2 * cost_list[0] + cost_list[3])); - *ir = divide_and_round((cost_list[4] - cost_list[2]) * (1 << (bits - 1)), - (cost_list[4] - 2 * cost_list[0] + cost_list[2])); -} - -int av1_find_best_sub_pixel_tree_pruned_evenmore( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - SETUP_SUBPEL_SEARCH; - besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, - src_address, src_stride, y, y_stride, - second_pred, mask, mask_stride, invert_mask, w, - h, offset, mvjcost, mvcost, sse1, distortion); - (void)halfiters; - (void)quarteriters; - (void)eighthiters; - (void)whichdir; - (void)allow_hp; - (void)forced_stop; - (void)hstep; - (void)use_accurate_subpel_search; - (void)cm; - (void)mi_row; - (void)mi_col; - (void)do_reset_fractional_mv; - - if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && - cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && - cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) { - int ir, ic; - unsigned int minpt; - get_cost_surf_min(cost_list, &ir, &ic, 2); - if (ir != 0 || ic != 0) { - CHECK_BETTER(minpt, tr + 2 * ir, tc + 2 * ic); - } - } else { - FIRST_LEVEL_CHECKS; - if (halfiters > 1) { - SECOND_LEVEL_CHECKS; - } - - tr = br; - tc = bc; - - // Each subsequent iteration checks at least one point in common with - // the last iteration could be 2 ( if diag selected) 1/4 pel - // Note forced_stop: 0 - full, 1 - qtr only, 2 - half only - if (forced_stop != 2) { - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (quarteriters > 1) { - SECOND_LEVEL_CHECKS; - } - } - } - - tr = br; - tc = bc; - - if (allow_hp && forced_stop == 0) { - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (eighthiters > 1) { - SECOND_LEVEL_CHECKS; - } - } - - bestmv->row = br; - bestmv->col = bc; - - return besterr; -} - -int av1_find_best_sub_pixel_tree_pruned_more( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - SETUP_SUBPEL_SEARCH; - (void)use_accurate_subpel_search; - (void)cm; - (void)mi_row; - (void)mi_col; - (void)do_reset_fractional_mv; - - besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, - src_address, src_stride, y, y_stride, - second_pred, mask, mask_stride, invert_mask, w, - h, offset, mvjcost, mvcost, sse1, distortion); - if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && - cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && - cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) { - unsigned int minpt; - int ir, ic; - get_cost_surf_min(cost_list, &ir, &ic, 1); - if (ir != 0 || ic != 0) { - CHECK_BETTER(minpt, tr + ir * hstep, tc + ic * hstep); - } - } else { - FIRST_LEVEL_CHECKS; - if (halfiters > 1) { - SECOND_LEVEL_CHECKS; - } - } - - // Each subsequent iteration checks at least one point in common with - // the last iteration could be 2 ( if diag selected) 1/4 pel - - // Note forced_stop: 0 - full, 1 - qtr only, 2 - half only - if (forced_stop != 2) { - tr = br; - tc = bc; - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (quarteriters > 1) { - SECOND_LEVEL_CHECKS; - } - } - - if (allow_hp && forced_stop == 0) { - tr = br; - tc = bc; - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (eighthiters > 1) { - SECOND_LEVEL_CHECKS; - } - } - // These lines insure static analysis doesn't warn that - // tr and tc aren't used after the above point. - (void)tr; - (void)tc; - - bestmv->row = br; - bestmv->col = bc; - - return besterr; -} - -int av1_find_best_sub_pixel_tree_pruned( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - SETUP_SUBPEL_SEARCH; - (void)use_accurate_subpel_search; - (void)cm; - (void)mi_row; - (void)mi_col; - (void)do_reset_fractional_mv; - - besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, - src_address, src_stride, y, y_stride, - second_pred, mask, mask_stride, invert_mask, w, - h, offset, mvjcost, mvcost, sse1, distortion); - if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && - cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && - cost_list[4] != INT_MAX) { - unsigned int left, right, up, down, diag; - whichdir = (cost_list[1] < cost_list[3] ? 0 : 1) + - (cost_list[2] < cost_list[4] ? 0 : 2); - switch (whichdir) { - case 0: - CHECK_BETTER(left, tr, tc - hstep); - CHECK_BETTER(down, tr + hstep, tc); - CHECK_BETTER(diag, tr + hstep, tc - hstep); - break; - case 1: - CHECK_BETTER(right, tr, tc + hstep); - CHECK_BETTER(down, tr + hstep, tc); - CHECK_BETTER(diag, tr + hstep, tc + hstep); - break; - case 2: - CHECK_BETTER(left, tr, tc - hstep); - CHECK_BETTER(up, tr - hstep, tc); - CHECK_BETTER(diag, tr - hstep, tc - hstep); - break; - case 3: - CHECK_BETTER(right, tr, tc + hstep); - CHECK_BETTER(up, tr - hstep, tc); - CHECK_BETTER(diag, tr - hstep, tc + hstep); - break; - } - } else { - FIRST_LEVEL_CHECKS; - if (halfiters > 1) { - SECOND_LEVEL_CHECKS; - } - } - - tr = br; - tc = bc; - - // Each subsequent iteration checks at least one point in common with - // the last iteration could be 2 ( if diag selected) 1/4 pel - - // Note forced_stop: 0 - full, 1 - qtr only, 2 - half only - if (forced_stop != 2) { - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (quarteriters > 1) { - SECOND_LEVEL_CHECKS; - } - tr = br; - tc = bc; - } - - if (allow_hp && forced_stop == 0) { - hstep >>= 1; - FIRST_LEVEL_CHECKS; - if (eighthiters > 1) { - SECOND_LEVEL_CHECKS; - } - tr = br; - tc = bc; - } - // These lines insure static analysis doesn't warn that - // tr and tc aren't used after the above point. - (void)tr; - (void)tc; - - bestmv->row = br; - bestmv->col = bc; - - return besterr; -} - -/* clang-format off */ -static const MV search_step_table[12] = { - // left, right, up, down - { 0, -4 }, { 0, 4 }, { -4, 0 }, { 4, 0 }, - { 0, -2 }, { 0, 2 }, { -2, 0 }, { 2, 0 }, - { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } -}; -/* clang-format on */ - -static int upsampled_pref_error(MACROBLOCKD *xd, const AV1_COMMON *const cm, - int mi_row, int mi_col, const MV *const mv, - const aom_variance_fn_ptr_t *vfp, - const uint8_t *const src, const int src_stride, - const uint8_t *const y, int y_stride, - int subpel_x_q3, int subpel_y_q3, - const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - unsigned int *sse, int subpel_search) { - unsigned int besterr; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - DECLARE_ALIGNED(16, uint16_t, pred16[MAX_SB_SQUARE]); - uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred16); - if (second_pred != NULL) { - if (mask) { - aom_highbd_comp_mask_upsampled_pred( - xd, cm, mi_row, mi_col, mv, pred8, second_pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, mask, mask_stride, invert_mask, xd->bd, - subpel_search); - } else { - aom_highbd_comp_avg_upsampled_pred( - xd, cm, mi_row, mi_col, mv, pred8, second_pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, xd->bd, subpel_search); - } - } else { - aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred8, w, h, - subpel_x_q3, subpel_y_q3, y, y_stride, xd->bd, - subpel_search); - } - besterr = vfp->vf(pred8, w, src, src_stride, sse); - } else { - DECLARE_ALIGNED(16, uint8_t, pred[MAX_SB_SQUARE]); - if (second_pred != NULL) { - if (mask) { - aom_comp_mask_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, - second_pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, mask, - mask_stride, invert_mask, subpel_search); - } else { - aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, - second_pred, w, h, subpel_x_q3, subpel_y_q3, - y, y_stride, subpel_search); - } - } else { - aom_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, subpel_search); - } - - besterr = vfp->vf(pred, w, src, src_stride, sse); - } -#else - DECLARE_ALIGNED(16, uint8_t, pred[MAX_SB_SQUARE]); - if (second_pred != NULL) { - if (mask) { - aom_comp_mask_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, - second_pred, w, h, subpel_x_q3, subpel_y_q3, - y, y_stride, mask, mask_stride, invert_mask, - subpel_search); - } else { - aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, second_pred, - w, h, subpel_x_q3, subpel_y_q3, y, y_stride, - subpel_search); - } - } else { - aom_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, subpel_search); - } - - besterr = vfp->vf(pred, w, src, src_stride, sse); -#endif - return besterr; -} - -static unsigned int upsampled_setup_center_error( - MACROBLOCKD *xd, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *bestmv, const MV *ref_mv, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, const uint8_t *const src, - const int src_stride, const uint8_t *const y, int y_stride, - const uint8_t *second_pred, const uint8_t *mask, int mask_stride, - int invert_mask, int w, int h, int offset, int *mvjcost, int *mvcost[2], - unsigned int *sse1, int *distortion, int subpel_search) { - unsigned int besterr = - upsampled_pref_error(xd, cm, mi_row, mi_col, bestmv, vfp, src, src_stride, - y + offset, y_stride, 0, 0, second_pred, mask, - mask_stride, invert_mask, w, h, sse1, subpel_search); - *distortion = besterr; - besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit); - return besterr; -} - -// when use_accurate_subpel_search == 0 -static INLINE unsigned int estimate_upsampled_pref_error( - const aom_variance_fn_ptr_t *vfp, const uint8_t *const src, - const int src_stride, const uint8_t *const pre, int y_stride, - int subpel_x_q3, int subpel_y_q3, const uint8_t *second_pred, - const uint8_t *mask, int mask_stride, int invert_mask, unsigned int *sse) { - if (second_pred == NULL) { - return vfp->svf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride, - sse); - } else if (mask) { - return vfp->msvf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride, - second_pred, mask, mask_stride, invert_mask, sse); - } else { - return vfp->svaf(pre, y_stride, subpel_x_q3, subpel_y_q3, src, src_stride, - sse, second_pred); - } -} - -int av1_find_best_sub_pixel_tree( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - const uint8_t *const src_address = x->plane[0].src.buf; - const int src_stride = x->plane[0].src.stride; - MACROBLOCKD *xd = &x->e_mbd; - unsigned int besterr = INT_MAX; - unsigned int sse; - unsigned int thismse; - const int y_stride = xd->plane[0].pre[0].stride; - MV *bestmv = &x->best_mv.as_mv; - const int offset = bestmv->row * y_stride + bestmv->col; - const uint8_t *const y = xd->plane[0].pre[0].buf; - - int br = bestmv->row * 8; - int bc = bestmv->col * 8; - int hstep = 4; - int iter, round = 3 - forced_stop; - int tr = br; - int tc = bc; - const MV *search_step = search_step_table; - int idx, best_idx = -1; - unsigned int cost_array[5]; - int kr, kc; - int minc, maxc, minr, maxr; - - set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, ref_mv); - - if (!allow_hp) - if (round == 3) round = 2; - - bestmv->row *= 8; - bestmv->col *= 8; - - if (use_accurate_subpel_search) - besterr = upsampled_setup_center_error( - xd, cm, mi_row, mi_col, bestmv, ref_mv, error_per_bit, vfp, src_address, - src_stride, y, y_stride, second_pred, mask, mask_stride, invert_mask, w, - h, offset, mvjcost, mvcost, sse1, distortion, - use_accurate_subpel_search); - else - besterr = setup_center_error(xd, bestmv, ref_mv, error_per_bit, vfp, - src_address, src_stride, y, y_stride, - second_pred, mask, mask_stride, invert_mask, w, - h, offset, mvjcost, mvcost, sse1, distortion); - - (void)cost_list; // to silence compiler warning - - if (do_reset_fractional_mv) { - av1_set_fractional_mv(x->fractional_best_mv); - } - - for (iter = 0; iter < round; ++iter) { - if ((x->fractional_best_mv[iter].as_mv.row == br) && - (x->fractional_best_mv[iter].as_mv.col == bc)) - return INT_MAX; - x->fractional_best_mv[iter].as_mv.row = br; - x->fractional_best_mv[iter].as_mv.col = bc; - // Check vertical and horizontal sub-pixel positions. - for (idx = 0; idx < 4; ++idx) { - tr = br + search_step[idx].row; - tc = bc + search_step[idx].col; - if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) { - MV this_mv = { tr, tc }; - - if (use_accurate_subpel_search) { - thismse = upsampled_pref_error( - xd, cm, mi_row, mi_col, &this_mv, vfp, src_address, src_stride, - pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), second_pred, - mask, mask_stride, invert_mask, w, h, &sse, - use_accurate_subpel_search); - } else { - thismse = estimate_upsampled_pref_error( - vfp, src_address, src_stride, pre(y, y_stride, tr, tc), y_stride, - sp(tc), sp(tr), second_pred, mask, mask_stride, invert_mask, - &sse); - } - - cost_array[idx] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost, - mvcost, error_per_bit); - - if (cost_array[idx] < besterr) { - best_idx = idx; - besterr = cost_array[idx]; - *distortion = thismse; - *sse1 = sse; - } - } else { - cost_array[idx] = INT_MAX; - } - } - - // Check diagonal sub-pixel position - kc = (cost_array[0] <= cost_array[1] ? -hstep : hstep); - kr = (cost_array[2] <= cost_array[3] ? -hstep : hstep); - - tc = bc + kc; - tr = br + kr; - if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) { - MV this_mv = { tr, tc }; - - if (use_accurate_subpel_search) { - thismse = upsampled_pref_error( - xd, cm, mi_row, mi_col, &this_mv, vfp, src_address, src_stride, - pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), second_pred, - mask, mask_stride, invert_mask, w, h, &sse, - use_accurate_subpel_search); - } else { - thismse = estimate_upsampled_pref_error( - vfp, src_address, src_stride, pre(y, y_stride, tr, tc), y_stride, - sp(tc), sp(tr), second_pred, mask, mask_stride, invert_mask, &sse); - } - - cost_array[4] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, - error_per_bit); - - if (cost_array[4] < besterr) { - best_idx = 4; - besterr = cost_array[4]; - *distortion = thismse; - *sse1 = sse; - } - } else { - cost_array[idx] = INT_MAX; - } - - if (best_idx < 4 && best_idx >= 0) { - br += search_step[best_idx].row; - bc += search_step[best_idx].col; - } else if (best_idx == 4) { - br = tr; - bc = tc; - } - - if (iters_per_step > 1 && best_idx != -1) { - if (use_accurate_subpel_search) { - SECOND_LEVEL_CHECKS_BEST(1); - } else { - SECOND_LEVEL_CHECKS_BEST(0); - } - } - - search_step += 4; - hstep >>= 1; - best_idx = -1; - } - - // These lines insure static analysis doesn't warn that - // tr and tc aren't used after the above point. - (void)tr; - (void)tc; - - bestmv->row = br; - bestmv->col = bc; - - return besterr; -} - -#undef PRE -#undef CHECK_BETTER - -unsigned int av1_compute_motion_cost(const AV1_COMP *cpi, MACROBLOCK *const x, - BLOCK_SIZE bsize, int mi_row, int mi_col, - const MV *this_mv) { - const AV1_COMMON *const cm = &cpi->common; - MACROBLOCKD *xd = &x->e_mbd; - const uint8_t *const src = x->plane[0].src.buf; - const int src_stride = x->plane[0].src.stride; - uint8_t *const dst = xd->plane[0].dst.buf; - const int dst_stride = xd->plane[0].dst.stride; - const aom_variance_fn_ptr_t *vfp = &cpi->fn_ptr[bsize]; - const int_mv ref_mv = av1_get_ref_mv(x, 0); - unsigned int mse; - unsigned int sse; - - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - mse = vfp->vf(dst, dst_stride, src, src_stride, &sse); - mse += mv_err_cost(this_mv, &ref_mv.as_mv, x->nmv_vec_cost, x->mv_cost_stack, - x->errorperbit); - return mse; -} - -// Refine MV in a small range -unsigned int av1_refine_warped_mv(const AV1_COMP *cpi, MACROBLOCK *const x, - BLOCK_SIZE bsize, int mi_row, int mi_col, - int *pts0, int *pts_inref0, - int total_samples) { - const AV1_COMMON *const cm = &cpi->common; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - const MV neighbors[8] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, - { 0, -2 }, { 2, 0 }, { 0, 2 }, { -2, 0 } }; - const int_mv ref_mv = av1_get_ref_mv(x, 0); - int16_t br = mbmi->mv[0].as_mv.row; - int16_t bc = mbmi->mv[0].as_mv.col; - int16_t *tr = &mbmi->mv[0].as_mv.row; - int16_t *tc = &mbmi->mv[0].as_mv.col; - WarpedMotionParams best_wm_params = mbmi->wm_params; - int best_num_proj_ref = mbmi->num_proj_ref; - unsigned int bestmse; - int minc, maxc, minr, maxr; - const int start = cm->allow_high_precision_mv ? 0 : 4; - int ite; - - set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, - &ref_mv.as_mv); - - // Calculate the center position's error - assert(bc >= minc && bc <= maxc && br >= minr && br <= maxr); - bestmse = av1_compute_motion_cost(cpi, x, bsize, mi_row, mi_col, - &mbmi->mv[0].as_mv); - - // MV search - for (ite = 0; ite < 2; ++ite) { - int best_idx = -1; - int idx; - - for (idx = start; idx < start + 4; ++idx) { - unsigned int thismse; - - *tr = br + neighbors[idx].row; - *tc = bc + neighbors[idx].col; - - if (*tc >= minc && *tc <= maxc && *tr >= minr && *tr <= maxr) { - MV this_mv = { *tr, *tc }; - int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE]; - - memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0)); - memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0)); - if (total_samples > 1) - mbmi->num_proj_ref = - av1_selectSamples(&this_mv, pts, pts_inref, total_samples, bsize); - - if (!av1_find_projection(mbmi->num_proj_ref, pts, pts_inref, bsize, *tr, - *tc, &mbmi->wm_params, mi_row, mi_col)) { - thismse = - av1_compute_motion_cost(cpi, x, bsize, mi_row, mi_col, &this_mv); - - if (thismse < bestmse) { - best_idx = idx; - best_wm_params = mbmi->wm_params; - best_num_proj_ref = mbmi->num_proj_ref; - bestmse = thismse; - } - } - } - } - - if (best_idx == -1) break; - - if (best_idx >= 0) { - br += neighbors[best_idx].row; - bc += neighbors[best_idx].col; - } - } - - *tr = br; - *tc = bc; - mbmi->wm_params = best_wm_params; - mbmi->num_proj_ref = best_num_proj_ref; - return bestmse; -} - -static INLINE int check_bounds(const MvLimits *mv_limits, int row, int col, +// Checks whether the mv is within range of the mv_limits +static INLINE int check_bounds(const FullMvLimits *mv_limits, int row, int col, int range) { return ((row - range) >= mv_limits->row_min) & ((row + range) <= mv_limits->row_max) & @@ -1019,158 +396,240 @@ static INLINE int check_bounds(const MvLimits *mv_limits, int row, int col, ((col + range) <= mv_limits->col_max); } -static INLINE int is_mv_in(const MvLimits *mv_limits, const MV *mv) { - return (mv->col >= mv_limits->col_min) && (mv->col <= mv_limits->col_max) && - (mv->row >= mv_limits->row_min) && (mv->row <= mv_limits->row_max); +static INLINE int get_mvpred_var_cost( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV *this_mv) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const MV sub_this_mv = get_mv_from_fullmv(this_mv); + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; + const uint8_t *src_buf = src->buf; + const int src_stride = src->stride; + const int ref_stride = ref->stride; + + unsigned unused; + int bestsme; + + bestsme = vfp->vf(src_buf, src_stride, get_buf_from_fullmv(ref, this_mv), + ref_stride, &unused); + + bestsme += mv_err_cost_(&sub_this_mv, &ms_params->mv_cost_params); + + return bestsme; } -#define CHECK_BETTER \ - { \ - if (thissad < bestsad) { \ - if (use_mvcost) \ - thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit); \ - if (thissad < bestsad) { \ - bestsad = thissad; \ - best_site = i; \ - } \ - } \ +static INLINE int get_mvpred_sad(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct buf_2d *const src, + const uint8_t *const ref_address, + const int ref_stride) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const uint8_t *src_buf = src->buf; + const int src_stride = src->stride; + + return vfp->sdf(src_buf, src_stride, ref_address, ref_stride); +} + +static INLINE int get_mvpred_compound_var_cost( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV *this_mv) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; + const uint8_t *src_buf = src->buf; + const int src_stride = src->stride; + const int ref_stride = ref->stride; + + const uint8_t *mask = ms_params->ms_buffers.mask; + const uint8_t *second_pred = ms_params->ms_buffers.second_pred; + const int mask_stride = ms_params->ms_buffers.mask_stride; + const int invert_mask = ms_params->ms_buffers.inv_mask; + unsigned unused; + int bestsme; + + if (mask) { + bestsme = vfp->msvf(src_buf, src_stride, 0, 0, + get_buf_from_fullmv(ref, this_mv), ref_stride, + second_pred, mask, mask_stride, invert_mask, &unused); + } else if (second_pred) { + bestsme = vfp->svaf(get_buf_from_fullmv(ref, this_mv), ref_stride, 0, 0, + src_buf, src_stride, &unused, second_pred); + } else { + bestsme = vfp->vf(src_buf, src_stride, get_buf_from_fullmv(ref, this_mv), + ref_stride, &unused); } -#define MAX_PATTERN_SCALES 11 -#define MAX_PATTERN_CANDIDATES 8 // max number of canddiates per scale -#define PATTERN_CANDIDATES_REF 3 // number of refinement candidates + const MV sub_this_mv = get_mv_from_fullmv(this_mv); + bestsme += mv_err_cost_(&sub_this_mv, &ms_params->mv_cost_params); -// Calculate and return a sad+mvcost list around an integer best pel. -static INLINE void calc_int_cost_list(const MACROBLOCK *x, - const MV *const ref_mv, int sadpb, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *best_mv, int *cost_list) { - static const MV neighbors[4] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &x->e_mbd.plane[0].pre[0]; - const MV fcenter_mv = { ref_mv->row >> 3, ref_mv->col >> 3 }; - const int br = best_mv->row; - const int bc = best_mv->col; - int i; - unsigned int sse; - const MV this_mv = { br, bc }; + return bestsme; +} - cost_list[0] = - fn_ptr->vf(what->buf, what->stride, get_buf_from_mv(in_what, &this_mv), - in_what->stride, &sse) + - mvsad_err_cost(x, &this_mv, &fcenter_mv, sadpb); - if (check_bounds(&x->mv_limits, br, bc, 1)) { - for (i = 0; i < 4; i++) { - const MV neighbor_mv = { br + neighbors[i].row, bc + neighbors[i].col }; - cost_list[i + 1] = fn_ptr->vf(what->buf, what->stride, - get_buf_from_mv(in_what, &neighbor_mv), - in_what->stride, &sse) + - mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit); +static INLINE int get_mvpred_compound_sad( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct buf_2d *const src, const uint8_t *const ref_address, + const int ref_stride) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const uint8_t *src_buf = src->buf; + const int src_stride = src->stride; + + const uint8_t *mask = ms_params->ms_buffers.mask; + const uint8_t *second_pred = ms_params->ms_buffers.second_pred; + const int mask_stride = ms_params->ms_buffers.mask_stride; + const int invert_mask = ms_params->ms_buffers.inv_mask; + + if (mask) { + return vfp->msdf(src_buf, src_stride, ref_address, ref_stride, second_pred, + mask, mask_stride, invert_mask); + } else if (second_pred) { + return vfp->sdaf(src_buf, src_stride, ref_address, ref_stride, second_pred); + } else { + return vfp->sdf(src_buf, src_stride, ref_address, ref_stride); + } +} + +// Calculates and returns a sad+mvcost list around an integer best pel during +// fullpixel motion search. The resulting list can be used to speed up subpel +// motion search later. +#define USE_SAD_COSTLIST 1 + +// calc_int_cost_list uses var to populate the costlist, which is more accurate +// than sad but slightly slower. +static AOM_FORCE_INLINE void calc_int_cost_list( + const FULLPEL_MV best_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + int *cost_list) { + static const FULLPEL_MV neighbors[4] = { + { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } + }; + const int br = best_mv.row; + const int bc = best_mv.col; + + cost_list[0] = get_mvpred_var_cost(ms_params, &best_mv); + + if (check_bounds(&ms_params->mv_limits, br, bc, 1)) { + for (int i = 0; i < 4; i++) { + const FULLPEL_MV neighbor_mv = { br + neighbors[i].row, + bc + neighbors[i].col }; + cost_list[i + 1] = get_mvpred_var_cost(ms_params, &neighbor_mv); } } else { - for (i = 0; i < 4; i++) { - const MV neighbor_mv = { br + neighbors[i].row, bc + neighbors[i].col }; - if (!is_mv_in(&x->mv_limits, &neighbor_mv)) + for (int i = 0; i < 4; i++) { + const FULLPEL_MV neighbor_mv = { br + neighbors[i].row, + bc + neighbors[i].col }; + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, neighbor_mv)) { cost_list[i + 1] = INT_MAX; - else - cost_list[i + 1] = - fn_ptr->vf(what->buf, what->stride, - get_buf_from_mv(in_what, &neighbor_mv), in_what->stride, - &sse) + - mv_err_cost(&neighbor_mv, &fcenter_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit); + } else { + cost_list[i + 1] = get_mvpred_var_cost(ms_params, &neighbor_mv); + } } } } -static INLINE void calc_int_sad_list(const MACROBLOCK *x, - const MV *const ref_mv, int sadpb, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *best_mv, int *cost_list, - const int use_mvcost, const int bestsad) { - static const MV neighbors[4] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &x->e_mbd.plane[0].pre[0]; - const MV fcenter_mv = { ref_mv->row >> 3, ref_mv->col >> 3 }; - int i; - const int br = best_mv->row; - const int bc = best_mv->col; +// calc_int_sad_list uses sad to populate the costlist, which is less accurate +// than var but faster. +static AOM_FORCE_INLINE void calc_int_sad_list( + const FULLPEL_MV best_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + int *cost_list, int costlist_has_sad) { + static const FULLPEL_MV neighbors[4] = { + { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } + }; + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; + const int ref_stride = ref->stride; + const int br = best_mv.row; + const int bc = best_mv.col; - if (cost_list[0] == INT_MAX) { - cost_list[0] = bestsad; - if (check_bounds(&x->mv_limits, br, bc, 1)) { - for (i = 0; i < 4; i++) { - const MV this_mv = { br + neighbors[i].row, bc + neighbors[i].col }; - cost_list[i + 1] = - fn_ptr->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + assert(av1_is_fullmv_in_range(&ms_params->mv_limits, best_mv)); + + // Refresh the costlist it does not contain valid sad + if (!costlist_has_sad) { + cost_list[0] = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &best_mv), ref_stride); + + if (check_bounds(&ms_params->mv_limits, br, bc, 1)) { + for (int i = 0; i < 4; i++) { + const FULLPEL_MV this_mv = { br + neighbors[i].row, + bc + neighbors[i].col }; + cost_list[i + 1] = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); } } else { - for (i = 0; i < 4; i++) { - const MV this_mv = { br + neighbors[i].row, bc + neighbors[i].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) + for (int i = 0; i < 4; i++) { + const FULLPEL_MV this_mv = { br + neighbors[i].row, + bc + neighbors[i].col }; + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) { cost_list[i + 1] = INT_MAX; - else - cost_list[i + 1] = - fn_ptr->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); - } - } - } else { - if (use_mvcost) { - for (i = 0; i < 4; i++) { - const MV this_mv = { br + neighbors[i].row, bc + neighbors[i].col }; - if (cost_list[i + 1] != INT_MAX) { - cost_list[i + 1] += mvsad_err_cost(x, &this_mv, &fcenter_mv, sadpb); + } else { + cost_list[i + 1] = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); } } } } + + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + cost_list[0] += mvsad_err_cost_(&best_mv, mv_cost_params); + + for (int idx = 0; idx < 4; idx++) { + if (cost_list[idx + 1] != INT_MAX) { + const FULLPEL_MV this_mv = { br + neighbors[idx].row, + bc + neighbors[idx].col }; + cost_list[idx + 1] += mvsad_err_cost_(&this_mv, mv_cost_params); + } + } } +#define CHECK_BETTER \ + if (thissad < bestsad) { \ + int tmp_thissad = thissad; \ + if (use_mvcost) thissad += mvsad_err_cost_(&this_mv, mv_cost_params); \ + if (thissad < bestsad) { \ + raw_bestsad = tmp_thissad; \ + bestsad = thissad; \ + best_site = i; \ + } \ + } + // Generic pattern search function that searches over multiple scales. // Each scale can have a different number of candidates and shape of // candidates as indicated in the num_candidates and candidates arrays // passed into this function -// static int pattern_search( - MACROBLOCK *x, MV *start_mv, int search_param, int sad_per_bit, - int do_init_search, int *cost_list, const aom_variance_fn_ptr_t *vfp, - int use_mvcost, const MV *center_mv, + FULLPEL_MV start_mv, const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, const int num_candidates[MAX_PATTERN_SCALES], - const MV candidates[MAX_PATTERN_SCALES][MAX_PATTERN_CANDIDATES]) { - const MACROBLOCKD *const xd = &x->e_mbd; + const MV candidates[MAX_PATTERN_SCALES][MAX_PATTERN_CANDIDATES], + int *cost_list, FULLPEL_MV *best_mv) { static const int search_param_to_steps[MAX_MVSEARCH_STEPS] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, }; int i, s, t; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; + + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; + const int ref_stride = ref->stride; const int last_is_4 = num_candidates[0] == 4; int br, bc; - int bestsad = INT_MAX; + int bestsad = INT_MAX, raw_bestsad = INT_MAX; int thissad; int k = -1; - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; + const int use_mvcost = ms_params->mv_cost_params.mv_cost_type != MV_COST_NONE; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; assert(search_param < MAX_MVSEARCH_STEPS); int best_init_s = search_param_to_steps[search_param]; // adjust ref_mv to make sure it is within MV range - clamp_mv(start_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - br = start_mv->row; - bc = start_mv->col; + clamp_fullmv(&start_mv, &ms_params->mv_limits); + br = start_mv.row; + bc = start_mv.col; if (cost_list != NULL) { cost_list[0] = cost_list[1] = cost_list[2] = cost_list[3] = cost_list[4] = INT_MAX; } + int costlist_has_sad = 0; // Work out the start point for the search - bestsad = vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, start_mv), in_what->stride) + - mvsad_err_cost(x, start_mv, &fcenter_mv, sad_per_bit); + raw_bestsad = get_mvpred_sad(ms_params, src, + get_buf_from_fullmv(ref, &start_mv), ref_stride); + bestsad = raw_bestsad + mvsad_err_cost_(&start_mv, mv_cost_params); - // Search all possible scales upto the search param around the center point + // Search all possible scales up to the search param around the center point // pick the scale of the point that is best as the starting scale of // further steps around it. if (do_init_search) { @@ -1178,23 +637,21 @@ static int pattern_search( best_init_s = -1; for (t = 0; t <= s; ++t) { int best_site = -1; - if (check_bounds(&x->mv_limits, br, bc, 1 << t)) { + if (check_bounds(&ms_params->mv_limits, br, bc, 1 << t)) { for (i = 0; i < num_candidates[t]; i++) { - const MV this_mv = { br + candidates[t][i].row, - bc + candidates[t][i].col }; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[t][i].row, + bc + candidates[t][i].col }; + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } else { for (i = 0; i < num_candidates[t]; i++) { - const MV this_mv = { br + candidates[t][i].row, - bc + candidates[t][i].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) continue; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[t][i].row, + bc + candidates[t][i].col }; + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) continue; + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } @@ -1221,23 +678,22 @@ static int pattern_search( for (; s >= last_s; s--) { // No need to search all points the 1st time if initial search was used if (!do_init_search || s != best_init_s) { - if (check_bounds(&x->mv_limits, br, bc, 1 << s)) { + if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) { for (i = 0; i < num_candidates[s]; i++) { - const MV this_mv = { br + candidates[s][i].row, - bc + candidates[s][i].col }; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[s][i].row, + bc + candidates[s][i].col }; + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } else { for (i = 0; i < num_candidates[s]; i++) { - const MV this_mv = { br + candidates[s][i].row, - bc + candidates[s][i].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) continue; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[s][i].row, + bc + candidates[s][i].col }; + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) + continue; + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } @@ -1258,27 +714,26 @@ static int pattern_search( next_chkpts_indices[1] = k; next_chkpts_indices[2] = (k == num_candidates[s] - 1) ? 0 : k + 1; - if (check_bounds(&x->mv_limits, br, bc, 1 << s)) { + if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) { for (i = 0; i < PATTERN_CANDIDATES_REF; i++) { - const MV this_mv = { + const FULLPEL_MV this_mv = { br + candidates[s][next_chkpts_indices[i]].row, bc + candidates[s][next_chkpts_indices[i]].col }; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } else { for (i = 0; i < PATTERN_CANDIDATES_REF; i++) { - const MV this_mv = { + const FULLPEL_MV this_mv = { br + candidates[s][next_chkpts_indices[i]].row, bc + candidates[s][next_chkpts_indices[i]].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) continue; - thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) + continue; + thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } @@ -1293,25 +748,25 @@ static int pattern_search( // Note: If we enter the if below, then cost_list must be non-NULL. if (s == 0) { - cost_list[0] = bestsad; + cost_list[0] = raw_bestsad; + costlist_has_sad = 1; if (!do_init_search || s != best_init_s) { - if (check_bounds(&x->mv_limits, br, bc, 1 << s)) { + if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) { for (i = 0; i < num_candidates[s]; i++) { - const MV this_mv = { br + candidates[s][i].row, - bc + candidates[s][i].col }; - cost_list[i + 1] = thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[s][i].row, + bc + candidates[s][i].col }; + cost_list[i + 1] = thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } else { for (i = 0; i < num_candidates[s]; i++) { - const MV this_mv = { br + candidates[s][i].row, - bc + candidates[s][i].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) continue; - cost_list[i + 1] = thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + const FULLPEL_MV this_mv = { br + candidates[s][i].row, + bc + candidates[s][i].col }; + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) + continue; + cost_list[i + 1] = thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } @@ -1330,32 +785,30 @@ static int pattern_search( next_chkpts_indices[2] = (k == num_candidates[s] - 1) ? 0 : k + 1; cost_list[1] = cost_list[2] = cost_list[3] = cost_list[4] = INT_MAX; cost_list[((k + 2) % 4) + 1] = cost_list[0]; - cost_list[0] = bestsad; + cost_list[0] = raw_bestsad; - if (check_bounds(&x->mv_limits, br, bc, 1 << s)) { + if (check_bounds(&ms_params->mv_limits, br, bc, 1 << s)) { for (i = 0; i < PATTERN_CANDIDATES_REF; i++) { - const MV this_mv = { + const FULLPEL_MV this_mv = { br + candidates[s][next_chkpts_indices[i]].row, bc + candidates[s][next_chkpts_indices[i]].col }; - cost_list[next_chkpts_indices[i] + 1] = thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + cost_list[next_chkpts_indices[i] + 1] = thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } else { for (i = 0; i < PATTERN_CANDIDATES_REF; i++) { - const MV this_mv = { + const FULLPEL_MV this_mv = { br + candidates[s][next_chkpts_indices[i]].row, bc + candidates[s][next_chkpts_indices[i]].col }; - if (!is_mv_in(&x->mv_limits, &this_mv)) { + if (!av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) { cost_list[next_chkpts_indices[i] + 1] = INT_MAX; continue; } - cost_list[next_chkpts_indices[i] + 1] = thissad = - vfp->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &this_mv), in_what->stride); + cost_list[next_chkpts_indices[i] + 1] = thissad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &this_mv), ref_stride); CHECK_BETTER } } @@ -1369,6 +822,9 @@ static int pattern_search( } } + best_mv->row = br; + best_mv->col = bc; + // Returns the one-away integer pel cost/sad around the best as follows: // cost_list[0]: cost/sad at the best integer pel // cost_list[1]: cost/sad at delta {0, -1} (left) from the best integer pel @@ -1376,75 +832,38 @@ static int pattern_search( // cost_list[3]: cost/sad at delta { 0, 1} (right) from the best integer pel // cost_list[4]: cost/sad at delta {-1, 0} (top) from the best integer pel if (cost_list) { - const MV best_int_mv = { br, bc }; - if (last_is_4) { - calc_int_sad_list(x, center_mv, sad_per_bit, vfp, &best_int_mv, cost_list, - use_mvcost, bestsad); + if (USE_SAD_COSTLIST) { + calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad); } else { - calc_int_cost_list(x, center_mv, sad_per_bit, vfp, &best_int_mv, - cost_list); + calc_int_cost_list(*best_mv, ms_params, cost_list); } } - x->best_mv.as_mv.row = br; - x->best_mv.as_mv.col = bc; - return bestsad; + best_mv->row = br; + best_mv->col = bc; + + const int var_cost = get_mvpred_var_cost(ms_params, best_mv); + return var_cost; } +#undef CHECK_BETTER -int av1_get_mvpred_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const aom_variance_fn_ptr_t *vfp, - int use_mvcost) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - const MV mv = { best_mv->row * 8, best_mv->col * 8 }; - unsigned int unused; - - return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), - in_what->stride, &unused) + - (use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit) - : 0); -} - -int av1_get_mvpred_av_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const uint8_t *second_pred, - const aom_variance_fn_ptr_t *vfp, int use_mvcost) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - const MV mv = { best_mv->row * 8, best_mv->col * 8 }; - unsigned int unused; - - return vfp->svaf(get_buf_from_mv(in_what, best_mv), in_what->stride, 0, 0, - what->buf, what->stride, &unused, second_pred) + - (use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit) - : 0); -} - -int av1_get_mvpred_mask_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const uint8_t *second_pred, - const uint8_t *mask, int mask_stride, - int invert_mask, const aom_variance_fn_ptr_t *vfp, - int use_mvcost) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - const MV mv = { best_mv->row * 8, best_mv->col * 8 }; - unsigned int unused; - - return vfp->msvf(what->buf, what->stride, 0, 0, - get_buf_from_mv(in_what, best_mv), in_what->stride, - second_pred, mask, mask_stride, invert_mask, &unused) + - (use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit) - : 0); -} - -int av1_hex_search(MACROBLOCK *x, MV *start_mv, int search_param, - int sad_per_bit, int do_init_search, int *cost_list, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - const MV *center_mv) { +// For the following foo_search, the input arguments are: +// x: The struct used to hold a bunch of random configs. +// start_mv: where we are starting our motion search +// search_param: how many steps to skip in our motion search. For example, +// a value 3 suggests that 3 search steps have already taken place prior to +// this function call, so we jump directly to step 4 of the search process +// sad_per_bit: a multiplier used to convert rate to sad cost +// do_init_search: if on, do an initial search of all possible scales around the +// start_mv, and then pick the best scale. +// cond_list: used to hold the cost around the best full mv so we can use it to +// speed up subpel search later. +// vfp: a function pointer to the simd function so we can compute the cost +// efficiently +// ref_mv: the reference mv used to compute the mv cost +static int hex_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, + int *cost_list, FULLPEL_MV *best_mv) { // First scale has 8-closest points, the rest have 6 points in hex shape // at increasing scales static const int hex_num_candidates[MAX_PATTERN_SCALES] = { 8, 6, 6, 6, 6, 6, @@ -1472,15 +891,14 @@ int av1_hex_search(MACROBLOCK *x, MV *start_mv, int search_param, { -512, 1024 }, { -1024, 0 } }, }; /* clang-format on */ - return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search, - cost_list, vfp, use_mvcost, center_mv, - hex_num_candidates, hex_candidates); + return pattern_search(start_mv, ms_params, search_param, do_init_search, + hex_num_candidates, hex_candidates, cost_list, best_mv); } -static int bigdia_search(MACROBLOCK *x, MV *start_mv, int search_param, - int sad_per_bit, int do_init_search, int *cost_list, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - const MV *center_mv) { +static int bigdia_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, + int *cost_list, FULLPEL_MV *best_mv) { // First scale has 4-closest points, the rest have 8 points in diamond // shape at increasing scales static const int bigdia_num_candidates[MAX_PATTERN_SCALES] = { @@ -1513,15 +931,15 @@ static int bigdia_search(MACROBLOCK *x, MV *start_mv, int search_param, { 512, 512 }, { 0, 1024 }, { -512, 512 }, { -1024, 0 } }, }; /* clang-format on */ - return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search, - cost_list, vfp, use_mvcost, center_mv, - bigdia_num_candidates, bigdia_candidates); + return pattern_search(start_mv, ms_params, search_param, do_init_search, + bigdia_num_candidates, bigdia_candidates, cost_list, + best_mv); } -static int square_search(MACROBLOCK *x, MV *start_mv, int search_param, - int sad_per_bit, int do_init_search, int *cost_list, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - const MV *center_mv) { +static int square_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, + int *cost_list, FULLPEL_MV *best_mv) { // All scales have 8 closest points in square shape static const int square_num_candidates[MAX_PATTERN_SCALES] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, @@ -1554,42 +972,215 @@ static int square_search(MACROBLOCK *x, MV *start_mv, int search_param, { 1024, 1024 }, { 0, 1024 }, { -1024, 1024 }, { -1024, 0 } }, }; /* clang-format on */ - return pattern_search(x, start_mv, search_param, sad_per_bit, do_init_search, - cost_list, vfp, use_mvcost, center_mv, - square_num_candidates, square_candidates); + return pattern_search(start_mv, ms_params, search_param, do_init_search, + square_num_candidates, square_candidates, cost_list, + best_mv); } -static int fast_hex_search(MACROBLOCK *x, MV *ref_mv, int search_param, - int sad_per_bit, - int do_init_search, // must be zero for fast_hex - int *cost_list, const aom_variance_fn_ptr_t *vfp, - int use_mvcost, const MV *center_mv) { - return av1_hex_search(x, ref_mv, AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param), - sad_per_bit, do_init_search, cost_list, vfp, use_mvcost, - center_mv); +static int fast_hex_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, + int *cost_list, FULLPEL_MV *best_mv) { + return hex_search(start_mv, ms_params, + AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param), + do_init_search, cost_list, best_mv); } -static int fast_dia_search(MACROBLOCK *x, MV *ref_mv, int search_param, - int sad_per_bit, int do_init_search, int *cost_list, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - const MV *center_mv) { - return bigdia_search(x, ref_mv, AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param), - sad_per_bit, do_init_search, cost_list, vfp, use_mvcost, - center_mv); +static int fast_dia_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, const int do_init_search, + int *cost_list, FULLPEL_MV *best_mv) { + return bigdia_search(start_mv, ms_params, + AOMMAX(MAX_MVSEARCH_STEPS - 2, search_param), + do_init_search, cost_list, best_mv); } -#undef CHECK_BETTER +static int diamond_search_sad(FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int search_param, int *num00, + FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) { + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; -// Exhuastive motion search around a given centre position with a given + const int ref_stride = ref->stride; + const uint8_t *best_address; + + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const uint8_t *mask = ms_params->ms_buffers.mask; + const uint8_t *second_pred = ms_params->ms_buffers.second_pred; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + + const search_site_config *cfg = ms_params->search_sites; + + unsigned int bestsad = INT_MAX; + int best_site = 0; + int is_off_center = 0; + + clamp_fullmv(&start_mv, &ms_params->mv_limits); + + // search_param determines the length of the initial step and hence the number + // of iterations. + const int tot_steps = cfg->ss_count - search_param; + + *num00 = 0; + *best_mv = start_mv; + + // Check the starting position + best_address = get_buf_from_fullmv(ref, &start_mv); + bestsad = get_mvpred_compound_sad(ms_params, src, best_address, ref_stride); + bestsad += mvsad_err_cost_(best_mv, &ms_params->mv_cost_params); + + int next_step_size = tot_steps > 2 ? cfg->radius[tot_steps - 2] : 1; + for (int step = tot_steps - 1; step >= 0; --step) { + const search_site *ss = cfg->ss[step]; + best_site = 0; + if (step > 0) next_step_size = cfg->radius[step - 1]; + + int all_in = 1, j; + // Trap illegal vectors + all_in &= best_mv->row + ss[1].mv.row >= ms_params->mv_limits.row_min; + all_in &= best_mv->row + ss[2].mv.row <= ms_params->mv_limits.row_max; + all_in &= best_mv->col + ss[3].mv.col >= ms_params->mv_limits.col_min; + all_in &= best_mv->col + ss[4].mv.col <= ms_params->mv_limits.col_max; + + // TODO(anyone): Implement 4 points search for msdf&sdaf + if (all_in && !mask && !second_pred) { + const uint8_t *src_buf = src->buf; + const int src_stride = src->stride; + for (int idx = 1; idx <= cfg->searches_per_step[step]; idx += 4) { + unsigned char const *block_offset[4]; + unsigned int sads[4]; + + for (j = 0; j < 4; j++) + block_offset[j] = ss[idx + j].offset + best_address; + + vfp->sdx4df(src_buf, src_stride, block_offset, ref_stride, sads); + for (j = 0; j < 4; j++) { + if (sads[j] < bestsad) { + const FULLPEL_MV this_mv = { best_mv->row + ss[idx + j].mv.row, + best_mv->col + ss[idx + j].mv.col }; + unsigned int thissad = + sads[j] + mvsad_err_cost_(&this_mv, mv_cost_params); + if (thissad < bestsad) { + bestsad = thissad; + best_site = idx + j; + } + } + } + } + } else { + for (int idx = 1; idx <= cfg->searches_per_step[step]; idx++) { + const FULLPEL_MV this_mv = { best_mv->row + ss[idx].mv.row, + best_mv->col + ss[idx].mv.col }; + + if (av1_is_fullmv_in_range(&ms_params->mv_limits, this_mv)) { + const uint8_t *const check_here = ss[idx].offset + best_address; + unsigned int thissad; + + thissad = + get_mvpred_compound_sad(ms_params, src, check_here, ref_stride); + + if (thissad < bestsad) { + thissad += mvsad_err_cost_(&this_mv, mv_cost_params); + if (thissad < bestsad) { + bestsad = thissad; + best_site = idx; + } + } + } + } + } + + if (best_site != 0) { + if (second_best_mv) { + *second_best_mv = *best_mv; + } + best_mv->row += ss[best_site].mv.row; + best_mv->col += ss[best_site].mv.col; + best_address += ss[best_site].offset; + is_off_center = 1; + } + + if (is_off_center == 0) (*num00)++; + + if (best_site == 0) { + while (next_step_size == cfg->radius[step] && step > 2) { + ++(*num00); + --step; + next_step_size = cfg->radius[step - 1]; + } + } + } + + return bestsad; +} + +/* do_refine: If last step (1-away) of n-step search doesn't pick the center + point as the best match, we will do a final 1-away diamond + refining search */ +static int full_pixel_diamond(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int step_param, int *cost_list, + FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) { + const search_site_config *cfg = ms_params->search_sites; + int thissme, n, num00 = 0; + int bestsme = diamond_search_sad(start_mv, ms_params, step_param, &n, best_mv, + second_best_mv); + + if (bestsme < INT_MAX) { + bestsme = get_mvpred_compound_var_cost(ms_params, best_mv); + } + + // If there won't be more n-step search, check to see if refining search is + // needed. + const int further_steps = cfg->ss_count - 1 - step_param; + while (n < further_steps) { + ++n; + + if (num00) { + num00--; + } else { + // TODO(chiyotsai@google.com): There is another bug here where the second + // best mv gets incorrectly overwritten. Fix it later. + FULLPEL_MV tmp_best_mv; + thissme = diamond_search_sad(start_mv, ms_params, step_param + n, &num00, + &tmp_best_mv, second_best_mv); + + if (thissme < INT_MAX) { + thissme = get_mvpred_compound_var_cost(ms_params, &tmp_best_mv); + } + + if (thissme < bestsme) { + bestsme = thissme; + *best_mv = tmp_best_mv; + } + } + } + + // Return cost list. + if (cost_list) { + if (USE_SAD_COSTLIST) { + const int costlist_has_sad = 0; + calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad); + } else { + calc_int_cost_list(*best_mv, ms_params, cost_list); + } + } + return bestsme; +} + +// Exhaustive motion search around a given centre position with a given // step size. -static int exhuastive_mesh_search(MACROBLOCK *x, MV *ref_mv, MV *best_mv, - int range, int step, int sad_per_bit, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - MV fcenter_mv = { center_mv->row, center_mv->col }; +static int exhaustive_mesh_search(FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int range, const int step, + FULLPEL_MV *best_mv, + FULLPEL_MV *second_best_mv) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const struct buf_2d *const src = ms_params->ms_buffers.src; + const struct buf_2d *const ref = ms_params->ms_buffers.ref; + const int ref_stride = ref->stride; unsigned int best_sad = INT_MAX; int r, c, i; int start_col, end_col, start_row, end_row; @@ -1597,31 +1188,30 @@ static int exhuastive_mesh_search(MACROBLOCK *x, MV *ref_mv, MV *best_mv, assert(step >= 1); - clamp_mv(&fcenter_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - *best_mv = fcenter_mv; - best_sad = - fn_ptr->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &fcenter_mv), in_what->stride) + - mvsad_err_cost(x, &fcenter_mv, ref_mv, sad_per_bit); - start_row = AOMMAX(-range, x->mv_limits.row_min - fcenter_mv.row); - start_col = AOMMAX(-range, x->mv_limits.col_min - fcenter_mv.col); - end_row = AOMMIN(range, x->mv_limits.row_max - fcenter_mv.row); - end_col = AOMMIN(range, x->mv_limits.col_max - fcenter_mv.col); + clamp_fullmv(&start_mv, &ms_params->mv_limits); + *best_mv = start_mv; + best_sad = get_mvpred_sad(ms_params, src, get_buf_from_fullmv(ref, &start_mv), + ref_stride); + best_sad += mvsad_err_cost_(&start_mv, mv_cost_params); + start_row = AOMMAX(-range, ms_params->mv_limits.row_min - start_mv.row); + start_col = AOMMAX(-range, ms_params->mv_limits.col_min - start_mv.col); + end_row = AOMMIN(range, ms_params->mv_limits.row_max - start_mv.row); + end_col = AOMMIN(range, ms_params->mv_limits.col_max - start_mv.col); for (r = start_row; r <= end_row; r += step) { for (c = start_col; c <= end_col; c += col_step) { // Step > 1 means we are not checking every location in this pass. if (step > 1) { - const MV mv = { fcenter_mv.row + r, fcenter_mv.col + c }; - unsigned int sad = - fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, &mv), - in_what->stride); + const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c }; + unsigned int sad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &mv), ref_stride); if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, ref_mv, sad_per_bit); + sad += mvsad_err_cost_(&mv, mv_cost_params); if (sad < best_sad) { best_sad = sad; - x->second_best_mv.as_mv = *best_mv; + if (second_best_mv) { + *second_best_mv = *best_mv; + } *best_mv = mv; } } @@ -1631,34 +1221,37 @@ static int exhuastive_mesh_search(MACROBLOCK *x, MV *ref_mv, MV *best_mv, unsigned int sads[4]; const uint8_t *addrs[4]; for (i = 0; i < 4; ++i) { - const MV mv = { fcenter_mv.row + r, fcenter_mv.col + c + i }; - addrs[i] = get_buf_from_mv(in_what, &mv); + const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i }; + addrs[i] = get_buf_from_fullmv(ref, &mv); } - fn_ptr->sdx4df(what->buf, what->stride, addrs, in_what->stride, sads); + vfp->sdx4df(src->buf, src->stride, addrs, ref_stride, sads); for (i = 0; i < 4; ++i) { if (sads[i] < best_sad) { - const MV mv = { fcenter_mv.row + r, fcenter_mv.col + c + i }; + const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i }; const unsigned int sad = - sads[i] + mvsad_err_cost(x, &mv, ref_mv, sad_per_bit); + sads[i] + mvsad_err_cost_(&mv, mv_cost_params); if (sad < best_sad) { best_sad = sad; - x->second_best_mv.as_mv = *best_mv; + if (second_best_mv) { + *second_best_mv = *best_mv; + } *best_mv = mv; } } } } else { for (i = 0; i < end_col - c; ++i) { - const MV mv = { fcenter_mv.row + r, fcenter_mv.col + c + i }; - unsigned int sad = - fn_ptr->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &mv), in_what->stride); + const FULLPEL_MV mv = { start_mv.row + r, start_mv.col + c + i }; + unsigned int sad = get_mvpred_sad( + ms_params, src, get_buf_from_fullmv(ref, &mv), ref_stride); if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, ref_mv, sad_per_bit); + sad += mvsad_err_cost_(&mv, mv_cost_params); if (sad < best_sad) { best_sad = sad; - x->second_best_mv.as_mv = *best_mv; + if (second_best_mv) { + *second_best_mv = *best_mv; + } *best_mv = mv; } } @@ -1671,234 +1264,27 @@ static int exhuastive_mesh_search(MACROBLOCK *x, MV *ref_mv, MV *best_mv, return best_sad; } -int av1_diamond_search_sad_c(MACROBLOCK *x, const search_site_config *cfg, - MV *ref_mv, MV *best_mv, int search_param, - int sad_per_bit, int *num00, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv) { - int i, j, step; - - const MACROBLOCKD *const xd = &x->e_mbd; - uint8_t *what = x->plane[0].src.buf; - const int what_stride = x->plane[0].src.stride; - const uint8_t *in_what; - const int in_what_stride = xd->plane[0].pre[0].stride; - const uint8_t *best_address; - - unsigned int bestsad = INT_MAX; - int best_site = 0; - int last_site = 0; - - int ref_row; - int ref_col; - - // search_param determines the length of the initial step and hence the number - // of iterations. - // 0 = initial step (MAX_FIRST_STEP) pel - // 1 = (MAX_FIRST_STEP/2) pel, - // 2 = (MAX_FIRST_STEP/4) pel... - const search_site *ss = &cfg->ss[search_param * cfg->searches_per_step]; - const int tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param; - - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; - clamp_mv(ref_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - ref_row = ref_mv->row; - ref_col = ref_mv->col; - *num00 = 0; - best_mv->row = ref_row; - best_mv->col = ref_col; - - // Work out the start point for the search - in_what = xd->plane[0].pre[0].buf + ref_row * in_what_stride + ref_col; - best_address = in_what; - - // Check the starting position - bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride) + - mvsad_err_cost(x, best_mv, &fcenter_mv, sad_per_bit); - - i = 1; - - for (step = 0; step < tot_steps; step++) { - int all_in = 1, t; - - // All_in is true if every one of the points we are checking are within - // the bounds of the image. - all_in &= ((best_mv->row + ss[i].mv.row) > x->mv_limits.row_min); - all_in &= ((best_mv->row + ss[i + 1].mv.row) < x->mv_limits.row_max); - all_in &= ((best_mv->col + ss[i + 2].mv.col) > x->mv_limits.col_min); - all_in &= ((best_mv->col + ss[i + 3].mv.col) < x->mv_limits.col_max); - - // If all the pixels are within the bounds we don't check whether the - // search point is valid in this loop, otherwise we check each point - // for validity.. - if (all_in) { - unsigned int sad_array[4]; - - for (j = 0; j < cfg->searches_per_step; j += 4) { - unsigned char const *block_offset[4]; - - for (t = 0; t < 4; t++) - block_offset[t] = ss[i + t].offset + best_address; - - fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, - sad_array); - - for (t = 0; t < 4; t++, i++) { - if (sad_array[t] < bestsad) { - const MV this_mv = { best_mv->row + ss[i].mv.row, - best_mv->col + ss[i].mv.col }; - sad_array[t] += - mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit); - if (sad_array[t] < bestsad) { - bestsad = sad_array[t]; - best_site = i; - } - } - } - } - } else { - for (j = 0; j < cfg->searches_per_step; j++) { - // Trap illegal vectors - const MV this_mv = { best_mv->row + ss[i].mv.row, - best_mv->col + ss[i].mv.col }; - - if (is_mv_in(&x->mv_limits, &this_mv)) { - const uint8_t *const check_here = ss[i].offset + best_address; - unsigned int thissad = - fn_ptr->sdf(what, what_stride, check_here, in_what_stride); - - if (thissad < bestsad) { - thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit); - if (thissad < bestsad) { - bestsad = thissad; - best_site = i; - } - } - } - i++; - } - } - if (best_site != last_site) { - x->second_best_mv.as_mv = *best_mv; - best_mv->row += ss[best_site].mv.row; - best_mv->col += ss[best_site].mv.col; - best_address += ss[best_site].offset; - last_site = best_site; -#if defined(NEW_DIAMOND_SEARCH) - while (1) { - const MV this_mv = { best_mv->row + ss[best_site].mv.row, - best_mv->col + ss[best_site].mv.col }; - if (is_mv_in(&x->mv_limits, &this_mv)) { - const uint8_t *const check_here = ss[best_site].offset + best_address; - unsigned int thissad = - fn_ptr->sdf(what, what_stride, check_here, in_what_stride); - if (thissad < bestsad) { - thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit); - if (thissad < bestsad) { - bestsad = thissad; - best_mv->row += ss[best_site].mv.row; - best_mv->col += ss[best_site].mv.col; - best_address += ss[best_site].offset; - continue; - } - } - } - break; - } -#endif - } else if (best_address == in_what) { - (*num00)++; - } - } - return bestsad; -} - -/* do_refine: If last step (1-away) of n-step search doesn't pick the center - point as the best match, we will do a final 1-away diamond - refining search */ -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 search_site_config *cfg) { - MV temp_mv; - int thissme, n, num00 = 0; - 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; - - // If there won't be more n-step search, check to see if refining search is - // needed. - if (n > further_steps) do_refine = 0; - - while (n < further_steps) { - ++n; - - if (num00) { - num00--; - } else { - 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); - - // check to see if refining search is needed. - if (num00 > further_steps - n) do_refine = 0; - - if (thissme < bestsme) { - bestsme = thissme; - x->best_mv.as_mv = temp_mv; - } - } - } - - // final 1-away diamond refining search - if (do_refine) { - const int search_range = 8; - MV best_mv = x->best_mv.as_mv; - thissme = av1_refining_search_sad(x, &best_mv, sadpb, search_range, fn_ptr, - ref_mv); - if (thissme < INT_MAX) - thissme = av1_get_mvpred_var(x, &best_mv, ref_mv, fn_ptr, 1); - if (thissme < bestsme) { - bestsme = thissme; - x->best_mv.as_mv = best_mv; - } - } - - // Return cost list. - if (cost_list) { - calc_int_cost_list(x, ref_mv, sadpb, fn_ptr, &x->best_mv.as_mv, cost_list); - } - return bestsme; -} - -#define MIN_RANGE 7 -#define MAX_RANGE 256 -#define MIN_INTERVAL 1 // Runs an limited range exhaustive mesh search using a pattern set // according to the encode speed profile. -static int full_pixel_exhaustive( - MACROBLOCK *x, const MV *centre_mv_full, int sadpb, int *cost_list, - const aom_variance_fn_ptr_t *fn_ptr, const MV *ref_mv, MV *dst_mv, - const struct MESH_PATTERN *const mesh_patterns) { - MV temp_mv = { centre_mv_full->row, centre_mv_full->col }; - MV f_ref_mv = { ref_mv->row >> 3, ref_mv->col >> 3 }; +static int full_pixel_exhaustive(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct MESH_PATTERN *const mesh_patterns, + int *cost_list, FULLPEL_MV *best_mv, + FULLPEL_MV *second_best_mv) { + const int kMinRange = 7; + const int kMaxRange = 256; + const int kMinInterval = 1; + int bestsme; int i; int interval = mesh_patterns[0].interval; int range = mesh_patterns[0].range; int baseline_interval_divisor; - // Keep track of number of exhaustive calls (this frame in this thread). - if (x->ex_search_count_ptr != NULL) ++(*x->ex_search_count_ptr); + *best_mv = start_mv; // Trap illegal values for interval and range for this function. - if ((range < MIN_RANGE) || (range > MAX_RANGE) || (interval < MIN_INTERVAL) || + if ((range < kMinRange) || (range > kMaxRange) || (interval < kMinInterval) || (interval > range)) return INT_MAX; @@ -1906,119 +1292,47 @@ static int full_pixel_exhaustive( // Check size of proposed first range against magnitude of the centre // value used as a starting point. - range = AOMMAX(range, (5 * AOMMAX(abs(temp_mv.row), abs(temp_mv.col))) / 4); - range = AOMMIN(range, MAX_RANGE); + range = AOMMAX(range, (5 * AOMMAX(abs(best_mv->row), abs(best_mv->col))) / 4); + range = AOMMIN(range, kMaxRange); interval = AOMMAX(interval, range / baseline_interval_divisor); // initial search - bestsme = exhuastive_mesh_search(x, &f_ref_mv, &temp_mv, range, interval, - sadpb, fn_ptr, &temp_mv); + bestsme = exhaustive_mesh_search(*best_mv, ms_params, range, interval, + best_mv, second_best_mv); - if ((interval > MIN_INTERVAL) && (range > MIN_RANGE)) { + if ((interval > kMinInterval) && (range > kMinRange)) { // Progressive searches with range and step size decreasing each time // till we reach a step size of 1. Then break out. for (i = 1; i < MAX_MESH_STEP; ++i) { // First pass with coarser step and longer range - bestsme = exhuastive_mesh_search( - x, &f_ref_mv, &temp_mv, mesh_patterns[i].range, - mesh_patterns[i].interval, sadpb, fn_ptr, &temp_mv); + bestsme = exhaustive_mesh_search( + *best_mv, ms_params, mesh_patterns[i].range, + mesh_patterns[i].interval, best_mv, second_best_mv); if (mesh_patterns[i].interval == 1) break; } } - if (bestsme < INT_MAX) - bestsme = av1_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1); - *dst_mv = temp_mv; + if (bestsme < INT_MAX) { + bestsme = get_mvpred_var_cost(ms_params, best_mv); + } // Return cost list. if (cost_list) { - calc_int_cost_list(x, ref_mv, sadpb, fn_ptr, dst_mv, cost_list); + if (USE_SAD_COSTLIST) { + const int costlist_has_sad = 0; + calc_int_sad_list(*best_mv, ms_params, cost_list, costlist_has_sad); + } else { + calc_int_cost_list(*best_mv, ms_params, cost_list); + } } return bestsme; } -int av1_refining_search_sad(MACROBLOCK *x, MV *ref_mv, int error_per_bit, - int search_range, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv) { - const MACROBLOCKD *const xd = &x->e_mbd; - const MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } }; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; - const uint8_t *best_address = get_buf_from_mv(in_what, ref_mv); - unsigned int best_sad = - fn_ptr->sdf(what->buf, what->stride, best_address, in_what->stride) + - mvsad_err_cost(x, ref_mv, &fcenter_mv, error_per_bit); - int i, j; - - for (i = 0; i < search_range; i++) { - int best_site = -1; - const int all_in = ((ref_mv->row - 1) > x->mv_limits.row_min) & - ((ref_mv->row + 1) < x->mv_limits.row_max) & - ((ref_mv->col - 1) > x->mv_limits.col_min) & - ((ref_mv->col + 1) < x->mv_limits.col_max); - - if (all_in) { - unsigned int sads[4]; - const uint8_t *const positions[4] = { best_address - in_what->stride, - best_address - 1, best_address + 1, - best_address + in_what->stride }; - - fn_ptr->sdx4df(what->buf, what->stride, positions, in_what->stride, sads); - - for (j = 0; j < 4; ++j) { - if (sads[j] < best_sad) { - const MV mv = { ref_mv->row + neighbors[j].row, - ref_mv->col + neighbors[j].col }; - sads[j] += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit); - if (sads[j] < best_sad) { - best_sad = sads[j]; - best_site = j; - } - } - } - } else { - for (j = 0; j < 4; ++j) { - const MV mv = { ref_mv->row + neighbors[j].row, - ref_mv->col + neighbors[j].col }; - - if (is_mv_in(&x->mv_limits, &mv)) { - unsigned int sad = - fn_ptr->sdf(what->buf, what->stride, - get_buf_from_mv(in_what, &mv), in_what->stride); - if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit); - if (sad < best_sad) { - best_sad = sad; - best_site = j; - } - } - } - } - } - - if (best_site == -1) { - break; - } else { - x->second_best_mv.as_mv = *ref_mv; - ref_mv->row += neighbors[best_site].row; - ref_mv->col += neighbors[best_site].col; - best_address = get_buf_from_mv(in_what, ref_mv); - } - } - - return best_sad; -} - // This function is called when we do joint motion search in comp_inter_inter // mode, or when searching for one component of an ext-inter compound mode. -int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range, - const aom_variance_fn_ptr_t *fn_ptr, - const uint8_t *mask, int mask_stride, - int invert_mask, const MV *center_mv, - const uint8_t *second_pred) { +int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const FULLPEL_MV start_mv, FULLPEL_MV *best_mv) { static const search_neighbors neighbors[8] = { { { -1, 0 }, -1 * SEARCH_GRID_STRIDE_8P + 0 }, { { 0, -1 }, 0 * SEARCH_GRID_STRIDE_8P - 1 }, @@ -2029,59 +1343,47 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range, { { -1, 1 }, -1 * SEARCH_GRID_STRIDE_8P + 1 }, { { 1, 1 }, 1 * SEARCH_GRID_STRIDE_8P + 1 } }; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const what = &x->plane[0].src; - const struct buf_2d *const in_what = &xd->plane[0].pre[0]; - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; - MV *best_mv = &x->best_mv.as_mv; - unsigned int best_sad = INT_MAX; - int i, j; + uint8_t do_refine_search_grid[SEARCH_GRID_STRIDE_8P * SEARCH_GRID_STRIDE_8P] = { 0 }; int grid_center = SEARCH_GRID_CENTER_8P; int grid_coord = grid_center; - clamp_mv(best_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - if (mask) { - best_sad = fn_ptr->msdf(what->buf, what->stride, - get_buf_from_mv(in_what, best_mv), in_what->stride, - second_pred, mask, mask_stride, invert_mask) + - mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit); - } else { - best_sad = - fn_ptr->sdaf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), - in_what->stride, second_pred) + - mvsad_err_cost(x, best_mv, &fcenter_mv, error_per_bit); - } + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const FullMvLimits *mv_limits = &ms_params->mv_limits; + const MSBuffers *ms_buffers = &ms_params->ms_buffers; + const struct buf_2d *src = ms_buffers->src; + const struct buf_2d *ref = ms_buffers->ref; + const int ref_stride = ref->stride; + + *best_mv = start_mv; + clamp_fullmv(best_mv, mv_limits); + + unsigned int best_sad = get_mvpred_compound_sad( + ms_params, src, get_buf_from_fullmv(ref, best_mv), ref_stride); + best_sad += mvsad_err_cost_(best_mv, mv_cost_params); do_refine_search_grid[grid_coord] = 1; - for (i = 0; i < search_range; ++i) { + for (int i = 0; i < SEARCH_RANGE_8P; ++i) { int best_site = -1; - for (j = 0; j < 8; ++j) { + for (int j = 0; j < 8; ++j) { grid_coord = grid_center + neighbors[j].coord_offset; if (do_refine_search_grid[grid_coord] == 1) { continue; } - const MV mv = { best_mv->row + neighbors[j].coord.row, - best_mv->col + neighbors[j].coord.col }; + const FULLPEL_MV mv = { best_mv->row + neighbors[j].coord.row, + best_mv->col + neighbors[j].coord.col }; do_refine_search_grid[grid_coord] = 1; - if (is_mv_in(&x->mv_limits, &mv)) { + if (av1_is_fullmv_in_range(mv_limits, mv)) { unsigned int sad; - if (mask) { - sad = fn_ptr->msdf(what->buf, what->stride, - get_buf_from_mv(in_what, &mv), in_what->stride, - second_pred, mask, mask_stride, invert_mask); - } else { - sad = fn_ptr->sdaf(what->buf, what->stride, - get_buf_from_mv(in_what, &mv), in_what->stride, - second_pred); - } + sad = get_mvpred_compound_sad( + ms_params, src, get_buf_from_fullmv(ref, &mv), ref_stride); if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit); + sad += mvsad_err_cost_(&mv, mv_cost_params); + if (sad < best_sad) { best_sad = sad; best_site = j; @@ -2101,20 +1403,164 @@ int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range, return best_sad; } -#define MIN_EX_SEARCH_LIMIT 128 -static int is_exhaustive_allowed(const AV1_COMP *const cpi, MACROBLOCK *x, - int max_exhaustive_pct) { - const SPEED_FEATURES *const sf = &cpi->sf; - int is_allowed = sf->allow_exhaustive_searches && - (sf->exhaustive_searches_thresh < INT_MAX) && - !cpi->rc.is_src_frame_alt_ref; - if (x->m_search_count_ptr != NULL && x->ex_search_count_ptr != NULL) { - const int max_ex = - AOMMAX(MIN_EX_SEARCH_LIMIT, - (*x->m_search_count_ptr * max_exhaustive_pct) / 100); - is_allowed = *x->ex_search_count_ptr <= max_ex && is_allowed; +int av1_full_pixel_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int step_param, int *cost_list, + FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv) { + const BLOCK_SIZE bsize = ms_params->bsize; + const SEARCH_METHODS search_method = ms_params->search_method; + + const int is_intra_mode = ms_params->is_intra_mode; + int run_mesh_search = ms_params->run_mesh_search; + + int var = 0; + MARK_MV_INVALID(best_mv); + if (second_best_mv) { + MARK_MV_INVALID(second_best_mv); } - return is_allowed; + + assert(ms_params->ms_buffers.second_pred == NULL && + ms_params->ms_buffers.mask == NULL && + "av1_full_pixel_search does not support compound pred"); + + if (cost_list) { + cost_list[0] = INT_MAX; + cost_list[1] = INT_MAX; + cost_list[2] = INT_MAX; + cost_list[3] = INT_MAX; + cost_list[4] = INT_MAX; + } + + switch (search_method) { + case FAST_DIAMOND: + var = fast_dia_search(start_mv, ms_params, step_param, 0, cost_list, + best_mv); + break; + case FAST_HEX: + var = fast_hex_search(start_mv, ms_params, step_param, 0, cost_list, + best_mv); + break; + case HEX: + var = hex_search(start_mv, ms_params, step_param, 1, cost_list, best_mv); + break; + case SQUARE: + var = + square_search(start_mv, ms_params, step_param, 1, cost_list, best_mv); + break; + case BIGDIA: + var = + bigdia_search(start_mv, ms_params, step_param, 1, cost_list, best_mv); + break; + case NSTEP: + case DIAMOND: + var = full_pixel_diamond(start_mv, ms_params, step_param, cost_list, + best_mv, second_best_mv); + break; + default: assert(0 && "Invalid search method."); + } + + // Should we allow a follow on exhaustive search? + if (!run_mesh_search && search_method == NSTEP) { + int exhuastive_thr = ms_params->force_mesh_thresh; + exhuastive_thr >>= + 10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]); + // Threshold variance for an exhaustive full search. + if (var > exhuastive_thr) run_mesh_search = 1; + } + + // TODO(yunqing): the following is used to reduce mesh search in temporal + // filtering. Can extend it to intrabc. + if (!is_intra_mode && ms_params->prune_mesh_search) { + const int full_pel_mv_diff = AOMMAX(abs(start_mv.row - best_mv->row), + abs(start_mv.col - best_mv->col)); + if (full_pel_mv_diff <= 4) { + run_mesh_search = 0; + } + } + + if (run_mesh_search) { + int var_ex; + FULLPEL_MV tmp_mv_ex; + // Pick the mesh pattern for exhaustive search based on the toolset (intraBC + // or non-intraBC) + // TODO(chiyotsai@google.com): There is a bug here where the second best mv + // gets overwritten without actually comparing the rdcost. + const MESH_PATTERN *const mesh_patterns = + ms_params->mesh_patterns[is_intra_mode]; + // TODO(chiyotsai@google.com): the second best mv is not set correctly by + // full_pixel_exhaustive, which can incorrectly override it. + var_ex = full_pixel_exhaustive(*best_mv, ms_params, mesh_patterns, + cost_list, &tmp_mv_ex, second_best_mv); + if (var_ex < var) { + var = var_ex; + *best_mv = tmp_mv_ex; + } + } + + return var; +} + +int av1_intrabc_hash_search(const AV1_COMP *cpi, const MACROBLOCKD *xd, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + IntraBCHashInfo *intrabc_hash_info, + FULLPEL_MV *best_mv) { + if (!av1_use_hash_me(cpi)) return INT_MAX; + + const BLOCK_SIZE bsize = ms_params->bsize; + const int block_width = block_size_wide[bsize]; + const int block_height = block_size_high[bsize]; + + if (block_width != block_height) return INT_MAX; + + const FullMvLimits *mv_limits = &ms_params->mv_limits; + const MSBuffers *ms_buffer = &ms_params->ms_buffers; + + const uint8_t *src = ms_buffer->src->buf; + const int src_stride = ms_buffer->src->stride; + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int x_pos = mi_col * MI_SIZE; + const int y_pos = mi_row * MI_SIZE; + + uint32_t hash_value1, hash_value2; + int best_hash_cost = INT_MAX; + + // for the hashMap + hash_table *ref_frame_hash = &intrabc_hash_info->intrabc_hash_table; + + av1_get_block_hash_value(intrabc_hash_info, src, src_stride, block_width, + &hash_value1, &hash_value2, is_cur_buf_hbd(xd)); + + const int count = av1_hash_table_count(ref_frame_hash, hash_value1); + if (count <= 1) { + return INT_MAX; + } + + Iterator iterator = av1_hash_get_first_iterator(ref_frame_hash, hash_value1); + for (int i = 0; i < count; i++, aom_iterator_increment(&iterator)) { + block_hash ref_block_hash = *(block_hash *)(aom_iterator_get(&iterator)); + if (hash_value2 == ref_block_hash.hash_value2) { + // Make sure the prediction is from valid area. + const MV dv = { GET_MV_SUBPEL(ref_block_hash.y - y_pos), + GET_MV_SUBPEL(ref_block_hash.x - x_pos) }; + if (!av1_is_dv_valid(dv, &cpi->common, xd, mi_row, mi_col, bsize, + cpi->common.seq_params.mib_size_log2)) + continue; + + FULLPEL_MV hash_mv; + hash_mv.col = ref_block_hash.x - x_pos; + hash_mv.row = ref_block_hash.y - y_pos; + if (!av1_is_fullmv_in_range(mv_limits, hash_mv)) continue; + const int refCost = get_mvpred_var_cost(ms_params, &hash_mv); + if (refCost < best_hash_cost) { + best_hash_cost = refCost; + *best_mv = hash_mv; + } + } + } + + return best_hash_cost; } static int vector_match(int16_t *ref, int16_t *src, int bwl) { @@ -2182,13 +1628,7 @@ static int vector_match(int16_t *ref, int16_t *src, int bwl) { return (center - (bw >> 1)); } -static const MV search_pos[4] = { - { -1, 0 }, - { 0, -1 }, - { 0, 1 }, - { 1, 0 }, -}; - +// A special fast version of motion search used in rt mode 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) { @@ -2207,13 +1647,17 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, 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; + int_mv *best_int_mv = &xd->mi[0]->mv[0]; 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; + static const MV search_pos[4] = { + { -1, 0 }, + { 0, -1 }, + { 0, 1 }, + { 1, 0 }, + }; if (scaled_ref_frame) { int i; @@ -2227,8 +1671,7 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, if (xd->bd != 8) { unsigned int sad; - tmp_mv->row = 0; - tmp_mv->col = 0; + best_int_mv->as_fullmv = kZeroFullMv; sad = cpi->fn_ptr[bsize].sdf(x->plane[0].src.buf, src_stride, xd->plane[0].pre[0].buf, ref_stride); @@ -2265,12 +1708,14 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, } // 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]); + best_int_mv->as_fullmv.col = + vector_match(hbuf, src_hbuf, mi_size_wide_log2[bsize]); + best_int_mv->as_fullmv.row = + vector_match(vbuf, src_vbuf, mi_size_high_log2[bsize]); - this_mv = *tmp_mv; + FULLPEL_MV this_mv = best_int_mv->as_fullmv; src_buf = x->plane[0].src.buf; - ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col; + ref_buf = get_buf_from_fullmv(&xd->plane[0].pre[0], &this_mv); best_sad = cpi->fn_ptr[bsize].sdf(src_buf, src_stride, ref_buf, ref_stride); { @@ -2287,8 +1732,8 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, 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; + best_int_mv->as_fullmv.row = search_pos[idx].row + this_mv.row; + best_int_mv->as_fullmv.col = search_pos[idx].col + this_mv.col; } } @@ -2302,22 +1747,19 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, else this_mv.col += 1; - ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col; + ref_buf = get_buf_from_fullmv(&xd->plane[0].pre[0], &this_mv); 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_int_mv->as_fullmv = this_mv; best_sad = tmp_sad; } - tmp_mv->row *= 8; - tmp_mv->col *= 8; + convert_fullmv_to_mv(best_int_mv); - 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); + SubpelMvLimits subpel_mv_limits; + av1_set_subpel_mv_search_range(&subpel_mv_limits, &x->mv_limits, ref_mv); + clamp_mv(&best_int_mv->as_mv, &subpel_mv_limits); if (scaled_ref_frame) { int i; @@ -2327,473 +1769,53 @@ unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x, 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, - const search_site_config *cfg, - int use_intrabc_mesh_pattern) { - const SPEED_FEATURES *const sf = &cpi->sf; - const aom_variance_fn_ptr_t *fn_ptr = &cpi->fn_ptr[bsize]; - int var = 0; +// ============================================================================= +// Fullpixel Motion Search: OBMC +// ============================================================================= +static INLINE int get_obmc_mvpred_var( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV *this_mv) { + const aom_variance_fn_ptr_t *vfp = ms_params->vfp; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const MSBuffers *ms_buffers = &ms_params->ms_buffers; + const int32_t *wsrc = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const struct buf_2d *ref_buf = ms_buffers->ref; - if (cost_list) { - cost_list[0] = INT_MAX; - cost_list[1] = INT_MAX; - cost_list[2] = INT_MAX; - cost_list[3] = INT_MAX; - cost_list[4] = INT_MAX; - } - - // Keep track of number of searches (this frame in this thread). - if (x->m_search_count_ptr != NULL) ++(*x->m_search_count_ptr); - - switch (method) { - case FAST_DIAMOND: - var = fast_dia_search(x, mvp_full, step_param, error_per_bit, 0, - cost_list, fn_ptr, 1, ref_mv); - break; - case FAST_HEX: - var = fast_hex_search(x, mvp_full, step_param, error_per_bit, 0, - cost_list, fn_ptr, 1, ref_mv); - break; - case HEX: - var = av1_hex_search(x, mvp_full, step_param, error_per_bit, 1, cost_list, - fn_ptr, 1, ref_mv); - break; - case SQUARE: - var = square_search(x, mvp_full, step_param, error_per_bit, 1, cost_list, - fn_ptr, 1, ref_mv); - break; - case BIGDIA: - var = bigdia_search(x, mvp_full, step_param, error_per_bit, 1, cost_list, - fn_ptr, 1, ref_mv); - break; - 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, cfg); - break; - default: assert(0 && "Invalid search method."); - } - - // Should we allow a follow on exhaustive search? - // Pick the threshold for decision on the evaluation of exhaustive search - // based on the toolset (intraBC or non-intraBC) - const int max_exhaustive_pct = use_intrabc_mesh_pattern - ? sf->intrabc_max_exhaustive_pct - : sf->max_exhaustive_pct; - if (!run_mesh_search && method == NSTEP && - is_exhaustive_allowed(cpi, x, max_exhaustive_pct)) { - int exhuastive_thr = sf->exhaustive_searches_thresh; - exhuastive_thr >>= - 10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]); - // Threshold variance for an exhaustive full search. - if (var > exhuastive_thr) run_mesh_search = 1; - } - - if (run_mesh_search) { - int var_ex; - MV tmp_mv_ex; - // Pick the mesh pattern for exhaustive search based on the toolset (intraBC - // or non-intraBC) - const MESH_PATTERN *const mesh_patterns = use_intrabc_mesh_pattern - ? sf->intrabc_mesh_patterns - : sf->mesh_patterns; - var_ex = - full_pixel_exhaustive(x, &x->best_mv.as_mv, error_per_bit, cost_list, - fn_ptr, ref_mv, &tmp_mv_ex, mesh_patterns); - if (var_ex < var) { - var = var_ex; - x->best_mv.as_mv = tmp_mv_ex; - } - } - - if (method != NSTEP && rd && var < var_max) - var = av1_get_mvpred_var(x, &x->best_mv.as_mv, ref_mv, fn_ptr, 1); - - // Use hash-me for intrablock copy - do { - if (!intra || !av1_use_hash_me(&cpi->common)) break; - - // already single ME - // get block size and original buffer of current block - const int block_height = block_size_high[bsize]; - const int block_width = block_size_wide[bsize]; - if (block_height == block_width && x_pos >= 0 && y_pos >= 0) { - if (block_width == 4 || block_width == 8 || block_width == 16 || - block_width == 32 || block_width == 64 || block_width == 128) { - uint8_t *what = x->plane[0].src.buf; - const int what_stride = x->plane[0].src.stride; - uint32_t hash_value1, hash_value2; - MV best_hash_mv; - int best_hash_cost = INT_MAX; - - // for the hashMap - hash_table *ref_frame_hash = &cpi->common.cur_frame->hash_table; - - av1_get_block_hash_value(what, what_stride, block_width, &hash_value1, - &hash_value2, is_cur_buf_hbd(&x->e_mbd), x); - - const int count = av1_hash_table_count(ref_frame_hash, hash_value1); - // for intra, at lest one matching can be found, itself. - if (count <= (intra ? 1 : 0)) { - break; - } - - Iterator iterator = - av1_hash_get_first_iterator(ref_frame_hash, hash_value1); - for (int i = 0; i < count; i++, aom_iterator_increment(&iterator)) { - block_hash ref_block_hash = - *(block_hash *)(aom_iterator_get(&iterator)); - if (hash_value2 == ref_block_hash.hash_value2) { - // For intra, make sure the prediction is from valid area. - if (intra) { - const int mi_col = x_pos / MI_SIZE; - const int mi_row = y_pos / MI_SIZE; - const MV dv = { 8 * (ref_block_hash.y - y_pos), - 8 * (ref_block_hash.x - x_pos) }; - if (!av1_is_dv_valid(dv, &cpi->common, &x->e_mbd, mi_row, mi_col, - bsize, cpi->common.seq_params.mib_size_log2)) - continue; - } - MV hash_mv; - hash_mv.col = ref_block_hash.x - x_pos; - hash_mv.row = ref_block_hash.y - y_pos; - if (!is_mv_in(&x->mv_limits, &hash_mv)) continue; - const int refCost = - av1_get_mvpred_var(x, &hash_mv, ref_mv, fn_ptr, 1); - if (refCost < best_hash_cost) { - best_hash_cost = refCost; - best_hash_mv = hash_mv; - } - } - } - if (best_hash_cost < var) { - x->second_best_mv = x->best_mv; - x->best_mv.as_mv = best_hash_mv; - var = best_hash_cost; - } - } - } - } while (0); - - return var; -} - -/* returns subpixel variance error function */ -#define DIST(r, c) \ - vfp->osvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, mask, &sse) - -/* checks if (r, c) has better score than previous best */ -#define MVC(r, c) \ - (unsigned int)(mvcost \ - ? ((mvjcost[((r) != rr) * 2 + ((c) != rc)] + \ - mvcost[0][((r)-rr)] + (int64_t)mvcost[1][((c)-rc)]) * \ - error_per_bit + \ - 4096) >> \ - 13 \ - : 0) - -#define CHECK_BETTER(v, r, c) \ - if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \ - thismse = (DIST(r, c)); \ - if ((v = MVC(r, c) + thismse) < besterr) { \ - besterr = v; \ - br = r; \ - bc = c; \ - *distortion = thismse; \ - *sse1 = sse; \ - } \ - } else { \ - v = INT_MAX; \ - } - -#undef CHECK_BETTER0 -#define CHECK_BETTER0(v, r, c) CHECK_BETTER(v, r, c) - -#undef CHECK_BETTER1 -#define CHECK_BETTER1(v, r, c) \ - if (c >= minc && c <= maxc && r >= minr && r <= maxr) { \ - MV this_mv = { r, c }; \ - thismse = upsampled_obmc_pref_error(xd, cm, mi_row, mi_col, &this_mv, \ - mask, vfp, z, pre(y, y_stride, r, c), \ - y_stride, sp(c), sp(r), w, h, &sse, \ - use_accurate_subpel_search); \ - v = mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \ - if ((v + thismse) < besterr) { \ - besterr = v + thismse; \ - br = r; \ - bc = c; \ - *distortion = thismse; \ - *sse1 = sse; \ - } \ - } else { \ - v = INT_MAX; \ - } - -static unsigned int setup_obmc_center_error( - const int32_t *mask, const MV *bestmv, const MV *ref_mv, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, const int32_t *const wsrc, - const uint8_t *const y, int y_stride, int offset, int *mvjcost, - int *mvcost[2], unsigned int *sse1, int *distortion) { - unsigned int besterr; - besterr = vfp->ovf(y + offset, y_stride, wsrc, mask, sse1); - *distortion = besterr; - besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit); - return besterr; -} - -static int upsampled_obmc_pref_error( - MACROBLOCKD *xd, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *const mv, const int32_t *mask, const aom_variance_fn_ptr_t *vfp, - const int32_t *const wsrc, const uint8_t *const y, int y_stride, - int subpel_x_q3, int subpel_y_q3, int w, int h, unsigned int *sse, - int subpel_search) { - unsigned int besterr; - - DECLARE_ALIGNED(16, uint8_t, pred[2 * MAX_SB_SQUARE]); -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred); - aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred8, w, h, - subpel_x_q3, subpel_y_q3, y, y_stride, xd->bd, - subpel_search); - besterr = vfp->ovf(pred8, w, wsrc, mask, sse); - } else { - aom_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, subpel_search); - - besterr = vfp->ovf(pred, w, wsrc, mask, sse); - } -#else - aom_upsampled_pred(xd, cm, mi_row, mi_col, mv, pred, w, h, subpel_x_q3, - subpel_y_q3, y, y_stride, subpel_search); - - besterr = vfp->ovf(pred, w, wsrc, mask, sse); -#endif - return besterr; -} - -static unsigned int upsampled_setup_obmc_center_error( - MACROBLOCKD *xd, const AV1_COMMON *const cm, int mi_row, int mi_col, - const int32_t *mask, const MV *bestmv, const MV *ref_mv, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, const int32_t *const wsrc, - const uint8_t *const y, int y_stride, int w, int h, int offset, - int *mvjcost, int *mvcost[2], unsigned int *sse1, int *distortion, - int subpel_search) { - unsigned int besterr = upsampled_obmc_pref_error( - xd, cm, mi_row, mi_col, bestmv, mask, vfp, wsrc, y + offset, y_stride, 0, - 0, w, h, sse1, subpel_search); - *distortion = besterr; - besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit); - return besterr; -} - -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, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *mvjcost, int *mvcost[2], int *distortion, unsigned int *sse1, - int is_second, int use_accurate_subpel_search) { - const int32_t *wsrc = x->wsrc_buf; - const int32_t *mask = x->mask_buf; - const int *const z = wsrc; - const int *const src_address = z; - MACROBLOCKD *xd = &x->e_mbd; - struct macroblockd_plane *const pd = &xd->plane[0]; - MB_MODE_INFO *mbmi = xd->mi[0]; - unsigned int besterr = INT_MAX; - unsigned int sse; - unsigned int thismse; - - int rr = ref_mv->row; - int rc = ref_mv->col; - int br = bestmv->row * 8; - int bc = bestmv->col * 8; - int hstep = 4; - int iter; - int round = 3 - forced_stop; - int tr = br; - int tc = bc; - const MV *search_step = search_step_table; - int idx, best_idx = -1; - unsigned int cost_array[5]; - int kr, kc; - const int w = block_size_wide[mbmi->sb_type]; - const int h = block_size_high[mbmi->sb_type]; - int offset; - int y_stride; - const uint8_t *y; - - int minc, maxc, minr, maxr; - - set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, ref_mv); - - y = pd->pre[is_second].buf; - y_stride = pd->pre[is_second].stride; - offset = bestmv->row * y_stride + bestmv->col; - - if (!allow_hp) - if (round == 3) round = 2; - - bestmv->row *= 8; - bestmv->col *= 8; - // use_accurate_subpel_search can be 0 or 1 or 2 - if (use_accurate_subpel_search) - besterr = upsampled_setup_obmc_center_error( - xd, cm, mi_row, mi_col, mask, bestmv, ref_mv, error_per_bit, vfp, z, y, - y_stride, w, h, offset, mvjcost, mvcost, sse1, distortion, - use_accurate_subpel_search); - else - besterr = setup_obmc_center_error(mask, bestmv, ref_mv, error_per_bit, vfp, - z, y, y_stride, offset, mvjcost, mvcost, - sse1, distortion); - - for (iter = 0; iter < round; ++iter) { - // Check vertical and horizontal sub-pixel positions. - for (idx = 0; idx < 4; ++idx) { - tr = br + search_step[idx].row; - tc = bc + search_step[idx].col; - if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) { - MV this_mv = { tr, tc }; - if (use_accurate_subpel_search) { - thismse = upsampled_obmc_pref_error( - xd, cm, mi_row, mi_col, &this_mv, mask, vfp, src_address, - pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), w, h, &sse, - use_accurate_subpel_search); - } else { - thismse = vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), - sp(tr), src_address, mask, &sse); - } - - cost_array[idx] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost, - mvcost, error_per_bit); - if (cost_array[idx] < besterr) { - best_idx = idx; - besterr = cost_array[idx]; - *distortion = thismse; - *sse1 = sse; - } - } else { - cost_array[idx] = INT_MAX; - } - } - - // Check diagonal sub-pixel position - kc = (cost_array[0] <= cost_array[1] ? -hstep : hstep); - kr = (cost_array[2] <= cost_array[3] ? -hstep : hstep); - - tc = bc + kc; - tr = br + kr; - if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) { - MV this_mv = { tr, tc }; - - if (use_accurate_subpel_search) { - thismse = upsampled_obmc_pref_error( - xd, cm, mi_row, mi_col, &this_mv, mask, vfp, src_address, - pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), w, h, &sse, - use_accurate_subpel_search); - } else { - thismse = vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), - src_address, mask, &sse); - } - - cost_array[4] = thismse + mv_err_cost(&this_mv, ref_mv, mvjcost, mvcost, - error_per_bit); - - if (cost_array[4] < besterr) { - best_idx = 4; - besterr = cost_array[4]; - *distortion = thismse; - *sse1 = sse; - } - } else { - cost_array[idx] = INT_MAX; - } - - if (best_idx < 4 && best_idx >= 0) { - br += search_step[best_idx].row; - bc += search_step[best_idx].col; - } else if (best_idx == 4) { - br = tr; - bc = tc; - } - - if (iters_per_step > 1 && best_idx != -1) { - if (use_accurate_subpel_search) { - SECOND_LEVEL_CHECKS_BEST(1); - } else { - SECOND_LEVEL_CHECKS_BEST(0); - } - } - - tr = br; - tc = bc; - - search_step += 4; - hstep >>= 1; - best_idx = -1; - } - - // These lines insure static analysis doesn't warn that - // tr and tc aren't used after the above point. - (void)tr; - (void)tc; - - bestmv->row = br; - bestmv->col = bc; - - return besterr; -} - -#undef DIST -#undef MVC -#undef CHECK_BETTER - -static int get_obmc_mvpred_var(const MACROBLOCK *x, const int32_t *wsrc, - const int32_t *mask, const MV *best_mv, - const MV *center_mv, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - int is_second) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const in_what = &xd->plane[0].pre[is_second]; - const MV mv = { best_mv->row * 8, best_mv->col * 8 }; + const MV mv = get_mv_from_fullmv(this_mv); unsigned int unused; - return vfp->ovf(get_buf_from_mv(in_what, best_mv), in_what->stride, wsrc, + return vfp->ovf(get_buf_from_fullmv(ref_buf, this_mv), ref_buf->stride, wsrc, mask, &unused) + - (use_mvcost ? mv_err_cost(&mv, center_mv, x->nmv_vec_cost, - x->mv_cost_stack, x->errorperbit) - : 0); + mv_err_cost_(&mv, mv_cost_params); } -static int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc, - const int32_t *mask, MV *ref_mv, - int error_per_bit, int search_range, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv, int is_second) { - const MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } }; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const in_what = &xd->plane[0].pre[is_second]; - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; - unsigned int best_sad = fn_ptr->osdf(get_buf_from_mv(in_what, ref_mv), - in_what->stride, wsrc, mask) + - mvsad_err_cost(x, ref_mv, &fcenter_mv, error_per_bit); - int i, j; +static int obmc_refining_search_sad( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, FULLPEL_MV *best_mv) { + const aom_variance_fn_ptr_t *fn_ptr = ms_params->vfp; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const MSBuffers *ms_buffers = &ms_params->ms_buffers; + const int32_t *wsrc = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const struct buf_2d *ref_buf = ms_buffers->ref; + const FULLPEL_MV neighbors[4] = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } }; + const int kSearchRange = 8; - for (i = 0; i < search_range; i++) { + unsigned int best_sad = fn_ptr->osdf(get_buf_from_fullmv(ref_buf, best_mv), + ref_buf->stride, wsrc, mask) + + mvsad_err_cost_(best_mv, mv_cost_params); + + for (int i = 0; i < kSearchRange; i++) { int best_site = -1; - for (j = 0; j < 4; j++) { - const MV mv = { ref_mv->row + neighbors[j].row, - ref_mv->col + neighbors[j].col }; - if (is_mv_in(&x->mv_limits, &mv)) { - unsigned int sad = fn_ptr->osdf(get_buf_from_mv(in_what, &mv), - in_what->stride, wsrc, mask); + for (int j = 0; j < 4; j++) { + const FULLPEL_MV mv = { best_mv->row + neighbors[j].row, + best_mv->col + neighbors[j].col }; + if (av1_is_fullmv_in_range(&ms_params->mv_limits, mv)) { + unsigned int sad = fn_ptr->osdf(get_buf_from_fullmv(ref_buf, &mv), + ref_buf->stride, wsrc, mask); if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit); + sad += mvsad_err_cost_(&mv, mv_cost_params); + if (sad < best_sad) { best_sad = sad; best_site = j; @@ -2805,121 +1827,88 @@ static int obmc_refining_search_sad(const MACROBLOCK *x, const int32_t *wsrc, if (best_site == -1) { break; } else { - ref_mv->row += neighbors[best_site].row; - ref_mv->col += neighbors[best_site].col; + best_mv->row += neighbors[best_site].row; + best_mv->col += neighbors[best_site].col; } } return best_sad; } -static int obmc_diamond_search_sad(const MACROBLOCK *x, - const search_site_config *cfg, - const int32_t *wsrc, const int32_t *mask, - MV *ref_mv, MV *best_mv, int search_param, - int sad_per_bit, int *num00, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv, int is_second) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const in_what = &xd->plane[0].pre[is_second]; +static int obmc_diamond_search_sad( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, FULLPEL_MV start_mv, + FULLPEL_MV *best_mv, int search_param, int *num00) { + const aom_variance_fn_ptr_t *fn_ptr = ms_params->vfp; + const search_site_config *cfg = ms_params->search_sites; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const MSBuffers *ms_buffers = &ms_params->ms_buffers; + const int32_t *wsrc = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const struct buf_2d *const ref_buf = ms_buffers->ref; // search_param determines the length of the initial step and hence the number // of iterations // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 = // (MAX_FIRST_STEP/4) pel... etc. - const search_site *const ss = &cfg->ss[search_param * cfg->searches_per_step]; - const int tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param; - const MV fcenter_mv = { center_mv->row >> 3, center_mv->col >> 3 }; - const uint8_t *best_address, *in_what_ref; + + const int tot_steps = MAX_MVSEARCH_STEPS - 1 - search_param; + const uint8_t *best_address, *init_ref; int best_sad = INT_MAX; int best_site = 0; - int last_site = 0; - int i, j, step; + int step; - clamp_mv(ref_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - in_what_ref = in_what->buf + ref_mv->row * in_what->stride + ref_mv->col; - best_address = in_what_ref; + clamp_fullmv(&start_mv, &ms_params->mv_limits); + best_address = init_ref = get_buf_from_fullmv(ref_buf, &start_mv); *num00 = 0; - *best_mv = *ref_mv; + *best_mv = start_mv; // Check the starting position - best_sad = fn_ptr->osdf(best_address, in_what->stride, wsrc, mask) + - mvsad_err_cost(x, best_mv, &fcenter_mv, sad_per_bit); + best_sad = fn_ptr->osdf(best_address, ref_buf->stride, wsrc, mask) + + mvsad_err_cost_(best_mv, mv_cost_params); - i = 1; - - for (step = 0; step < tot_steps; step++) { - for (j = 0; j < cfg->searches_per_step; j++) { - const MV mv = { best_mv->row + ss[i].mv.row, - best_mv->col + ss[i].mv.col }; - if (is_mv_in(&x->mv_limits, &mv)) { - int sad = fn_ptr->osdf(best_address + ss[i].offset, in_what->stride, + for (step = tot_steps; step >= 0; --step) { + const search_site *const ss = cfg->ss[step]; + best_site = 0; + for (int idx = 1; idx <= cfg->searches_per_step[step]; ++idx) { + const FULLPEL_MV mv = { best_mv->row + ss[idx].mv.row, + best_mv->col + ss[idx].mv.col }; + if (av1_is_fullmv_in_range(&ms_params->mv_limits, mv)) { + int sad = fn_ptr->osdf(best_address + ss[idx].offset, ref_buf->stride, wsrc, mask); if (sad < best_sad) { - sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit); + sad += mvsad_err_cost_(&mv, mv_cost_params); + if (sad < best_sad) { best_sad = sad; - best_site = i; + best_site = idx; } } } - - i++; } - if (best_site != last_site) { + if (best_site != 0) { best_mv->row += ss[best_site].mv.row; best_mv->col += ss[best_site].mv.col; best_address += ss[best_site].offset; - last_site = best_site; -#if defined(NEW_DIAMOND_SEARCH) - while (1) { - const MV this_mv = { best_mv->row + ss[best_site].mv.row, - best_mv->col + ss[best_site].mv.col }; - if (is_mv_in(&x->mv_limits, &this_mv)) { - int sad = fn_ptr->osdf(best_address + ss[best_site].offset, - in_what->stride, wsrc, mask); - if (sad < best_sad) { - sad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit); - if (sad < best_sad) { - best_sad = sad; - best_mv->row += ss[best_site].mv.row; - best_mv->col += ss[best_site].mv.col; - best_address += ss[best_site].offset; - continue; - } - } - } - break; - } -#endif - } else if (best_address == in_what_ref) { + } else if (best_address == init_ref) { (*num00)++; } } return best_sad; } -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 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; +static int obmc_full_pixel_diamond( + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const FULLPEL_MV start_mv, + int step_param, int do_refine, FULLPEL_MV *best_mv) { + const search_site_config *cfg = ms_params->search_sites; + FULLPEL_MV tmp_mv; int thissme, n, num00 = 0; int bestsme = - 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, - is_second); - *dst_mv = temp_mv; + obmc_diamond_search_sad(ms_params, start_mv, &tmp_mv, step_param, &n); + if (bestsme < INT_MAX) bestsme = get_obmc_mvpred_var(ms_params, &tmp_mv); + *best_mv = tmp_mv; // If there won't be more n-step search, check to see if refining search is // needed. + const int further_steps = cfg->ss_count - 1 - step_param; if (n > further_steps) do_refine = 0; while (n < further_steps) { @@ -2928,271 +1917,1475 @@ static int obmc_full_pixel_diamond(const AV1_COMP *cpi, MACROBLOCK *x, if (num00) { num00--; } else { - 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); + thissme = obmc_diamond_search_sad(ms_params, start_mv, &tmp_mv, + step_param + n, &num00); + if (thissme < INT_MAX) thissme = get_obmc_mvpred_var(ms_params, &tmp_mv); // check to see if refining search is needed. if (num00 > further_steps - n) do_refine = 0; if (thissme < bestsme) { bestsme = thissme; - *dst_mv = temp_mv; + *best_mv = tmp_mv; } } } // final 1-away diamond refining search if (do_refine) { - const int search_range = 8; - MV best_mv = *dst_mv; - thissme = obmc_refining_search_sad(x, wsrc, mask, &best_mv, sadpb, - search_range, fn_ptr, ref_mv, is_second); - if (thissme < INT_MAX) - thissme = get_obmc_mvpred_var(x, wsrc, mask, &best_mv, ref_mv, fn_ptr, 1, - is_second); + tmp_mv = *best_mv; + thissme = obmc_refining_search_sad(ms_params, &tmp_mv); + if (thissme < INT_MAX) thissme = get_obmc_mvpred_var(ms_params, &tmp_mv); if (thissme < bestsme) { bestsme = thissme; - *dst_mv = best_mv; + *best_mv = tmp_mv; } } return bestsme; } -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 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, cfg); +int av1_obmc_full_pixel_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int step_param, FULLPEL_MV *best_mv) { + if (!ms_params->fast_obmc_search) { + const int do_refine = 1; + const int bestsme = obmc_full_pixel_diamond(ms_params, start_mv, step_param, + do_refine, best_mv); + return bestsme; } else { - const int32_t *wsrc = x->wsrc_buf; - const int32_t *mask = x->mask_buf; - const int search_range = 8; - *dst_mv = *mvp_full; - clamp_mv(dst_mv, x->mv_limits.col_min, x->mv_limits.col_max, - x->mv_limits.row_min, x->mv_limits.row_max); - int thissme = obmc_refining_search_sad( - x, wsrc, mask, dst_mv, sadpb, search_range, fn_ptr, ref_mv, is_second); - if (thissme < INT_MAX) - thissme = get_obmc_mvpred_var(x, wsrc, mask, dst_mv, ref_mv, fn_ptr, 1, - is_second); + *best_mv = start_mv; + clamp_fullmv(best_mv, &ms_params->mv_limits); + int thissme = obmc_refining_search_sad(ms_params, best_mv); + if (thissme < INT_MAX) thissme = get_obmc_mvpred_var(ms_params, best_mv); return thissme; } } +// ============================================================================= +// Subpixel Motion Search: Translational +// ============================================================================= +#define INIT_SUBPEL_STEP_SIZE (4) +/* + * To avoid the penalty for crossing cache-line read, preload the reference + * area in a small buffer, which is aligned to make sure there won't be crossing + * cache-line read while reading from this buffer. This reduced the cpu + * cycles spent on reading ref data in sub-pixel filter functions. + * TODO: Currently, since sub-pixel search range here is -3 ~ 3, copy 22 rows x + * 32 cols area that is enough for 16x16 macroblock. Later, for SPLITMV, we + * could reduce the area. + */ + +// Returns the subpel offset used by various subpel variance functions [m]sv[a]f +static INLINE int get_subpel_part(int x) { return x & 7; } + +// Gets the address of the ref buffer at subpel location (r, c), rounded to the +// nearest fullpel precision toward - \infty + +static INLINE const uint8_t *get_buf_from_mv(const struct buf_2d *buf, + const MV mv) { + const int offset = (mv.row >> 3) * buf->stride + (mv.col >> 3); + return &buf->buf[offset]; +} + +// Estimates the variance of prediction residue using bilinear filter for fast +// search. +static INLINE int estimated_pref_error( + const MV *this_mv, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + unsigned int *sse) { + const aom_variance_fn_ptr_t *vfp = var_params->vfp; + + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const uint8_t *src = ms_buffers->src->buf; + const uint8_t *ref = get_buf_from_mv(ms_buffers->ref, *this_mv); + const int src_stride = ms_buffers->src->stride; + const int ref_stride = ms_buffers->ref->stride; + const uint8_t *second_pred = ms_buffers->second_pred; + const uint8_t *mask = ms_buffers->mask; + const int mask_stride = ms_buffers->mask_stride; + const int invert_mask = ms_buffers->inv_mask; + + const int subpel_x_q3 = get_subpel_part(this_mv->col); + const int subpel_y_q3 = get_subpel_part(this_mv->row); + + if (second_pred == NULL) { + return vfp->svf(ref, ref_stride, subpel_x_q3, subpel_y_q3, src, src_stride, + sse); + } else if (mask) { + return vfp->msvf(ref, ref_stride, subpel_x_q3, subpel_y_q3, src, src_stride, + second_pred, mask, mask_stride, invert_mask, sse); + } else { + return vfp->svaf(ref, ref_stride, subpel_x_q3, subpel_y_q3, src, src_stride, + sse, second_pred); + } +} + +// Calculates the variance of prediction residue. +static int upsampled_pref_error(MACROBLOCKD *xd, const AV1_COMMON *cm, + const MV *this_mv, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + unsigned int *sse) { + const aom_variance_fn_ptr_t *vfp = var_params->vfp; + const SUBPEL_SEARCH_TYPE subpel_search_type = var_params->subpel_search_type; + + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const uint8_t *src = ms_buffers->src->buf; + const uint8_t *ref = get_buf_from_mv(ms_buffers->ref, *this_mv); + const int src_stride = ms_buffers->src->stride; + const int ref_stride = ms_buffers->ref->stride; + const uint8_t *second_pred = ms_buffers->second_pred; + const uint8_t *mask = ms_buffers->mask; + const int mask_stride = ms_buffers->mask_stride; + const int invert_mask = ms_buffers->inv_mask; + const int w = var_params->w; + const int h = var_params->h; + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int subpel_x_q3 = get_subpel_part(this_mv->col); + const int subpel_y_q3 = get_subpel_part(this_mv->row); + + unsigned int besterr; +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + DECLARE_ALIGNED(16, uint16_t, pred16[MAX_SB_SQUARE]); + uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred16); + if (second_pred != NULL) { + if (mask) { + aom_highbd_comp_mask_upsampled_pred( + xd, cm, mi_row, mi_col, this_mv, pred8, second_pred, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, mask, mask_stride, + invert_mask, xd->bd, subpel_search_type); + } else { + aom_highbd_comp_avg_upsampled_pred( + xd, cm, mi_row, mi_col, this_mv, pred8, second_pred, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, xd->bd, + subpel_search_type); + } + } else { + aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred8, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, + xd->bd, subpel_search_type); + } + besterr = vfp->vf(pred8, w, src, src_stride, sse); + } else { + DECLARE_ALIGNED(16, uint8_t, pred[MAX_SB_SQUARE]); + if (second_pred != NULL) { + if (mask) { + aom_comp_mask_upsampled_pred( + xd, cm, mi_row, mi_col, this_mv, pred, second_pred, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, mask, mask_stride, + invert_mask, subpel_search_type); + } else { + aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, + second_pred, w, h, subpel_x_q3, subpel_y_q3, + ref, ref_stride, subpel_search_type); + } + } else { + aom_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, + subpel_search_type); + } + + besterr = vfp->vf(pred, w, src, src_stride, sse); + } +#else + DECLARE_ALIGNED(16, uint8_t, pred[MAX_SB_SQUARE]); + if (second_pred != NULL) { + if (mask) { + aom_comp_mask_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, + second_pred, w, h, subpel_x_q3, subpel_y_q3, + ref, ref_stride, mask, mask_stride, + invert_mask, subpel_search_type); + } else { + aom_comp_avg_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, + second_pred, w, h, subpel_x_q3, subpel_y_q3, + ref, ref_stride, subpel_search_type); + } + } else { + aom_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, w, h, subpel_x_q3, + subpel_y_q3, ref, ref_stride, subpel_search_type); + } + + besterr = vfp->vf(pred, w, src, src_stride, sse); +#endif + return besterr; +} + +// Estimates whether this_mv is better than best_mv. This function incorporates +// both prediction error and residue into account. It is suffixed "fast" because +// it uses bilinear filter to estimate the prediction. +static INLINE unsigned int check_better_fast( + const MV *this_mv, MV *best_mv, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion, int *has_better_mv) { + unsigned int cost; + if (av1_is_subpelmv_in_range(mv_limits, *this_mv)) { + unsigned int sse; + int thismse = estimated_pref_error(this_mv, var_params, &sse); + cost = mv_err_cost_(this_mv, mv_cost_params); + cost += thismse; + + if (cost < *besterr) { + *besterr = cost; + *best_mv = *this_mv; + *distortion = thismse; + *sse1 = sse; + *has_better_mv |= 1; + } + } else { + cost = INT_MAX; + } + return cost; +} + +// Checks whether this_mv is better than best_mv. This function incorporates +// both prediction error and residue into account. +static AOM_FORCE_INLINE unsigned int check_better( + MACROBLOCKD *xd, const AV1_COMMON *cm, const MV *this_mv, MV *best_mv, + const SubpelMvLimits *mv_limits, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion, int *is_better) { + unsigned int cost; + if (av1_is_subpelmv_in_range(mv_limits, *this_mv)) { + unsigned int sse; + int thismse; + thismse = upsampled_pref_error(xd, cm, this_mv, var_params, &sse); + cost = mv_err_cost_(this_mv, mv_cost_params); + cost += thismse; + if (cost < *besterr) { + *besterr = cost; + *best_mv = *this_mv; + *distortion = thismse; + *sse1 = sse; + *is_better |= 1; + } + } else { + cost = INT_MAX; + } + return cost; +} + +static INLINE MV get_best_diag_step(int step_size, unsigned int left_cost, + unsigned int right_cost, + unsigned int up_cost, + unsigned int down_cost) { + const MV diag_step = { up_cost <= down_cost ? -step_size : step_size, + left_cost <= right_cost ? -step_size : step_size }; + + return diag_step; +} + +// Searches the four cardinal direction for a better mv, then follows up with a +// search in the best quadrant. This uses bilinear filter to speed up the +// calculation. +static AOM_FORCE_INLINE MV first_level_check_fast( + const MV this_mv, MV *best_mv, int hstep, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + // Check the four cardinal directions + const MV left_mv = { this_mv.row, this_mv.col - hstep }; + int dummy = 0; + const unsigned int left = + check_better_fast(&left_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + const MV right_mv = { this_mv.row, this_mv.col + hstep }; + const unsigned int right = + check_better_fast(&right_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + const MV top_mv = { this_mv.row - hstep, this_mv.col }; + const unsigned int up = + check_better_fast(&top_mv, best_mv, mv_limits, var_params, mv_cost_params, + besterr, sse1, distortion, &dummy); + + const MV bottom_mv = { this_mv.row + hstep, this_mv.col }; + const unsigned int down = + check_better_fast(&bottom_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + const MV diag_step = get_best_diag_step(hstep, left, right, up, down); + const MV diag_mv = { this_mv.row + diag_step.row, + this_mv.col + diag_step.col }; + + // Check the diagonal direction with the best mv + check_better_fast(&diag_mv, best_mv, mv_limits, var_params, mv_cost_params, + besterr, sse1, distortion, &dummy); + + return diag_step; +} + +// Performs a following up search after first_level_check_fast is called. This +// performs two extra chess pattern searches in the best quadrant. +static AOM_FORCE_INLINE void second_level_check_fast( + const MV this_mv, const MV diag_step, MV *best_mv, int hstep, + const SubpelMvLimits *mv_limits, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + assert(diag_step.row == hstep || diag_step.row == -hstep); + assert(diag_step.col == hstep || diag_step.col == -hstep); + const int tr = this_mv.row; + const int tc = this_mv.col; + const int br = best_mv->row; + const int bc = best_mv->col; + int dummy = 0; + if (tr != br && tc != bc) { + assert(diag_step.col == bc - tc); + assert(diag_step.row == br - tr); + const MV chess_mv_1 = { br, bc + diag_step.col }; + const MV chess_mv_2 = { br + diag_step.row, bc }; + check_better_fast(&chess_mv_1, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + check_better_fast(&chess_mv_2, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + } else if (tr == br && tc != bc) { + assert(diag_step.col == bc - tc); + // Continue searching in the best direction + const MV bottom_long_mv = { br + hstep, bc + diag_step.col }; + const MV top_long_mv = { br - hstep, bc + diag_step.col }; + check_better_fast(&bottom_long_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + check_better_fast(&top_long_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + // Search in the direction opposite of the best quadrant + const MV rev_mv = { br - diag_step.row, bc }; + check_better_fast(&rev_mv, best_mv, mv_limits, var_params, mv_cost_params, + besterr, sse1, distortion, &dummy); + } else if (tr != br && tc == bc) { + assert(diag_step.row == br - tr); + // Continue searching in the best direction + const MV right_long_mv = { br + diag_step.row, bc + hstep }; + const MV left_long_mv = { br + diag_step.row, bc - hstep }; + check_better_fast(&right_long_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + check_better_fast(&left_long_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + // Search in the direction opposite of the best quadrant + const MV rev_mv = { br, bc - diag_step.col }; + check_better_fast(&rev_mv, best_mv, mv_limits, var_params, mv_cost_params, + besterr, sse1, distortion, &dummy); + } +} + +// Combines first level check and second level check when applicable. This first +// searches the four cardinal directions, and perform several +// diagonal/chess-pattern searches in the best quadrant. +static AOM_FORCE_INLINE void two_level_checks_fast( + const MV this_mv, MV *best_mv, int hstep, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion, int iters) { + const MV diag_step = + first_level_check_fast(this_mv, best_mv, hstep, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion); + if (iters > 1) { + second_level_check_fast(this_mv, diag_step, best_mv, hstep, mv_limits, + var_params, mv_cost_params, besterr, sse1, + distortion); + } +} + +static AOM_FORCE_INLINE MV +first_level_check(MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV this_mv, + MV *best_mv, const int hstep, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + int dummy = 0; + const MV left_mv = { this_mv.row, this_mv.col - hstep }; + const MV right_mv = { this_mv.row, this_mv.col + hstep }; + const MV top_mv = { this_mv.row - hstep, this_mv.col }; + const MV bottom_mv = { this_mv.row + hstep, this_mv.col }; + + const unsigned int left = + check_better(xd, cm, &left_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int right = + check_better(xd, cm, &right_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int up = + check_better(xd, cm, &top_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int down = + check_better(xd, cm, &bottom_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + const MV diag_step = get_best_diag_step(hstep, left, right, up, down); + const MV diag_mv = { this_mv.row + diag_step.row, + this_mv.col + diag_step.col }; + + // Check the diagonal direction with the best mv + check_better(xd, cm, &diag_mv, best_mv, mv_limits, var_params, mv_cost_params, + besterr, sse1, distortion, &dummy); + + return diag_step; +} + +// A newer version of second level check that gives better quality. +// TODO(chiyotsai@google.com): evaluate this on subpel_search_types different +// from av1_find_best_sub_pixel_tree +static AOM_FORCE_INLINE void second_level_check_v2( + MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV this_mv, MV diag_step, + MV *best_mv, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + assert(best_mv->row == this_mv.row + diag_step.row || + best_mv->col == this_mv.col + diag_step.col); + if (CHECK_MV_EQUAL(this_mv, *best_mv)) { + return; + } else if (this_mv.row == best_mv->row) { + // Search away from diagonal step since diagonal search did not provide any + // improvement + diag_step.row *= -1; + } else if (this_mv.col == best_mv->col) { + diag_step.col *= -1; + } + + const MV row_bias_mv = { best_mv->row + diag_step.row, best_mv->col }; + const MV col_bias_mv = { best_mv->row, best_mv->col + diag_step.col }; + const MV diag_bias_mv = { best_mv->row + diag_step.row, + best_mv->col + diag_step.col }; + int has_better_mv = 0; + + if (var_params->subpel_search_type != USE_2_TAPS_ORIG) { + check_better(xd, cm, &row_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &has_better_mv); + check_better(xd, cm, &col_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &has_better_mv); + + // Do an additional search if the second iteration gives a better mv + if (has_better_mv) { + check_better(xd, cm, &diag_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &has_better_mv); + } + } else { + check_better_fast(&row_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + check_better_fast(&col_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + + // Do an additional search if the second iteration gives a better mv + if (has_better_mv) { + check_better_fast(&diag_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + } + } +} + +// Gets the error at the beginning when the mv has fullpel precision +static unsigned int setup_center_error( + const MACROBLOCKD *xd, const MV *bestmv, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *sse1, int *distortion) { + const aom_variance_fn_ptr_t *vfp = var_params->vfp; + const int w = var_params->w; + const int h = var_params->h; + + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const uint8_t *src = ms_buffers->src->buf; + const uint8_t *y = get_buf_from_mv(ms_buffers->ref, *bestmv); + const int src_stride = ms_buffers->src->stride; + const int y_stride = ms_buffers->ref->stride; + const uint8_t *second_pred = ms_buffers->second_pred; + const uint8_t *mask = ms_buffers->mask; + const int mask_stride = ms_buffers->mask_stride; + const int invert_mask = ms_buffers->inv_mask; + + unsigned int besterr; + + if (second_pred != NULL) { +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + DECLARE_ALIGNED(16, uint16_t, comp_pred16[MAX_SB_SQUARE]); + uint8_t *comp_pred = CONVERT_TO_BYTEPTR(comp_pred16); + if (mask) { + aom_highbd_comp_mask_pred(comp_pred, second_pred, w, h, y, y_stride, + mask, mask_stride, invert_mask); + } else { + aom_highbd_comp_avg_pred(comp_pred, second_pred, w, h, y, y_stride); + } + besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); + } else { + DECLARE_ALIGNED(16, uint8_t, comp_pred[MAX_SB_SQUARE]); + if (mask) { + aom_comp_mask_pred(comp_pred, second_pred, w, h, y, y_stride, mask, + mask_stride, invert_mask); + } else { + aom_comp_avg_pred(comp_pred, second_pred, w, h, y, y_stride); + } + besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); + } +#else + (void)xd; + DECLARE_ALIGNED(16, uint8_t, comp_pred[MAX_SB_SQUARE]); + if (mask) { + aom_comp_mask_pred(comp_pred, second_pred, w, h, y, y_stride, mask, + mask_stride, invert_mask); + } else { + aom_comp_avg_pred(comp_pred, second_pred, w, h, y, y_stride); + } + besterr = vfp->vf(comp_pred, w, src, src_stride, sse1); +#endif + } else { + besterr = vfp->vf(y, y_stride, src, src_stride, sse1); + } + *distortion = besterr; + besterr += mv_err_cost_(bestmv, mv_cost_params); + return besterr; +} + +// Gets the error at the beginning when the mv has fullpel precision +static unsigned int upsampled_setup_center_error( + MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV *bestmv, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *sse1, int *distortion) { + unsigned int besterr = upsampled_pref_error(xd, cm, bestmv, var_params, sse1); + *distortion = besterr; + besterr += mv_err_cost_(bestmv, mv_cost_params); + return besterr; +} + +static INLINE int divide_and_round(int n, int d) { + return ((n < 0) ^ (d < 0)) ? ((n - d / 2) / d) : ((n + d / 2) / d); +} + +static INLINE int is_cost_list_wellbehaved(const int *cost_list) { + return cost_list[0] < cost_list[1] && cost_list[0] < cost_list[2] && + cost_list[0] < cost_list[3] && cost_list[0] < cost_list[4]; +} + +// Returns surface minima estimate at given precision in 1/2^n bits. +// Assume a model for the cost surface: S = A(x - x0)^2 + B(y - y0)^2 + C +// For a given set of costs S0, S1, S2, S3, S4 at points +// (y, x) = (0, 0), (0, -1), (1, 0), (0, 1) and (-1, 0) respectively, +// the solution for the location of the minima (x0, y0) is given by: +// x0 = 1/2 (S1 - S3)/(S1 + S3 - 2*S0), +// y0 = 1/2 (S4 - S2)/(S4 + S2 - 2*S0). +// The code below is an integerized version of that. +static AOM_INLINE void get_cost_surf_min(const int *cost_list, int *ir, int *ic, + int bits) { + *ic = divide_and_round((cost_list[1] - cost_list[3]) * (1 << (bits - 1)), + (cost_list[1] - 2 * cost_list[0] + cost_list[3])); + *ir = divide_and_round((cost_list[4] - cost_list[2]) * (1 << (bits - 1)), + (cost_list[4] - 2 * cost_list[0] + cost_list[2])); +} + +// Checks the list of mvs searched in the last iteration and see if we are +// repeating it. If so, return 1. Otherwise we update the last_mv_search_list +// with current_mv and return 0. +static INLINE int check_repeated_mv_and_update(int_mv *last_mv_search_list, + const MV current_mv, int iter) { + if (last_mv_search_list) { + if (CHECK_MV_EQUAL(last_mv_search_list[iter].as_mv, current_mv)) { + return 1; + } + + last_mv_search_list[iter].as_mv = current_mv; + } + return 0; +} + +int av1_find_best_sub_pixel_tree_pruned_evenmore( + MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV start_mv, MV *bestmv, + int *distortion, unsigned int *sse1, int_mv *last_mv_search_list) { + (void)cm; + const int allow_hp = ms_params->allow_hp; + const int forced_stop = ms_params->forced_stop; + const int iters_per_step = ms_params->iters_per_step; + const int *cost_list = ms_params->cost_list; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + + // The iteration we are current searching for. Iter 0 corresponds to fullpel + // mv, iter 1 to half pel, and so on + int iter = 0; + int hstep = INIT_SUBPEL_STEP_SIZE; // Step size, initialized to 4/8=1/2 pel + unsigned int besterr = INT_MAX; + *bestmv = start_mv; + + besterr = setup_center_error(xd, bestmv, var_params, mv_cost_params, sse1, + distortion); + + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && + cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && + cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) { + int ir, ic; + int dummy = 0; + get_cost_surf_min(cost_list, &ir, &ic, 2); + if (ir != 0 || ic != 0) { + const MV this_mv = { start_mv.row + 2 * ir, start_mv.col + 2 * ic }; + check_better_fast(&this_mv, bestmv, mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion, &dummy); + } + } else { + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + + // Each subsequent iteration checks at least one point in common with + // the last iteration could be 2 ( if diag selected) 1/4 pel + if (forced_stop != HALF_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + } + + if (allow_hp && forced_stop == EIGHTH_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + return besterr; +} + +int av1_find_best_sub_pixel_tree_pruned_more( + MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV start_mv, MV *bestmv, + int *distortion, unsigned int *sse1, int_mv *last_mv_search_list) { + (void)cm; + const int allow_hp = ms_params->allow_hp; + const int forced_stop = ms_params->forced_stop; + const int iters_per_step = ms_params->iters_per_step; + const int *cost_list = ms_params->cost_list; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + + // The iteration we are current searching for. Iter 0 corresponds to fullpel + // mv, iter 1 to half pel, and so on + int iter = 0; + int hstep = INIT_SUBPEL_STEP_SIZE; // Step size, initialized to 4/8=1/2 pel + unsigned int besterr = INT_MAX; + *bestmv = start_mv; + + besterr = setup_center_error(xd, bestmv, var_params, mv_cost_params, sse1, + distortion); + + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && + cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && + cost_list[4] != INT_MAX && is_cost_list_wellbehaved(cost_list)) { + int ir, ic; + get_cost_surf_min(cost_list, &ir, &ic, 1); + if (ir != 0 || ic != 0) { + const MV this_mv = { start_mv.row + ir * hstep, + start_mv.col + ic * hstep }; + int dummy = 0; + check_better_fast(&this_mv, bestmv, mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion, &dummy); + } + } else { + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + // Each subsequent iteration checks at least one point in common with + // the last iteration could be 2 ( if diag selected) 1/4 pel + if (forced_stop != HALF_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + if (allow_hp && forced_stop == EIGHTH_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + return besterr; +} + +int av1_find_best_sub_pixel_tree_pruned( + MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV start_mv, MV *bestmv, + int *distortion, unsigned int *sse1, int_mv *last_mv_search_list) { + (void)cm; + const int allow_hp = ms_params->allow_hp; + const int forced_stop = ms_params->forced_stop; + const int iters_per_step = ms_params->iters_per_step; + const int *cost_list = ms_params->cost_list; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + + // The iteration we are current searching for. Iter 0 corresponds to fullpel + // mv, iter 1 to half pel, and so on + int iter = 0; + int hstep = INIT_SUBPEL_STEP_SIZE; // Step size, initialized to 4/8=1/2 pel + unsigned int besterr = INT_MAX; + *bestmv = start_mv; + + besterr = setup_center_error(xd, bestmv, var_params, mv_cost_params, sse1, + distortion); + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + if (cost_list && cost_list[0] != INT_MAX && cost_list[1] != INT_MAX && + cost_list[2] != INT_MAX && cost_list[3] != INT_MAX && + cost_list[4] != INT_MAX) { + const unsigned int whichdir = (cost_list[1] < cost_list[3] ? 0 : 1) + + (cost_list[2] < cost_list[4] ? 0 : 2); + + const MV left_mv = { start_mv.row, start_mv.col - hstep }; + const MV right_mv = { start_mv.row, start_mv.col + hstep }; + const MV bottom_mv = { start_mv.row + hstep, start_mv.col }; + const MV top_mv = { start_mv.row - hstep, start_mv.col }; + + const MV bottom_left_mv = { start_mv.row + hstep, start_mv.col - hstep }; + const MV bottom_right_mv = { start_mv.row + hstep, start_mv.col + hstep }; + const MV top_left_mv = { start_mv.row - hstep, start_mv.col - hstep }; + const MV top_right_mv = { start_mv.row - hstep, start_mv.col + hstep }; + + int dummy = 0; + + switch (whichdir) { + case 0: // bottom left quadrant + check_better_fast(&left_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&bottom_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&bottom_left_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + break; + case 1: // bottom right quadrant + check_better_fast(&right_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&bottom_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&bottom_right_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + break; + case 2: // top left quadrant + check_better_fast(&left_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&top_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&top_left_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + break; + case 3: // top right quadrant + check_better_fast(&right_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&top_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + check_better_fast(&top_right_mv, bestmv, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, &dummy); + break; + } + } else { + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + // Each subsequent iteration checks at least one point in common with + // the last iteration could be 2 ( if diag selected) 1/4 pel + if (forced_stop != HALF_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + if (allow_hp && forced_stop == EIGHTH_PEL) { + if (check_repeated_mv_and_update(last_mv_search_list, *bestmv, iter)) { + return INT_MAX; + } + iter++; + + hstep >>= 1; + start_mv = *bestmv; + two_level_checks_fast(start_mv, bestmv, hstep, mv_limits, var_params, + mv_cost_params, &besterr, sse1, distortion, + iters_per_step); + } + + return besterr; +} + +int av1_find_best_sub_pixel_tree(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + MV start_mv, MV *bestmv, int *distortion, + unsigned int *sse1, + int_mv *last_mv_search_list) { + const int allow_hp = ms_params->allow_hp; + const int forced_stop = ms_params->forced_stop; + const int iters_per_step = ms_params->iters_per_step; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + const SUBPEL_SEARCH_TYPE subpel_search_type = + ms_params->var_params.subpel_search_type; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + + // How many steps to take. A round of 0 means fullpel search only, 1 means + // half-pel, and so on. + const int round = AOMMIN(FULL_PEL - forced_stop, 3 - !allow_hp); + int hstep = INIT_SUBPEL_STEP_SIZE; // Step size, initialized to 4/8=1/2 pel + + unsigned int besterr = INT_MAX; + + *bestmv = start_mv; + + if (subpel_search_type != USE_2_TAPS_ORIG) { + besterr = upsampled_setup_center_error(xd, cm, bestmv, var_params, + mv_cost_params, sse1, distortion); + } else { + besterr = setup_center_error(xd, bestmv, var_params, mv_cost_params, sse1, + distortion); + } + + for (int iter = 0; iter < round; ++iter) { + MV iter_center_mv = *bestmv; + if (check_repeated_mv_and_update(last_mv_search_list, iter_center_mv, + iter)) { + return INT_MAX; + } + + MV diag_step; + if (subpel_search_type != USE_2_TAPS_ORIG) { + diag_step = first_level_check(xd, cm, iter_center_mv, bestmv, hstep, + mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion); + } else { + diag_step = first_level_check_fast(iter_center_mv, bestmv, hstep, + mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion); + } + + // Check diagonal sub-pixel position + if (!CHECK_MV_EQUAL(iter_center_mv, *bestmv) && iters_per_step > 1) { + second_level_check_v2(xd, cm, iter_center_mv, diag_step, bestmv, + mv_limits, var_params, mv_cost_params, &besterr, + sse1, distortion); + } + + hstep >>= 1; + } + + return besterr; +} + // Note(yunqingwang): The following 2 functions are only used in the motion // vector unit test, which return extreme motion vectors allowed by the MV // limits. -#define COMMON_MV_TEST \ - SETUP_SUBPEL_SEARCH; \ - \ - (void)error_per_bit; \ - (void)vfp; \ - (void)src_address; \ - (void)src_stride; \ - (void)y; \ - (void)y_stride; \ - (void)second_pred; \ - (void)w; \ - (void)h; \ - (void)use_accurate_subpel_search; \ - (void)offset; \ - (void)mvjcost; \ - (void)mvcost; \ - (void)sse1; \ - (void)distortion; \ - \ - (void)halfiters; \ - (void)quarteriters; \ - (void)eighthiters; \ - (void)whichdir; \ - (void)forced_stop; \ - (void)hstep; \ - \ - (void)tr; \ - (void)tc; \ - (void)sse; \ - (void)thismse; \ - (void)cost_list; -// Return the maximum MV. -int av1_return_max_sub_pixel_mv( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - COMMON_MV_TEST; - (void)mask; - (void)mask_stride; - (void)invert_mask; - (void)minr; - (void)minc; - +// Returns the maximum MV. +int av1_return_max_sub_pixel_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + MV start_mv, MV *bestmv, int *distortion, + unsigned int *sse1, + int_mv *last_mv_search_list) { + (void)xd; (void)cm; - (void)mi_row; - (void)mi_col; - (void)do_reset_fractional_mv; + (void)start_mv; + (void)sse1; + (void)distortion; + (void)last_mv_search_list; - bestmv->row = maxr; - bestmv->col = maxc; - besterr = 0; - // In the sub-pel motion search, if hp is not used, then the last bit of mv - // has to be 0. - lower_mv_precision(bestmv, allow_hp, 0); - return besterr; -} -// Return the minimum MV. -int av1_return_min_sub_pixel_mv( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *cost_list, int *mvjcost, int *mvcost[2], int *distortion, - unsigned int *sse1, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv) { - COMMON_MV_TEST; - (void)maxr; - (void)maxc; - (void)mask; - (void)mask_stride; - (void)invert_mask; + const int allow_hp = ms_params->allow_hp; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; - (void)cm; - (void)mi_row; - (void)mi_col; - (void)do_reset_fractional_mv; + bestmv->row = mv_limits->row_max; + bestmv->col = mv_limits->col_max; + + unsigned int besterr = 0; - bestmv->row = minr; - bestmv->col = minc; - besterr = 0; // In the sub-pel motion search, if hp is not used, then the last bit of mv // has to be 0. lower_mv_precision(bestmv, allow_hp, 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; +// Returns the minimum MV. +int av1_return_min_sub_pixel_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + MV start_mv, MV *bestmv, int *distortion, + unsigned int *sse1, + int_mv *last_mv_search_list) { + (void)xd; + (void)cm; + (void)start_mv; + (void)sse1; + (void)distortion; + (void)last_mv_search_list; - set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize); + const int allow_hp = ms_params->allow_hp; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; - 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; + bestmv->row = mv_limits->row_min; + bestmv->col = mv_limits->col_min; - 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 = cpi->sf.mv.search_method; - const int do_mesh_search = 0; - const int sadpb = x->sadperbit16; - int cost_list[5]; - const int ref_idx = 0; - int var; + unsigned int besterr = 0; + // In the sub-pel motion search, if hp is not used, then the last bit of mv + // has to be 0. + lower_mv_precision(bestmv, allow_hp, 0); + return besterr; +} - av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col, - get_ref_scale_factors(cm, ref), num_planes); - set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); - 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); - } +// Computes the cost of the current predictor by going through the whole +// av1_enc_build_inter_predictor pipeline. This is mainly used by warped mv +// during motion_mode_rd. We are going through the whole +// av1_enc_build_inter_predictor because we might have changed the interpolation +// filter, etc before motion_mode_rd is called. +static INLINE unsigned int compute_motion_cost( + MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, BLOCK_SIZE bsize, + const MV *this_mv) { + unsigned int mse; + unsigned int sse; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; - // 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], 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 (scaled_ref_frame) { - xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12; - } - 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 av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, AOM_PLANE_Y, AOM_PLANE_Y); - aom_clear_system_state(); + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + const MSBuffers *ms_buffers = &var_params->ms_buffers; - if (scaled_ref_frame) { - xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12; + const uint8_t *const src = ms_buffers->src->buf; + const int src_stride = ms_buffers->src->stride; + const uint8_t *const dst = xd->plane[0].dst.buf; + const int dst_stride = xd->plane[0].dst.stride; + const aom_variance_fn_ptr_t *vfp = ms_params->var_params.vfp; + + mse = vfp->vf(dst, dst_stride, src, src_stride, &sse); + mse += mv_err_cost_(this_mv, &ms_params->mv_cost_params); + return mse; +} + +// Refines MV in a small range +unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + BLOCK_SIZE bsize, const int *pts0, + const int *pts_inref0, int total_samples) { + MB_MODE_INFO *mbmi = xd->mi[0]; + static const MV neighbors[8] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, + { 0, -2 }, { 2, 0 }, { 0, 2 }, { -2, 0 } }; + MV *best_mv = &mbmi->mv[0].as_mv; + + WarpedMotionParams best_wm_params = mbmi->wm_params; + int best_num_proj_ref = mbmi->num_proj_ref; + unsigned int bestmse; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + + const int start = ms_params->allow_hp ? 0 : 4; + + // Calculate the center position's error + assert(av1_is_subpelmv_in_range(mv_limits, *best_mv)); + bestmse = compute_motion_cost(xd, cm, ms_params, bsize, best_mv); + + // MV search + int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE]; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + for (int ite = 0; ite < 2; ++ite) { + int best_idx = -1; + + for (int idx = start; idx < start + 4; ++idx) { + unsigned int thismse; + + MV this_mv = { best_mv->row + neighbors[idx].row, + best_mv->col + neighbors[idx].col }; + if (av1_is_subpelmv_in_range(mv_limits, this_mv)) { + memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0)); + memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0)); + if (total_samples > 1) + mbmi->num_proj_ref = + av1_selectSamples(&this_mv, pts, pts_inref, total_samples, bsize); + + if (!av1_find_projection(mbmi->num_proj_ref, pts, pts_inref, bsize, + this_mv.row, this_mv.col, &mbmi->wm_params, + mi_row, mi_col)) { + thismse = compute_motion_cost(xd, cm, ms_params, bsize, &this_mv); + + if (thismse < bestmse) { + best_idx = idx; + best_wm_params = mbmi->wm_params; + best_num_proj_ref = mbmi->num_proj_ref; + bestmse = thismse; + } + } + } + } + + if (best_idx == -1) break; + + if (best_idx >= 0) { + best_mv->row += neighbors[best_idx].row; + best_mv->col += neighbors[best_idx].col; + } + } + + mbmi->wm_params = best_wm_params; + mbmi->num_proj_ref = best_num_proj_ref; + return bestmse; +} +// ============================================================================= +// Subpixel Motion Search: OBMC +// ============================================================================= +// Estimates the variance of prediction residue +static INLINE int estimate_obmc_pref_error( + const MV *this_mv, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + unsigned int *sse) { + const aom_variance_fn_ptr_t *vfp = var_params->vfp; + + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const int32_t *src = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const uint8_t *ref = get_buf_from_mv(ms_buffers->ref, *this_mv); + const int ref_stride = ms_buffers->ref->stride; + + const int subpel_x_q3 = get_subpel_part(this_mv->col); + const int subpel_y_q3 = get_subpel_part(this_mv->row); + + return vfp->osvf(ref, ref_stride, subpel_x_q3, subpel_y_q3, src, mask, sse); +} + +// Calculates the variance of prediction residue +static int upsampled_obmc_pref_error(MACROBLOCKD *xd, const AV1_COMMON *cm, + const MV *this_mv, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + unsigned int *sse) { + const aom_variance_fn_ptr_t *vfp = var_params->vfp; + const SUBPEL_SEARCH_TYPE subpel_search_type = var_params->subpel_search_type; + const int w = var_params->w; + const int h = var_params->h; + + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const int32_t *wsrc = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const uint8_t *ref = get_buf_from_mv(ms_buffers->ref, *this_mv); + const int ref_stride = ms_buffers->ref->stride; + + const int subpel_x_q3 = get_subpel_part(this_mv->col); + const int subpel_y_q3 = get_subpel_part(this_mv->row); + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + unsigned int besterr; + DECLARE_ALIGNED(16, uint8_t, pred[2 * MAX_SB_SQUARE]); +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + uint8_t *pred8 = CONVERT_TO_BYTEPTR(pred); + aom_highbd_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred8, w, h, + subpel_x_q3, subpel_y_q3, ref, ref_stride, xd->bd, + subpel_search_type); + besterr = vfp->ovf(pred8, w, wsrc, mask, sse); + } else { + aom_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, w, h, subpel_x_q3, + subpel_y_q3, ref, ref_stride, subpel_search_type); + + besterr = vfp->ovf(pred, w, wsrc, mask, sse); + } +#else + aom_upsampled_pred(xd, cm, mi_row, mi_col, this_mv, pred, w, h, subpel_x_q3, + subpel_y_q3, ref, ref_stride, subpel_search_type); + + besterr = vfp->ovf(pred, w, wsrc, mask, sse); +#endif + return besterr; +} + +static unsigned int setup_obmc_center_error( + const MV *this_mv, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *sse1, int *distortion) { + // TODO(chiyotsai@google.com): There might be a bug here where we didn't use + // get_buf_from_mv(ref, *this_mv). + const MSBuffers *ms_buffers = &var_params->ms_buffers; + const int32_t *wsrc = ms_buffers->wsrc; + const int32_t *mask = ms_buffers->obmc_mask; + const uint8_t *ref = ms_buffers->ref->buf; + const int ref_stride = ms_buffers->ref->stride; + unsigned int besterr = + var_params->vfp->ovf(ref, ref_stride, wsrc, mask, sse1); + *distortion = besterr; + besterr += mv_err_cost_(this_mv, mv_cost_params); + return besterr; +} + +static unsigned int upsampled_setup_obmc_center_error( + MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV *this_mv, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *sse1, int *distortion) { + unsigned int besterr = + upsampled_obmc_pref_error(xd, cm, this_mv, var_params, sse1); + *distortion = besterr; + besterr += mv_err_cost_(this_mv, mv_cost_params); + return besterr; +} + +// Estimates the variance of prediction residue +// TODO(chiyotsai@google.com): the cost does does not match the cost in +// mv_cost_. Investigate this later. +static INLINE int estimate_obmc_mvcost(const MV *this_mv, + const MV_COST_PARAMS *mv_cost_params) { + const MV *ref_mv = mv_cost_params->ref_mv; + const int *mvjcost = mv_cost_params->mvjcost; + const int *const *mvcost = mv_cost_params->mvcost; + const int error_per_bit = mv_cost_params->error_per_bit; + const MV_COST_TYPE mv_cost_type = mv_cost_params->mv_cost_type; + const MV diff_mv = { GET_MV_SUBPEL(this_mv->row - ref_mv->row), + GET_MV_SUBPEL(this_mv->col - ref_mv->col) }; + + switch (mv_cost_type) { + case MV_COST_ENTROPY: + return (unsigned)((mv_cost(&diff_mv, mvjcost, + CONVERT_TO_CONST_MVCOST(mvcost)) * + error_per_bit + + 4096) >> + 13); + case MV_COST_NONE: return 0; + default: + assert(0 && "L1 norm is not tuned for estimated obmc mvcost"); + return 0; } } -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; +// Estimates whether this_mv is better than best_mv. This function incorporates +// both prediction error and residue into account. +static INLINE unsigned int obmc_check_better_fast( + const MV *this_mv, MV *best_mv, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion, int *has_better_mv) { + unsigned int cost; + if (av1_is_subpelmv_in_range(mv_limits, *this_mv)) { + unsigned int sse; + const int thismse = estimate_obmc_pref_error(this_mv, var_params, &sse); - av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, ref_mv_full, 1, - use_subpixel); + cost = estimate_obmc_mvcost(this_mv, mv_cost_params); + cost += thismse; - 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); + if (cost < *besterr) { + *besterr = cost; + *best_mv = *this_mv; + *distortion = thismse; + *sse1 = sse; + *has_better_mv |= 1; + } + } else { + cost = INT_MAX; + } + return cost; +} + +// Estimates whether this_mv is better than best_mv. This function incorporates +// both prediction error and residue into account. +static INLINE unsigned int obmc_check_better( + MACROBLOCKD *xd, const AV1_COMMON *cm, const MV *this_mv, MV *best_mv, + const SubpelMvLimits *mv_limits, const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion, int *has_better_mv) { + unsigned int cost; + if (av1_is_subpelmv_in_range(mv_limits, *this_mv)) { + unsigned int sse; + const int thismse = + upsampled_obmc_pref_error(xd, cm, this_mv, var_params, &sse); + cost = mv_err_cost_(this_mv, mv_cost_params); + + cost += thismse; + + if (cost < *besterr) { + *besterr = cost; + *best_mv = *this_mv; + *distortion = thismse; + *sse1 = sse; + *has_better_mv |= 1; + } + } else { + cost = INT_MAX; + } + return cost; +} + +static AOM_FORCE_INLINE MV obmc_first_level_check( + MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV this_mv, MV *best_mv, + const int hstep, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + int dummy = 0; + const MV left_mv = { this_mv.row, this_mv.col - hstep }; + const MV right_mv = { this_mv.row, this_mv.col + hstep }; + const MV top_mv = { this_mv.row - hstep, this_mv.col }; + const MV bottom_mv = { this_mv.row + hstep, this_mv.col }; + + if (var_params->subpel_search_type != USE_2_TAPS_ORIG) { + const unsigned int left = + obmc_check_better(xd, cm, &left_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int right = + obmc_check_better(xd, cm, &right_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int up = + obmc_check_better(xd, cm, &top_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + const unsigned int down = + obmc_check_better(xd, cm, &bottom_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + const MV diag_step = get_best_diag_step(hstep, left, right, up, down); + const MV diag_mv = { this_mv.row + diag_step.row, + this_mv.col + diag_step.col }; + + // Check the diagonal direction with the best mv + obmc_check_better(xd, cm, &diag_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + return diag_step; + } else { + const unsigned int left = obmc_check_better_fast( + &left_mv, best_mv, mv_limits, var_params, mv_cost_params, besterr, sse1, + distortion, &dummy); + const unsigned int right = obmc_check_better_fast( + &right_mv, best_mv, mv_limits, var_params, mv_cost_params, besterr, + sse1, distortion, &dummy); + + const unsigned int up = obmc_check_better_fast( + &top_mv, best_mv, mv_limits, var_params, mv_cost_params, besterr, sse1, + distortion, &dummy); + + const unsigned int down = obmc_check_better_fast( + &bottom_mv, best_mv, mv_limits, var_params, mv_cost_params, besterr, + sse1, distortion, &dummy); + + const MV diag_step = get_best_diag_step(hstep, left, right, up, down); + const MV diag_mv = { this_mv.row + diag_step.row, + this_mv.col + diag_step.col }; + + // Check the diagonal direction with the best mv + obmc_check_better_fast(&diag_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, &dummy); + + return diag_step; + } +} + +// A newer version of second level check for obmc that gives better quality. +static AOM_FORCE_INLINE void obmc_second_level_check_v2( + MACROBLOCKD *xd, const AV1_COMMON *const cm, const MV this_mv, MV diag_step, + MV *best_mv, const SubpelMvLimits *mv_limits, + const SUBPEL_SEARCH_VAR_PARAMS *var_params, + const MV_COST_PARAMS *mv_cost_params, unsigned int *besterr, + unsigned int *sse1, int *distortion) { + assert(best_mv->row == this_mv.row + diag_step.row || + best_mv->col == this_mv.col + diag_step.col); + if (CHECK_MV_EQUAL(this_mv, *best_mv)) { + return; + } else if (this_mv.row == best_mv->row) { + // Search away from diagonal step since diagonal search did not provide any + // improvement + diag_step.row *= -1; + } else if (this_mv.col == best_mv->col) { + diag_step.col *= -1; + } + + const MV row_bias_mv = { best_mv->row + diag_step.row, best_mv->col }; + const MV col_bias_mv = { best_mv->row, best_mv->col + diag_step.col }; + const MV diag_bias_mv = { best_mv->row + diag_step.row, + best_mv->col + diag_step.col }; + int has_better_mv = 0; + + if (var_params->subpel_search_type != USE_2_TAPS_ORIG) { + obmc_check_better(xd, cm, &row_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + obmc_check_better(xd, cm, &col_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + + // Do an additional search if the second iteration gives a better mv + if (has_better_mv) { + obmc_check_better(xd, cm, &diag_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + } + } else { + obmc_check_better_fast(&row_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + obmc_check_better_fast(&col_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + + // Do an additional search if the second iteration gives a better mv + if (has_better_mv) { + obmc_check_better_fast(&diag_bias_mv, best_mv, mv_limits, var_params, + mv_cost_params, besterr, sse1, distortion, + &has_better_mv); + } + } +} + +int av1_find_best_obmc_sub_pixel_tree_up( + MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV start_mv, MV *bestmv, + int *distortion, unsigned int *sse1, int_mv *last_mv_search_list) { + (void)last_mv_search_list; + const int allow_hp = ms_params->allow_hp; + const int forced_stop = ms_params->forced_stop; + const int iters_per_step = ms_params->iters_per_step; + const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params; + const SUBPEL_SEARCH_VAR_PARAMS *var_params = &ms_params->var_params; + const SUBPEL_SEARCH_TYPE subpel_search_type = + ms_params->var_params.subpel_search_type; + const SubpelMvLimits *mv_limits = &ms_params->mv_limits; + + int hstep = INIT_SUBPEL_STEP_SIZE; + const int round = AOMMIN(FULL_PEL - forced_stop, 3 - !allow_hp); + + unsigned int besterr = INT_MAX; + *bestmv = start_mv; + + if (subpel_search_type != USE_2_TAPS_ORIG) + besterr = upsampled_setup_obmc_center_error( + xd, cm, bestmv, var_params, mv_cost_params, sse1, distortion); + else + besterr = setup_obmc_center_error(bestmv, var_params, mv_cost_params, sse1, + distortion); + + for (int iter = 0; iter < round; ++iter) { + MV iter_center_mv = *bestmv; + MV diag_step = obmc_first_level_check(xd, cm, iter_center_mv, bestmv, hstep, + mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion); + + if (!CHECK_MV_EQUAL(iter_center_mv, *bestmv) && iters_per_step > 1) { + obmc_second_level_check_v2(xd, cm, iter_center_mv, diag_step, bestmv, + mv_limits, var_params, mv_cost_params, + &besterr, sse1, distortion); + } + hstep >>= 1; + } + + return besterr; +} + +// ============================================================================= +// Public cost function: mv_cost + pred error +// ============================================================================= +int av1_get_mvpred_sse(const MACROBLOCK *x, const FULLPEL_MV *best_mv, + const MV *ref_mv, const aom_variance_fn_ptr_t *vfp) { + const MACROBLOCKD *const xd = &x->e_mbd; + const struct buf_2d *const what = &x->plane[0].src; + const struct buf_2d *const in_what = &xd->plane[0].pre[0]; + const MV mv = get_mv_from_fullmv(best_mv); + const MV_COST_TYPE mv_cost_type = x->mv_cost_type; + unsigned int sse, var; + + var = vfp->vf(what->buf, what->stride, get_buf_from_fullmv(in_what, best_mv), + in_what->stride, &sse); + (void)var; + + return sse + mv_err_cost(&mv, ref_mv, x->nmv_vec_cost, + CONVERT_TO_CONST_MVCOST(x->mv_cost_stack), + x->errorperbit, mv_cost_type); +} + +static INLINE int get_mvpred_av_var(const MV_COST_PARAMS *mv_cost_params, + const FULLPEL_MV best_mv, + const uint8_t *second_pred, + const aom_variance_fn_ptr_t *vfp, + const struct buf_2d *src, + const struct buf_2d *pre) { + const struct buf_2d *const what = src; + const struct buf_2d *const in_what = pre; + const MV mv = get_mv_from_fullmv(&best_mv); + unsigned int unused; + + return vfp->svaf(get_buf_from_fullmv(in_what, &best_mv), in_what->stride, 0, + 0, what->buf, what->stride, &unused, second_pred) + + mv_err_cost_(&mv, mv_cost_params); +} + +static INLINE int get_mvpred_mask_var( + const MV_COST_PARAMS *mv_cost_params, const FULLPEL_MV best_mv, + const uint8_t *second_pred, const uint8_t *mask, int mask_stride, + int invert_mask, const aom_variance_fn_ptr_t *vfp, const struct buf_2d *src, + const struct buf_2d *pre) { + const struct buf_2d *const what = src; + const struct buf_2d *const in_what = pre; + const MV mv = get_mv_from_fullmv(&best_mv); + unsigned int unused; + + return vfp->msvf(what->buf, what->stride, 0, 0, + get_buf_from_fullmv(in_what, &best_mv), in_what->stride, + second_pred, mask, mask_stride, invert_mask, &unused) + + mv_err_cost_(&mv, mv_cost_params); +} + +int av1_get_mvpred_compound_var(const MV_COST_PARAMS *mv_cost_params, + const FULLPEL_MV best_mv, + const uint8_t *second_pred, const uint8_t *mask, + int mask_stride, int invert_mask, + const aom_variance_fn_ptr_t *vfp, + const struct buf_2d *src, + const struct buf_2d *pre) { + if (mask) { + return get_mvpred_mask_var(mv_cost_params, best_mv, second_pred, mask, + mask_stride, invert_mask, vfp, src, pre); + } else { + return get_mvpred_av_var(mv_cost_params, best_mv, second_pred, vfp, src, + pre); + } } diff --git a/media/libaom/src/av1/encoder/mcomp.h b/media/libaom/src/av1/encoder/mcomp.h index 458c80e8b2..73135d8591 100644 --- a/media/libaom/src/av1/encoder/mcomp.h +++ b/media/libaom/src/av1/encoder/mcomp.h @@ -12,6 +12,7 @@ #ifndef AOM_AV1_ENCODER_MCOMP_H_ #define AOM_AV1_ENCODER_MCOMP_H_ +#include "av1/common/mv.h" #include "av1/encoder/block.h" #include "aom_dsp/variance.h" @@ -28,9 +29,6 @@ extern "C" { #define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS - 1)) - 1) // Maximum size of the first step in full pel units #define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS - 1)) -// Allowed motion vector pixel distance outside image border -// for Block_16x16 -#define BORDER_MV_PIXELS_B16 (16 + AOM_INTERP_EXTEND) #define SEARCH_RANGE_8P 3 #define SEARCH_GRID_STRIDE_8P (2 * SEARCH_RANGE_8P + 1) @@ -39,78 +37,246 @@ extern "C" { // motion search site typedef struct search_site { - MV mv; + FULLPEL_MV mv; int offset; } search_site; typedef struct search_site_config { - search_site ss[8 * MAX_MVSEARCH_STEPS + 1]; + search_site ss[MAX_MVSEARCH_STEPS * 2][16 + 1]; int ss_count; - int searches_per_step; + int searches_per_step[MAX_MVSEARCH_STEPS * 2]; + int radius[MAX_MVSEARCH_STEPS * 2]; int stride; } search_site_config; typedef struct { - MV coord; + FULLPEL_MV coord; int coord_offset; } search_neighbors; -void av1_init_dsmotion_compensation(search_site_config *cfg, int stride); -void av1_init3smotion_compensation(search_site_config *cfg, int stride); - -void av1_set_mv_search_range(MvLimits *mv_limits, const MV *mv); - -int av1_mv_bit_cost(const MV *mv, const MV *ref, const int *mvjcost, - int *mvcost[2], int weight); - -// Utility to compute variance + MV rate cost for a given MV -int av1_get_mvpred_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const aom_variance_fn_ptr_t *vfp, - int use_mvcost); -int av1_get_mvpred_av_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const uint8_t *second_pred, - const aom_variance_fn_ptr_t *vfp, int use_mvcost); -int av1_get_mvpred_mask_var(const MACROBLOCK *x, const MV *best_mv, - const MV *center_mv, const uint8_t *second_pred, - const uint8_t *mask, int mask_stride, - int invert_mask, const aom_variance_fn_ptr_t *vfp, - int use_mvcost); - struct AV1_COMP; struct SPEED_FEATURES; -int av1_init_search_range(int size); +// ============================================================================= +// Cost functions +// ============================================================================= +typedef struct { + const MV *ref_mv; + FULLPEL_MV full_ref_mv; + const int *mvjcost; + const int *mvcost[2]; + int error_per_bit; + int sad_per_bit; + MV_COST_TYPE mv_cost_type; +} MV_COST_PARAMS; -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); +int av1_mv_bit_cost(const MV *mv, const MV *ref_mv, const int *mvjcost, + int *mvcost[2], int weight); + +int av1_get_mvpred_sse(const MACROBLOCK *x, const FULLPEL_MV *best_mv, + const MV *ref_mv, const aom_variance_fn_ptr_t *vfp); +int av1_get_mvpred_compound_var(const MV_COST_PARAMS *ms_params, + const FULLPEL_MV best_mv, + const uint8_t *second_pred, const uint8_t *mask, + int mask_stride, int invert_mask, + const aom_variance_fn_ptr_t *vfp, + const struct buf_2d *src, + const struct buf_2d *pre); + +// ============================================================================= +// Motion Search +// ============================================================================= +typedef struct { + // The reference buffer + const struct buf_2d *ref; + + // The source and predictors/mask used by translational search + const struct buf_2d *src; + const uint8_t *second_pred; + const uint8_t *mask; + int mask_stride; + int inv_mask; + + // The weighted source and mask used by OBMC + const int32_t *wsrc; + const int32_t *obmc_mask; +} MSBuffers; + +static INLINE void av1_set_ms_compound_refs(MSBuffers *ms_buffers, + const uint8_t *second_pred, + const uint8_t *mask, + int mask_stride, int invert_mask) { + ms_buffers->second_pred = second_pred; + ms_buffers->mask = mask; + ms_buffers->mask_stride = mask_stride; + ms_buffers->inv_mask = invert_mask; +} + +// ============================================================================= +// Fullpixel Motion Search +// ============================================================================= +enum { + DIAMOND = 0, + NSTEP = 1, + HEX = 2, + BIGDIA = 3, + SQUARE = 4, + FAST_HEX = 5, + FAST_DIAMOND = 6 +} UENUM1BYTE(SEARCH_METHODS); + +// This struct holds fullpixel motion search parameters that should be constant +// during the search +typedef struct { + BLOCK_SIZE bsize; + const aom_variance_fn_ptr_t *vfp; + + MSBuffers ms_buffers; + + SEARCH_METHODS search_method; + const search_site_config *search_sites; + FullMvLimits mv_limits; + + int run_mesh_search; // Sets mesh search unless it got pruned by + // prune_mesh_search. + int prune_mesh_search; // Disables mesh search if the best_mv after a normal + // search if close to the start_mv. + int force_mesh_thresh; // Forces mesh search if the residue variance is + // higher than the threshold. + const struct MESH_PATTERN *mesh_patterns[2]; + + int is_intra_mode; + + int fast_obmc_search; + + // For calculating mv cost + MV_COST_PARAMS mv_cost_params; +} FULLPEL_MOTION_SEARCH_PARAMS; + +void av1_make_default_fullpel_ms_params(FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct AV1_COMP *cpi, + const MACROBLOCK *x, BLOCK_SIZE bsize, + const MV *ref_mv, + const search_site_config *search_sites); + +// Sets up configs for fullpixel diamond search +void av1_init_dsmotion_compensation(search_site_config *cfg, int stride); +// Sets up configs for firstpass motion search +void av1_init_motion_fpf(search_site_config *cfg, int stride); +// Sets up configs for all other types of motion search +void av1_init3smotion_compensation(search_site_config *cfg, int stride); + +// Set up limit values for MV components. +// Mv beyond the range do not produce new/different prediction block. +static INLINE void av1_set_mv_row_limits( + const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, + int mi_row, int mi_height, int border) { + const int min1 = -(mi_row * MI_SIZE + border - 2 * AOM_INTERP_EXTEND); + const int min2 = -(((mi_row + mi_height) * MI_SIZE) + 2 * AOM_INTERP_EXTEND); + mv_limits->row_min = AOMMAX(min1, min2); + const int max1 = (mi_params->mi_rows - mi_row - mi_height) * MI_SIZE + + border - 2 * AOM_INTERP_EXTEND; + const int max2 = + (mi_params->mi_rows - mi_row) * MI_SIZE + 2 * AOM_INTERP_EXTEND; + mv_limits->row_max = AOMMIN(max1, max2); +} + +static INLINE void av1_set_mv_col_limits( + const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, + int mi_col, int mi_width, int border) { + const int min1 = -(mi_col * MI_SIZE + border - 2 * AOM_INTERP_EXTEND); + const int min2 = -(((mi_col + mi_width) * MI_SIZE) + 2 * AOM_INTERP_EXTEND); + mv_limits->col_min = AOMMAX(min1, min2); + const int max1 = (mi_params->mi_cols - mi_col - mi_width) * MI_SIZE + border - + 2 * AOM_INTERP_EXTEND; + const int max2 = + (mi_params->mi_cols - mi_col) * MI_SIZE + 2 * AOM_INTERP_EXTEND; + mv_limits->col_max = AOMMIN(max1, max2); +} + +static INLINE void av1_set_mv_limits( + const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, + int mi_row, int mi_col, int mi_height, int mi_width, int border) { + av1_set_mv_row_limits(mi_params, mv_limits, mi_row, mi_height, border); + av1_set_mv_col_limits(mi_params, mv_limits, mi_col, mi_width, border); +} + +void av1_set_mv_search_range(FullMvLimits *mv_limits, const MV *mv); + +int av1_init_search_range(int size); 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, - int further_steps, int do_refine, int *cost_list, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *ref_mv, MV *dst_mv); +int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const FULLPEL_MV start_mv, FULLPEL_MV *best_mv); -int av1_hex_search(MACROBLOCK *x, MV *start_mv, int search_param, - int sad_per_bit, int do_init_search, int *cost_list, - const aom_variance_fn_ptr_t *vfp, int use_mvcost, - const MV *center_mv); +int av1_full_pixel_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int step_param, int *cost_list, + FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv); -typedef int(fractional_mv_step_fp)( - MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col, - const MV *ref_mv, int allow_hp, int error_per_bit, - const aom_variance_fn_ptr_t *vfp, - int forced_stop, // 0 - full, 1 - qtr only, 2 - half only - int iters_per_step, int *cost_list, int *mvjcost, int *mvcost[2], - int *distortion, unsigned int *sse1, const uint8_t *second_pred, - const uint8_t *mask, int mask_stride, int invert_mask, int w, int h, - int use_accurate_subpel_search, const int do_reset_fractional_mv); +int av1_intrabc_hash_search(const struct AV1_COMP *cpi, const MACROBLOCKD *xd, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + IntraBCHashInfo *intrabc_hash_info, + FULLPEL_MV *best_mv); + +int av1_obmc_full_pixel_search(const FULLPEL_MV start_mv, + const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, + const int step_param, FULLPEL_MV *best_mv); + +static INLINE int av1_is_fullmv_in_range(const FullMvLimits *mv_limits, + FULLPEL_MV mv) { + return (mv.col >= mv_limits->col_min) && (mv.col <= mv_limits->col_max) && + (mv.row >= mv_limits->row_min) && (mv.row <= mv_limits->row_max); +} +// ============================================================================= +// Subpixel Motion Search +// ============================================================================= +enum { + EIGHTH_PEL, + QUARTER_PEL, + HALF_PEL, + FULL_PEL +} UENUM1BYTE(SUBPEL_FORCE_STOP); + +typedef struct { + const aom_variance_fn_ptr_t *vfp; + SUBPEL_SEARCH_TYPE subpel_search_type; + // Source and reference buffers + MSBuffers ms_buffers; + int w, h; +} SUBPEL_SEARCH_VAR_PARAMS; + +// This struct holds subpixel motion search parameters that should be constant +// during the search +typedef struct { + // High level motion search settings + int allow_hp; + const int *cost_list; + SUBPEL_FORCE_STOP forced_stop; + int iters_per_step; + SubpelMvLimits mv_limits; + + // For calculating mv cost + MV_COST_PARAMS mv_cost_params; + + // Distortion calculation params + SUBPEL_SEARCH_VAR_PARAMS var_params; +} SUBPEL_MOTION_SEARCH_PARAMS; + +void av1_make_default_subpel_ms_params(SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + const struct AV1_COMP *cpi, + const MACROBLOCK *x, BLOCK_SIZE bsize, + const MV *ref_mv, const int *cost_list); + +typedef int(fractional_mv_step_fp)(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + MV start_mv, MV *bestmv, int *distortion, + unsigned int *sse1, + int_mv *last_mv_search_list); extern fractional_mv_step_fp av1_find_best_sub_pixel_tree; extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned; @@ -118,64 +284,12 @@ extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_more; extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_evenmore; extern fractional_mv_step_fp av1_return_max_sub_pixel_mv; extern fractional_mv_step_fp av1_return_min_sub_pixel_mv; +extern fractional_mv_step_fp av1_find_best_obmc_sub_pixel_tree_up; -typedef int (*av1_full_search_fn_t)(const MACROBLOCK *x, const MV *ref_mv, - int sad_per_bit, int distance, - const aom_variance_fn_ptr_t *fn_ptr, - const MV *center_mv, MV *best_mv); - -typedef int (*av1_diamond_search_fn_t)( - MACROBLOCK *x, const search_site_config *cfg, MV *ref_mv, MV *best_mv, - int search_param, int sad_per_bit, int *num00, - const aom_variance_fn_ptr_t *fn_ptr, const MV *center_mv); - -int av1_refining_search_8p_c(MACROBLOCK *x, int error_per_bit, int search_range, - const aom_variance_fn_ptr_t *fn_ptr, - const uint8_t *mask, int mask_stride, - int invert_mask, const MV *center_mv, - const uint8_t *second_pred); - -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, - const search_site_config *cfg, - int use_intrabc_mesh_pattern); - -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 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, - const aom_variance_fn_ptr_t *vfp, int forced_stop, int iters_per_step, - int *mvjcost, int *mvcost[2], int *distortion, unsigned int *sse1, - int is_second, int use_accurate_subpel_search); - -unsigned int av1_compute_motion_cost(const struct AV1_COMP *cpi, - MACROBLOCK *const x, BLOCK_SIZE bsize, - int mi_row, int mi_col, const MV *this_mv); -unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi, - MACROBLOCK *const x, BLOCK_SIZE bsize, - 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); +unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm, + const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, + BLOCK_SIZE bsize, const int *pts0, + const int *pts_inref0, int total_samples); static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) { for (int z = 0; z < 3; z++) { @@ -183,20 +297,29 @@ static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) { } } -static INLINE void set_subpel_mv_search_range(const MvLimits *mv_limits, - int *col_min, int *col_max, - int *row_min, int *row_max, - const MV *ref_mv) { - const int max_mv = MAX_FULL_PEL_VAL * 8; - const int minc = AOMMAX(mv_limits->col_min * 8, ref_mv->col - max_mv); - const int maxc = AOMMIN(mv_limits->col_max * 8, ref_mv->col + max_mv); - const int minr = AOMMAX(mv_limits->row_min * 8, ref_mv->row - max_mv); - const int maxr = AOMMIN(mv_limits->row_max * 8, ref_mv->row + max_mv); +static INLINE void av1_set_subpel_mv_search_range(SubpelMvLimits *subpel_limits, + const FullMvLimits *mv_limits, + const MV *ref_mv) { + const int max_mv = GET_MV_SUBPEL(MAX_FULL_PEL_VAL); + const int minc = + AOMMAX(GET_MV_SUBPEL(mv_limits->col_min), ref_mv->col - max_mv); + const int maxc = + AOMMIN(GET_MV_SUBPEL(mv_limits->col_max), ref_mv->col + max_mv); + const int minr = + AOMMAX(GET_MV_SUBPEL(mv_limits->row_min), ref_mv->row - max_mv); + const int maxr = + AOMMIN(GET_MV_SUBPEL(mv_limits->row_max), ref_mv->row + max_mv); - *col_min = AOMMAX(MV_LOW + 1, minc); - *col_max = AOMMIN(MV_UPP - 1, maxc); - *row_min = AOMMAX(MV_LOW + 1, minr); - *row_max = AOMMIN(MV_UPP - 1, maxr); + subpel_limits->col_min = AOMMAX(MV_LOW + 1, minc); + subpel_limits->col_max = AOMMIN(MV_UPP - 1, maxc); + subpel_limits->row_min = AOMMAX(MV_LOW + 1, minr); + subpel_limits->row_max = AOMMIN(MV_UPP - 1, maxr); +} + +static INLINE int av1_is_subpelmv_in_range(const SubpelMvLimits *mv_limits, + MV mv) { + return (mv.col >= mv_limits->col_min) && (mv.col <= mv_limits->col_max) && + (mv.row >= mv_limits->row_min) && (mv.row <= mv_limits->row_max); } #ifdef __cplusplus diff --git a/media/libaom/src/av1/encoder/misc_model_weights.h b/media/libaom/src/av1/encoder/misc_model_weights.h new file mode 100644 index 0000000000..f00aeabcf6 --- /dev/null +++ b/media/libaom/src/av1/encoder/misc_model_weights.h @@ -0,0 +1,696 @@ +/* + * 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_MISC_MODEL_WEIGHTS_H_ +#define AOM_AV1_ENCODER_MISC_MODEL_WEIGHTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "av1/encoder/ml.h" + +#define MV_PREC_FEATURE_SIZE 18 + +#define NUM_DNN_LAYERS 1 +#define NUM_DNN_FEATURES MV_PREC_FEATURE_SIZE +#define MV_PREC_LAYER_SIZE_0 32 +#define NUM_LOGITS 1 + +const float av1_mv_prec_mean[MV_PREC_FEATURE_SIZE] = { 143.67358891063745f, + 141.6251917346238f, + 0.36313633945679064f, + 0.0028162791958822085f, + 0.000484820537626698f, + 0.002769969388939025f, + 0.0f, + 0.00031274626720947577f, + 0.00020578555375160075f, + 0.0007075246732697733f, + 0.000539641029909925f, + 0.0013939401375906984f, + 4.985394760423499f, + 4.985394760423499f, + 4.9992148717283085f, + 5.143739822380163f, + 5.518483124004564f, + 87.63597847427077f }; + +const float av1_mv_prec_std[MV_PREC_FEATURE_SIZE] = { 66.86256140247244f, + 68.04472572607503f, + 13.23247674430399f, + 0.0029123438396921955f, + 0.0015331406169374737f, + 0.0029149813096313775f, + 1.0f, + 0.00047501102871357813f, + 0.00030025962993117947f, + 0.0009861163580391207f, + 0.0012157593528004055f, + 0.002004954948490521f, + 6.539447500484038f, + 6.539447500484038f, + 6.396589058279465f, + 3.4870155874262516f, + 3.8911353973740535f, + 112.07985259573601f }; + +const float av1_mv_prec_nn_weights_layer_0[] = { -0.13008492159557145f, + -0.1483527373474774f, + 0.08112076098858864f, + -0.9582568679627453f, + -0.34794757171071206f, + 0.6465225723304947f, + 0.0f, + 0.06754171885839604f, + 0.27156803620541214f, + 0.10635231245664407f, + -0.031183926995968583f, + 0.048122572260291f, + -0.19498534230045128f, + -0.2614116319273316f, + -0.3223762845136331f, + -1.2063368350609205f, + -0.523333556911706f, + 1.075632260890728f, + 0.48989726814387946f, + -0.34816466111070477f, + 0.41668357610256473f, + -1.0973562848791671f, + 0.04183921854389494f, + -0.9123815389260476f, + 0.0f, + 0.859965047744027f, + 0.1962095804679813f, + 0.2606564339077058f, + 0.26695868715184895f, + 0.5319308568326692f, + -0.23717505799723165f, + -0.43127224481782567f, + -0.3214545776203726f, + 0.5850852241402176f, + -0.26705531612587813f, + -0.5786016766610093f, + 0.9360519909983003f, + 0.20771329289016555f, + -0.027614159544811823f, + -1.175022807046164f, + -0.07578967497693835f, + 0.6890172485324256f, + 0.0f, + -0.008008338164988263f, + -0.08064800010158935f, + -0.22606910981666667f, + 0.4541586669210879f, + 0.07731527661370792f, + -0.6744475941247964f, + -0.2625842448396184f, + 1.7018613444303785f, + -0.08622229073162656f, + 0.041858142814941275f, + -0.24575964090386415f, + -0.046626044730994964f, + 0.7608713064175202f, + -0.23330119070907146f, + -0.10115510984500826f, + 0.9722537349192069f, + 0.11718554254290829f, + 0.0f, + 0.2075123446014759f, + 0.09465167310768637f, + 0.7609896851963016f, + 0.4441038581385328f, + 0.26064144727430955f, + -0.14678625366485035f, + -0.03597014452200524f, + 0.3128680867196166f, + 1.102496797385966f, + 0.06642253233084111f, + -1.2665494483407629f, + 0.09049412632000911f, + -1.1160621999565095f, + 0.043420275255913035f, + -0.8811412259978966f, + 0.21076234632287777f, + 0.16571534463543866f, + 0.0f, + -0.7324075176473275f, + -0.3677622514459495f, + 0.3273532243056415f, + 0.22922161936797775f, + 0.8204766691058087f, + 0.02982161033720488f, + 0.5266419954188112f, + -1.0032154963302191f, + 0.7007602969763729f, + 0.37196355167990885f, + -0.7608579453228548f, + 0.08568111584781847f, + 0.07011061059123677f, + 0.3233263598082507f, + -0.08249928295410253f, + 0.08220165761319252f, + 0.22148722752246794f, + 0.0f, + 0.6122392701743506f, + -0.26429838296378333f, + 0.31958081620005463f, + -0.006027177397853826f, + -0.3088310785887994f, + -0.5436192046707807f, + -0.011080356757423306f, + 0.12632650770008413f, + -0.45097913215234525f, + 1.8008072867127298f, + -0.7630029654575501f, + -0.4054774329826579f, + 0.40386074452544535f, + -0.18541426257453025f, + 0.2444879765079863f, + -0.6216724756115081f, + 0.27030299321302f, + 0.0f, + -0.6835848952967989f, + -0.7914184320964815f, + -0.6761595019582928f, + -1.009565565604081f, + -0.1904242439353305f, + 0.4463417126318631f, + 0.6025503823452971f, + 0.5149990860115566f, + 1.0242970663937634f, + 0.037947306826401385f, + 0.07039339786212848f, + 0.14273796789711987f, + 0.168103961425691f, + 1.6596066376811978f, + 0.19321092229384657f, + -0.3710750388148514f, + -0.01717015559410288f, + 0.0f, + 0.3005688477942597f, + 0.23877080653829577f, + 0.2718594552971173f, + 0.3885402571589898f, + 0.32999531945669247f, + -0.6134460954213243f, + -0.13972265462799183f, + -0.07180089575716991f, + -1.014572598188105f, + 0.0717207322809836f, + 0.34896157745155615f, + -0.27127687591403f, + -0.5058651212773623f, + -1.5442435628306925f, + -0.6399784724734707f, + 0.6274301429074947f, + -0.4645750072767051f, + 0.0f, + -0.2406726815244178f, + -0.06321214115916597f, + 0.312856714253404f, + 0.16459514124116134f, + 0.3993579604809623f, + -0.15232044351561913f, + -0.5613743948568469f, + 0.7219801372223262f, + 0.2936857469624009f, + 0.7823466656034087f, + -0.12416947814098349f, + -0.36413756654028345f, + -0.07992098796866462f, + -0.7395722879842416f, + 0.8639913543220514f, + -0.311931773757945f, + -1.7308240470400613f, + 0.0f, + 0.394499716712104f, + 0.6511462819539963f, + -0.0722425275974144f, + 0.13490818194661386f, + 0.055319135836378035f, + 0.15389577508097013f, + 0.28958598328870605f, + -0.14608429470539772f, + 0.09488817462478298f, + -0.17231294096622088f, + 0.6721115415911466f, + -0.05664621150536103f, + 0.03291799673669331f, + 0.02845382711057482f, + -0.9953563446999164f, + -0.17994298220605923f, + 0.6560824519337476f, + 0.0f, + -0.30990646375917935f, + 0.17215517202874f, + 0.2026816225170481f, + 0.22011958747715601f, + 0.3562520768889686f, + -0.18436559057189175f, + 0.1733377147302066f, + 0.02818276995640877f, + -0.29703005574859076f, + -0.3310652639215064f, + -1.6091173258529277f, + 0.45461585790028003f, + -0.5078643334592593f, + -0.338997374732338f, + 0.4688619590359733f, + 0.627099126828289f, + -0.5249801376494249f, + 0.0f, + 0.34465498218272883f, + 0.009891680630908135f, + -0.27244020967349f, + 0.05404589867626979f, + -0.06220329325739666f, + -0.13365376464759104f, + -0.13098573553512366f, + 0.11434198976289106f, + 0.6740951247574676f, + 1.3381727185724581f, + -1.4865773213251936f, + 0.05809898701966341f, + 0.25380780261023456f, + 1.2716367496512722f, + 0.1768290070780598f, + -0.07554828135356352f, + 0.8180570085344856f, + 0.0f, + 1.0788448980077463f, + 0.0651938742459459f, + 0.3807672030015587f, + 0.6144792680268445f, + 0.011660612214908059f, + -0.018306023765580288f, + 0.44140813809926516f, + -0.13411994195502386f, + 0.15920368955127778f, + -0.19382358417849888f, + -0.08802147969690055f, + -0.019731052733814477f, + 0.1104744229169665f, + -0.195834419735958f, + -0.5005295046454347f, + -0.17041241868229032f, + -0.471942117351489f, + 0.0f, + -0.3599073304761372f, + -0.2745532782968519f, + -0.8323064841106417f, + -0.88355885384943f, + -0.02826466859020679f, + 0.06977870308805256f, + 0.11926112095374196f, + 1.367382707959643f, + -0.06119843162964051f, + -0.5331395268889569f, + -1.2155531584240624f, + -0.01896651779524327f, + 0.10591845408571081f, + -0.010632842156504733f, + 0.6150787968629282f, + -0.4191690185896091f, + -0.9961718918346271f, + 0.0f, + 0.23370364516013867f, + 0.4156033072362998f, + 0.1261005546633433f, + 0.0812413884532226f, + -0.008894337353937203f, + 0.07984447025056046f, + -0.1258098052766725f, + -0.40245475467767916f, + 1.78188906675019f, + -1.1544387954232302f, + -0.41768781481273387f, + 0.6791211165341995f, + -0.4175127856183446f, + -0.07353219159767788f, + -0.2888813577574072f, + -0.7107767892597061f, + -1.0450031091195449f, + 0.0f, + -0.9221599545079143f, + -0.6747876356740621f, + 0.30241454354872105f, + 0.4924965303373908f, + -0.14042722740054084f, + 0.27744210409350445f, + -0.14788270997426836f, + -0.9081467469237995f, + -0.04513115674995093f, + -0.5254168669125793f, + -0.6999012037974789f, + 0.434661246306547f, + -0.7193303957246092f, + -0.9117952623409744f, + -1.5097267865916142f, + -0.20779888103770922f, + 0.4935562480901218f, + 0.0f, + 0.18303393908923593f, + 0.34753722677570037f, + 0.29291001533177663f, + 0.3832351878354224f, + 0.3295194956120599f, + -0.32398033003617527f, + -0.31570906736433746f, + 0.23657779050372962f, + 0.9510794465234161f, + -0.5122243902568278f, + 0.08652112725315658f, + 0.2246634353717998f, + -0.9032595595582497f, + -0.8936484034533545f, + 0.6012969720865752f, + -0.6454216646117924f, + -1.1753786049658332f, + 0.0f, + -0.4360545677728656f, + -0.6586237455328507f, + -0.34347301697886656f, + -0.8909724651992144f, + -0.24378721818350263f, + 0.6179733359297576f, + 0.0661661181742234f, + -0.14120142044993794f, + -0.07732699885498932f, + 1.0221355882357506f, + 0.44514798994115284f, + -0.7371569579959046f, + -0.7212499572378936f, + 0.7453626921081045f, + 0.5478757761345768f, + -0.39411232789985384f, + 0.7200542656743857f, + 0.0f, + -0.11790869453118827f, + -0.12317030713581928f, + -0.4207902738133338f, + 0.15895105878327986f, + 0.304261777102111f, + 0.11450744587017621f, + -0.11470709991317944f, + 0.5949222371739038f, + 0.6549518619412444f, + -0.24390606570422838f, + -0.4212796009440803f, + -0.6269666206320964f, + -0.5421193969807078f, + -0.12297772128652287f, + 0.021517257619930424f, + 0.25462855095544523f, + -0.22107798187348246f, + 0.0f, + 0.5204516300095662f, + 0.2837402841862462f, + 0.11310823283285916f, + 0.8944351685018025f, + 0.17487203235834015f, + -0.5271221928634433f, + -0.19516594503423199f, + 0.452456617580365f, + 1.2456272242706414f, + 0.24166615894862817f, + 0.09411429305204502f, + -0.2730072283327243f, + -0.8129383770918172f, + -0.24093254193486136f, + 0.5696499174142177f, + -0.11110805836073044f, + -0.3968204166235694f, + 0.0f, + -0.04388165369378549f, + -0.005631266017272595f, + -0.02574211858479705f, + 0.06230399626660669f, + 0.17677671232932785f, + 0.5172871274400965f, + 0.4919150085620063f, + -1.597656637582941f, + 0.02415185715719143f, + -0.17945446376668306f, + -0.39340600199798886f, + 0.25013205256886845f, + 0.05972330340308685f, + 0.1359911505596489f, + -0.02341033271820833f, + 0.15726074644063684f, + 0.47512625913020357f, + 0.0f, + 0.7327341664835779f, + -0.3689092312320013f, + 0.4571824787436036f, + 0.6215465537945456f, + 0.0944111296842023f, + -0.12571956176607574f, + -0.2507235674395462f, + -0.09579602654351593f, + 1.4463357293728496f, + 0.749153535856049f, + -0.5553955120807588f, + -0.09622771929369946f, + -0.2598697420394813f, + -0.964691815299676f, + -0.8289963178173902f, + 0.7112949291983329f, + -0.8667009730492162f, + 0.0f, + -0.48698304169042794f, + -0.18786095669893707f, + -0.11425249263203247f, + -0.3693391011684809f, + 0.09933145842585253f, + 0.2568559685298844f, + 0.7048512233651738f, + 0.6056238412407038f, + -0.4355558119826642f, + 0.17318931883915484f, + 0.6481333496429564f, + -0.45728823054344486f, + -0.006325004538589701f, + 0.45609864075494927f, + -0.6199385981116988f, + 0.035105808783046165f, + 0.1203147963894839f, + 0.0f, + 0.383402190836527f, + 0.048429009055370106f, + 0.5887186439275204f, + -0.20538767641607814f, + -0.031237879611002117f, + 0.3140759860883231f, + 0.24447070584999556f, + 0.7271263905705878f, + 0.8432799162434237f, + -0.11530577554199217f, + -0.7781023892314718f, + 0.05359488822710336f, + 0.5624870388700809f, + 0.5134656523208906f, + 0.18304041423438375f, + -0.04237421156328257f, + -0.20759809886942207f, + 0.0f, + -0.06249337454975615f, + 0.10081284533873777f, + 0.3894374350259183f, + 1.518217777528342f, + -0.9100037950171563f, + 0.17796906121831477f, + -0.2892167255357892f, + 0.6117902467884032f, + 0.13332120964959573f, + -0.3487155932849374f, + -0.32920583745734694f, + 0.08242631209809854f, + -0.24920225708110588f, + 0.8401757259392635f, + 0.11729108681358365f, + 0.11222925752499184f, + -0.027078490721459958f, + 0.0f, + 0.726132375517389f, + 0.72220359881096f, + 0.5721582611845177f, + 0.15139162075524315f, + 0.6676549461551197f, + -0.321449586554697f, + -0.10141104515219895f, + -0.09711123988777906f, + 0.9623356184776928f, + -0.7941822373167173f, + -0.9373923554119346f, + 0.4573241832354059f, + -0.42029139056126147f, + 0.2675223459380999f, + -0.5487300191551386f, + 0.2236621891916084f, + 0.11692039230044018f, + 0.0f, + 0.1758399202780961f, + 0.676447587678781f, + 0.5945412815881029f, + 0.5669863357359594f, + 0.8433565415303922f, + -0.30300550790708036f, + -0.43332881999693673f, + -0.4996522695731392f, + -0.2084930815451962f, + 0.27765278702463786f, + 1.0886848763946915f, + -0.0739433655813831f, + -0.4762801579229192f, + -0.2490825339320731f, + -1.8820479350439439f, + -0.4251592225775914f, + -0.3992922365484464f, + 0.0f, + 0.19598917760218867f, + 0.4860238022746914f, + 0.3364528828641281f, + 0.3350950865226741f, + 0.2773654548632006f, + -0.30547262140782566f, + 0.028649620490728344f, + -0.11763407628280315f, + 0.6237318502627169f, + -0.3958952632477945f, + 0.14797171297835243f, + 0.45821729624747465f, + -0.8687137170773626f, + 0.06989667196937126f, + -0.5752606929478727f, + 0.16986945686358412f, + 0.6925071596817824f, + 0.0f, + 0.4991250796183003f, + 0.03424654896322111f, + 0.6153698611882319f, + 0.5070872444849457f, + 0.43615747516328135f, + -0.7870352838659244f, + -0.6424101231965247f, + -0.7005774876651399f, + 0.79983115431488f, + 0.15720357955596242f, + -1.408372612176309f, + -0.039294695217213765f, + 0.6979415372962309f, + 0.27403316751965656f, + 1.2844596102619275f, + -0.2781534150257364f, + 0.3248437714908865f, + 0.0f, + 0.4364362371752831f, + -0.2548580911485434f, + -0.19578001373349452f, + -0.04597194387828005f, + -0.010035156855533233f, + 0.0415941475251266f, + 0.07929549739797387f, + -0.060629652912508866f, + 0.5977303008711333f, + -1.4404008068066554f, + 0.8555694790197376f, + -0.03693438534401856f, + 0.17761411164512408f, + -0.11858304304109235f, + -1.4241324353471327f, + 0.1533849765389186f, + 0.7650643783126995f, + 0.0f, + -0.0639949379280401f, + 0.4288617817939563f, + 0.4235508646885404f, + 0.3419843254383798f, + -0.015992360660098768f, + -0.773247697505441f, + -0.4908452922015917f, + 0.9868134897291486f, + -0.5078689994742608f, + 1.05632043744864f, + -0.38867419409275117f, + -0.0065547696858664194f, + -0.3056003173415037f, + -0.333762331930102f, + 0.4459671174011671f, + 0.08219092584580244f, + -0.08099158579518179f, + 0.0f, + -0.1568180656346373f, + -0.061962372393910135f, + 0.14065868174859464f, + -0.055925712798972765f, + 0.05136117465820622f, + 0.0907831030477633f, + 0.19518110495319604f, + -0.7470794578145956f, + 1.5945999734733545f, + -0.4351697502345834f, + -0.33253649399571805f }; + +const float av1_mv_prec_nn_bias_layer_0[] = { + -0.651213833993862f, -1.1243309933417809f, -0.2123880023097051f, + 0.23095477452877616f, -0.6668057665893545f, 0.3082268148379634f, + -0.3344916753975844f, -0.20920185606857844f, 0.6057933917964854f, + 0.5031857662559803f, -1.5380096313468152f, -0.4457245344804041f, + 1.82368055812373f, 0.7973912064077963f, 0.25706500555622913f, + 0.1394695119825382f, 0.4508811973450553f, -0.5408959545111782f, + 1.064829233697863f, 0.3733268644246235f, 1.1173169029905483f, + -0.2012817466400134f, -0.16628447748302294f, 1.3086000088940826f, + 0.7267092979664235f, -0.9097857006590555f, -0.7564259343863077f, + -0.49844128036716173f, -0.4675729246975423f, -0.03626154526362181f, + -0.41957330902404616f, -0.9658160514319954f +}; + +const float av1_mv_prec_nn_weights_layer_1[] = { + 1.5017296484510276f, 1.044216918060133f, -1.066541411740906f, + -0.7762965171172661f, -0.9814396609661653f, 0.9334065847340715f, + 0.7117244268817873f, -0.7695942296628597f, 0.7892157680137047f, + -0.5786309358654476f, -2.4444494892027264f, 1.1666759262637185f, + -0.9699580532370483f, 0.5849682956422552f, -1.0372272986941953f, + -0.5005014627824439f, 1.1816204711740521f, -1.2204867615892114f, + 0.4510263977504913f, 0.35567865078585165f, -0.7811389330738839f, + -0.6643977800301099f, -0.6283287371705794f, 0.790873821018048f, + 0.8861643352684585f, 0.6438840651522237f, 0.6677191546466089f, + 0.9703715021995785f, 1.250893534236489f, 0.7733742028067933f, + -1.249673977776904f, -1.2890127265725608f +}; + +const float av1_mv_prec_nn_bias_layer_1[] = { -0.341771735378258f }; + +static const NN_CONFIG av1_mv_prec_dnn_config = { + NUM_DNN_FEATURES, + NUM_LOGITS, + NUM_DNN_LAYERS, + { MV_PREC_LAYER_SIZE_0 }, + { + av1_mv_prec_nn_weights_layer_0, + av1_mv_prec_nn_weights_layer_1, + }, + { + av1_mv_prec_nn_bias_layer_0, + av1_mv_prec_nn_bias_layer_1, + }, +}; +#undef NUM_DNN_LAYERS +#undef NUM_DNN_FEATURES +#undef NUM_LAYER_0_UNITS +#undef NUM_LOGITS + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_MISC_MODEL_WEIGHTS_H_ diff --git a/media/libaom/src/av1/encoder/model_rd.h b/media/libaom/src/av1/encoder/model_rd.h new file mode 100644 index 0000000000..c353c8f85b --- /dev/null +++ b/media/libaom/src/av1/encoder/model_rd.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2020, 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_MODEL_RD_H_ +#define AOM_AV1_ENCODER_MODEL_RD_H_ + +#include "aom/aom_integer.h" +#include "av1/encoder/block.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/pustats.h" +#include "av1/encoder/rdopt_utils.h" +#include "aom_ports/system_state.h" +#include "config/aom_dsp_rtcd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// 0: Legacy model +// 1: Curve fit model +// 2: Surface fit model +// 3: DNN regression model +// 4: Full rd model +#define MODELRD_TYPE_INTERP_FILTER 1 +#define MODELRD_TYPE_TX_SEARCH_PRUNE 1 +#define MODELRD_TYPE_MASKED_COMPOUND 1 +#define MODELRD_TYPE_INTERINTRA 1 +#define MODELRD_TYPE_INTRA 1 +#define MODELRD_TYPE_MOTION_MODE_RD 1 + +typedef void (*model_rd_for_sb_type)(const AV1_COMP *const cpi, + BLOCK_SIZE bsize, MACROBLOCK *x, + MACROBLOCKD *xd, int plane_from, + int plane_to, int *out_rate_sum, + int64_t *out_dist_sum, int *skip_txfm_sb, + int64_t *skip_sse_sb, int *plane_rate, + int64_t *plane_sse, int64_t *plane_dist); +typedef void (*model_rd_from_sse_type)(const AV1_COMP *const cpi, + const MACROBLOCK *const x, + BLOCK_SIZE plane_bsize, int plane, + int64_t sse, int num_samples, int *rate, + int64_t *dist); + +static int64_t calculate_sse(MACROBLOCKD *const xd, + const struct macroblock_plane *p, + struct macroblockd_plane *pd, const int bw, + const int bh) { + int64_t sse = 0; + const int shift = xd->bd - 8; +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + sse = aom_highbd_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, + bw, bh); + } else { + sse = + aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh); + } +#else + sse = aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh); +#endif + sse = ROUND_POWER_OF_TWO(sse, shift * 2); + return sse; +} + +static AOM_INLINE int64_t compute_sse_plane(MACROBLOCK *x, MACROBLOCKD *xd, + int plane, const BLOCK_SIZE bsize) { + struct macroblockd_plane *const pd = &xd->plane[plane]; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + int bw, bh; + const struct macroblock_plane *const p = &x->plane[plane]; + get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw, + &bh); + + int64_t sse = calculate_sse(xd, p, pd, bw, bh); + + return sse; +} + +static AOM_INLINE void model_rd_from_sse(const AV1_COMP *const cpi, + const MACROBLOCK *const x, + BLOCK_SIZE plane_bsize, int plane, + int64_t sse, int num_samples, + int *rate, int64_t *dist) { + (void)num_samples; + const MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblock_plane *const p = &x->plane[plane]; + const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; + + // Fast approximate the modelling function. + if (cpi->sf.rd_sf.simple_model_rd_from_var) { + const int64_t square_error = sse; + int quantizer = p->dequant_QTX[1] >> dequant_shift; + if (quantizer < 120) + *rate = (int)AOMMIN( + (square_error * (280 - quantizer)) >> (16 - AV1_PROB_COST_SHIFT), + INT_MAX); + else + *rate = 0; + assert(*rate >= 0); + *dist = (square_error * quantizer) >> 8; + } else { + av1_model_rd_from_var_lapndz(sse, num_pels_log2_lookup[plane_bsize], + p->dequant_QTX[1] >> dequant_shift, rate, + dist); + } + *dist <<= 4; +} + +// Fits a curve for rate and distortion using as feature: +// log2(sse_norm/qstep^2) +static AOM_INLINE void model_rd_with_curvfit(const AV1_COMP *const cpi, + const MACROBLOCK *const x, + BLOCK_SIZE plane_bsize, int plane, + int64_t sse, int num_samples, + int *rate, int64_t *dist) { + (void)cpi; + (void)plane_bsize; + const MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblock_plane *const p = &x->plane[plane]; + const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; + const int qstep = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1); + + if (sse == 0) { + if (rate) *rate = 0; + if (dist) *dist = 0; + return; + } + aom_clear_system_state(); + const double sse_norm = (double)sse / num_samples; + const double qstepsqr = (double)qstep * qstep; + 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, + &dist_by_sse_norm_f); + + const double dist_f = dist_by_sse_norm_f * sse_norm; + int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5); + int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5); + aom_clear_system_state(); + + // Check if skip is better + if (rate_i == 0) { + dist_i = sse << 4; + } else if (RDCOST(x->rdmult, rate_i, dist_i) >= + RDCOST(x->rdmult, 0, sse << 4)) { + rate_i = 0; + dist_i = sse << 4; + } + + if (rate) *rate = rate_i; + if (dist) *dist = dist_i; +} + +static AOM_INLINE void model_rd_for_sb( + const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, + int plane_from, int plane_to, int *out_rate_sum, int64_t *out_dist_sum, + int *skip_txfm_sb, int64_t *skip_sse_sb, int *plane_rate, + int64_t *plane_sse, int64_t *plane_dist) { + // Note our transform coeffs are 8 times an orthogonal transform. + // Hence quantizer step is also 8 times. To get effective quantizer + // we need to divide by 8 before sending to modeling function. + int plane; + const int ref = xd->mi[0]->ref_frame[0]; + + int64_t rate_sum = 0; + int64_t dist_sum = 0; + int64_t total_sse = 0; + + assert(bsize < BLOCK_SIZES_ALL); + + for (plane = plane_from; plane <= plane_to; ++plane) { + if (plane && !xd->is_chroma_ref) break; + struct macroblock_plane *const p = &x->plane[plane]; + struct macroblockd_plane *const pd = &xd->plane[plane]; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + assert(plane_bsize < BLOCK_SIZES_ALL); + const int bw = block_size_wide[plane_bsize]; + const int bh = block_size_high[plane_bsize]; + int64_t sse; + int rate; + int64_t dist; + + sse = calculate_sse(xd, p, pd, bw, bh); + + model_rd_from_sse(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, &dist); + + if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); + + total_sse += sse; + rate_sum += rate; + dist_sum += dist; + if (plane_rate) plane_rate[plane] = rate; + if (plane_sse) plane_sse[plane] = sse; + if (plane_dist) plane_dist[plane] = dist; + assert(rate_sum >= 0); + } + + if (skip_txfm_sb) *skip_txfm_sb = total_sse == 0; + if (skip_sse_sb) *skip_sse_sb = total_sse << 4; + rate_sum = AOMMIN(rate_sum, INT_MAX); + *out_rate_sum = (int)rate_sum; + *out_dist_sum = dist_sum; +} + +static AOM_INLINE void model_rd_for_sb_with_curvfit( + const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, + int plane_from, int plane_to, int *out_rate_sum, int64_t *out_dist_sum, + int *skip_txfm_sb, int64_t *skip_sse_sb, int *plane_rate, + int64_t *plane_sse, int64_t *plane_dist) { + // Note our transform coeffs are 8 times an orthogonal transform. + // Hence quantizer step is also 8 times. To get effective quantizer + // we need to divide by 8 before sending to modeling function. + const int ref = xd->mi[0]->ref_frame[0]; + + int64_t rate_sum = 0; + int64_t dist_sum = 0; + int64_t total_sse = 0; + + for (int plane = plane_from; plane <= plane_to; ++plane) { + if (plane && !xd->is_chroma_ref) break; + struct macroblockd_plane *const pd = &xd->plane[plane]; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + int64_t dist, sse; + int rate; + int bw, bh; + const struct macroblock_plane *const p = &x->plane[plane]; + get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, + &bw, &bh); + + sse = calculate_sse(xd, p, pd, bw, bh); + model_rd_with_curvfit(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, + &dist); + + if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); + + total_sse += sse; + rate_sum += rate; + dist_sum += dist; + + if (plane_rate) plane_rate[plane] = rate; + if (plane_sse) plane_sse[plane] = sse; + if (plane_dist) plane_dist[plane] = dist; + } + + if (skip_txfm_sb) *skip_txfm_sb = rate_sum == 0; + if (skip_sse_sb) *skip_sse_sb = total_sse << 4; + *out_rate_sum = (int)rate_sum; + *out_dist_sum = dist_sum; +} + +enum { MODELRD_LEGACY, MODELRD_CURVFIT, MODELRD_TYPES } UENUM1BYTE(ModelRdType); + +static const model_rd_for_sb_type model_rd_sb_fn[MODELRD_TYPES] = { + model_rd_for_sb, model_rd_for_sb_with_curvfit +}; + +static const model_rd_from_sse_type model_rd_sse_fn[MODELRD_TYPES] = { + model_rd_from_sse, model_rd_with_curvfit +}; + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // AOM_AV1_ENCODER_MODEL_RD_H_ diff --git a/media/libaom/src/av1/encoder/motion_search_facade.c b/media/libaom/src/av1/encoder/motion_search_facade.c new file mode 100644 index 0000000000..8db1423e7a --- /dev/null +++ b/media/libaom/src/av1/encoder/motion_search_facade.c @@ -0,0 +1,861 @@ +/* + * Copyright (c) 2020, 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/common/reconinter.h" + +#include "av1/encoder/encodemv.h" +#include "av1/encoder/encoder.h" +#include "av1/encoder/mcomp.h" +#include "av1/encoder/motion_search_facade.h" +#include "av1/encoder/partition_strategy.h" +#include "av1/encoder/reconinter_enc.h" +#include "av1/encoder/tpl_model.h" + +#define RIGHT_SHIFT_MV(x) (((x) + 3 + ((x) >= 0)) >> 3) + +typedef struct { + FULLPEL_MV fmv; + int weight; +} cand_mv_t; + +static int compare_weight(const void *a, const void *b) { + const int diff = ((cand_mv_t *)a)->weight - ((cand_mv_t *)b)->weight; + if (diff < 0) + return 1; + else if (diff > 0) + return -1; + return 0; +} + +void av1_single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int ref_idx, int *rate_mv, + int search_range, inter_mode_info *mode_info, + int_mv *best_mv) { + MACROBLOCKD *xd = &x->e_mbd; + const AV1_COMMON *cm = &cpi->common; + const MotionVectorSearchParams *mv_search_params = &cpi->mv_search_params; + const int num_planes = av1_num_planes(cm); + MB_MODE_INFO *mbmi = xd->mi[0]; + struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } }; + int bestsme = INT_MAX; + const int ref = mbmi->ref_frame[ref_idx]; + const YV12_BUFFER_CONFIG *scaled_ref_frame = + av1_get_scaled_ref_frame(cpi, ref); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + if (scaled_ref_frame) { + // Swap out the reference frame for a version that's been scaled to + // match the resolution of the current frame, allowing the existing + // full-pixel motion search code to be used without additional + // modifications. + for (int i = 0; i < num_planes; i++) { + backup_yv12[i] = xd->plane[i].pre[ref_idx]; + } + av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, + num_planes); + } + + // Work out the size of the first step in the mv step search. + // 0 here is maximum length first step. 1 is AOMMAX >> 1 etc. + int step_param; + if (cpi->sf.mv_sf.auto_mv_step_size && cm->show_frame) { + // Take the weighted average of the step_params based on the last frame's + // max mv magnitude and that based on the best ref mvs of the current + // block for the given reference. + step_param = (av1_init_search_range(x->max_mv_context[ref]) + + mv_search_params->mv_step_param) / + 2; + } else { + step_param = mv_search_params->mv_step_param; + } + + if (cpi->sf.mv_sf.adaptive_motion_search && bsize < cm->seq_params.sb_size) { + int boffset = + 2 * (mi_size_wide_log2[cm->seq_params.sb_size] - + AOMMIN(mi_size_high_log2[bsize], mi_size_wide_log2[bsize])); + step_param = AOMMAX(step_param, boffset); + } + + if (cpi->sf.mv_sf.adaptive_motion_search) { + int bwl = mi_size_wide_log2[bsize]; + int bhl = mi_size_high_log2[bsize]; + int tlevel = x->pred_mv_sad[ref] >> (bwl + bhl + 4); + + if (tlevel < 5) { + step_param += 2; + step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 1); + } + + // prev_mv_sad is not setup for dynamically scaled frames. + if (cpi->oxcf.resize_mode != RESIZE_RANDOM) { + int i; + for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) { + if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) { + x->pred_mv[ref].row = 0; + x->pred_mv[ref].col = 0; + best_mv->as_int = INVALID_MV; + + if (scaled_ref_frame) { + // Swap back the original buffers before returning. + for (int j = 0; j < num_planes; ++j) + xd->plane[j].pre[ref_idx] = backup_yv12[j]; + } + return; + } + } + } + } + + const MV ref_mv = av1_get_ref_mv(x, ref_idx).as_mv; + FULLPEL_MV start_mv; + if (mbmi->motion_mode != SIMPLE_TRANSLATION) + start_mv = get_fullmv_from_mv(&mbmi->mv[0].as_mv); + else + start_mv = get_fullmv_from_mv(&ref_mv); + + // cand stores start_mv and all possible MVs in a SB. + cand_mv_t cand[MAX_MC_FLOW_BLK_IN_SB * MAX_MC_FLOW_BLK_IN_SB + 1] = { + { { 0, 0 }, 0 } + }; + cand[0].fmv = start_mv; + int cnt = 1; + int total_weight = 0; + + if (!cpi->sf.mv_sf.full_pixel_search_level && + mbmi->motion_mode == SIMPLE_TRANSLATION) { + if (x->valid_cost_b) { + const BLOCK_SIZE tpl_bsize = convert_length_to_bsize(MC_FLOW_BSIZE_1D); + const int tplw = mi_size_wide[tpl_bsize]; + const int tplh = mi_size_high[tpl_bsize]; + const int nw = mi_size_wide[bsize] / tplw; + const int nh = mi_size_high[bsize] / tplh; + + if (nw >= 1 && nh >= 1) { + const int of_h = mi_row % mi_size_high[cm->seq_params.sb_size]; + const int of_w = mi_col % mi_size_wide[cm->seq_params.sb_size]; + const int start = of_h / tplh * x->cost_stride + of_w / tplw; + int valid = 1; + + // Assign large weight to start_mv, so it is always tested. + cand[0].weight = nw * nh; + + for (int k = 0; k < nh; k++) { + for (int l = 0; l < nw; l++) { + const int_mv mv = + x->mv_b[start + k * x->cost_stride + l][ref - LAST_FRAME]; + if (mv.as_int == INVALID_MV) { + valid = 0; + break; + } + + const FULLPEL_MV fmv = { GET_MV_RAWPEL(mv.as_mv.row), + GET_MV_RAWPEL(mv.as_mv.col) }; + int unique = 1; + for (int m = 0; m < cnt; m++) { + if (RIGHT_SHIFT_MV(fmv.row) == RIGHT_SHIFT_MV(cand[m].fmv.row) && + RIGHT_SHIFT_MV(fmv.col) == RIGHT_SHIFT_MV(cand[m].fmv.col)) { + unique = 0; + cand[m].weight++; + break; + } + } + + if (unique) { + cand[cnt].fmv = fmv; + cand[cnt].weight = 1; + cnt++; + } + } + if (!valid) break; + } + + if (valid) { + total_weight = 2 * nh * nw; + if (cnt > 2) qsort(cand, cnt, sizeof(cand[0]), &compare_weight); + } + } + } + } + + // Further reduce the search range. + if (search_range < INT_MAX) { + const search_site_config *ss_cfg = &mv_search_params->ss_cfg[SS_CFG_SRC]; + // MAx step_param is ss_cfg->ss_count. + if (search_range < 1) { + step_param = ss_cfg->ss_count; + } else { + while (ss_cfg->radius[ss_cfg->ss_count - step_param - 1] > + (search_range << 1) && + ss_cfg->ss_count - step_param - 1 > 0) + step_param++; + } + } + + int cost_list[5]; + int_mv second_best_mv; + best_mv->as_int = second_best_mv.as_int = INVALID_MV; + + const search_site_config *src_search_sites = + &mv_search_params->ss_cfg[SS_CFG_SRC]; + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &ref_mv, + src_search_sites); + + switch (mbmi->motion_mode) { + case SIMPLE_TRANSLATION: { + int sum_weight = 0; + + for (int m = 0; m < cnt; m++) { + FULLPEL_MV smv = cand[m].fmv; + FULLPEL_MV this_best_mv, this_second_best_mv; + + int thissme = av1_full_pixel_search( + smv, &full_ms_params, step_param, cond_cost_list(cpi, cost_list), + &this_best_mv, &this_second_best_mv); + + if (thissme < bestsme) { + bestsme = thissme; + best_mv->as_fullmv = this_best_mv; + second_best_mv.as_fullmv = this_second_best_mv; + } + + sum_weight += cand[m].weight; + if (m >= 2 || 4 * sum_weight > 3 * total_weight) break; + } + } break; + case OBMC_CAUSAL: + bestsme = av1_obmc_full_pixel_search(start_mv, &full_ms_params, + step_param, &best_mv->as_fullmv); + break; + default: assert(0 && "Invalid motion mode!\n"); + } + + if (scaled_ref_frame) { + // Swap back the original buffers for subpel motion search. + for (int i = 0; i < num_planes; i++) { + xd->plane[i].pre[ref_idx] = backup_yv12[i]; + } + } + + // Terminate search with the current ref_idx if we have already encountered + // another ref_mv in the drl such that: + // 1. The other drl has the same fullpel_mv during the SIMPLE_TRANSLATION + // search process as the current fullpel_mv. + // 2. The rate needed to encode the current fullpel_mv is larger than that + // for the other ref_mv. + if (cpi->sf.inter_sf.skip_repeated_full_newmv && + mbmi->motion_mode == SIMPLE_TRANSLATION && + best_mv->as_int != INVALID_MV) { + int_mv this_mv; + this_mv.as_mv = get_mv_from_fullmv(&best_mv->as_fullmv); + const int ref_mv_idx = mbmi->ref_mv_idx; + const int this_mv_rate = + av1_mv_bit_cost(&this_mv.as_mv, &ref_mv, x->nmv_vec_cost, + x->mv_cost_stack, MV_COST_WEIGHT); + mode_info[ref_mv_idx].full_search_mv.as_int = this_mv.as_int; + mode_info[ref_mv_idx].full_mv_rate = this_mv_rate; + + for (int prev_ref_idx = 0; prev_ref_idx < ref_mv_idx; ++prev_ref_idx) { + // Check if the motion search result same as previous results + if (this_mv.as_int == mode_info[prev_ref_idx].full_search_mv.as_int) { + // Compare the rate cost + const int prev_rate_cost = mode_info[prev_ref_idx].full_mv_rate + + mode_info[prev_ref_idx].drl_cost; + const int this_rate_cost = + this_mv_rate + mode_info[ref_mv_idx].drl_cost; + + if (prev_rate_cost <= this_rate_cost) { + // If the current rate_cost is worse than the previous rate_cost, then + // we terminate the search. Since av1_single_motion_search is only + // called by handle_new_mv in SIMPLE_TRANSLATION mode, we set the + // best_mv to INVALID mv to signal that we wish to terminate search + // for the current mode. + best_mv->as_int = INVALID_MV; + return; + } + } + } + } + + if (cpi->common.features.cur_frame_force_integer_mv) { + convert_fullmv_to_mv(best_mv); + } + + const int use_fractional_mv = + bestsme < INT_MAX && cpi->common.features.cur_frame_force_integer_mv == 0; + if (use_fractional_mv) { + int_mv fractional_ms_list[3]; + av1_set_fractional_mv(fractional_ms_list); + int dis; /* TODO: use dis in distortion calculation later. */ + + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv, + cost_list); + MV subpel_start_mv = get_mv_from_fullmv(&best_mv->as_fullmv); + + switch (mbmi->motion_mode) { + case SIMPLE_TRANSLATION: + if (cpi->sf.mv_sf.use_accurate_subpel_search) { + const int try_second = second_best_mv.as_int != INVALID_MV && + second_best_mv.as_int != best_mv->as_int; + const int best_mv_var = mv_search_params->find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &best_mv->as_mv, &dis, + &x->pred_sse[ref], fractional_ms_list); + + if (try_second) { + MV this_best_mv; + subpel_start_mv = get_mv_from_fullmv(&second_best_mv.as_fullmv); + if (av1_is_subpelmv_in_range(&ms_params.mv_limits, + subpel_start_mv)) { + const int this_var = mv_search_params->find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &this_best_mv, &dis, + &x->pred_sse[ref], fractional_ms_list); + if (this_var < best_mv_var) best_mv->as_mv = this_best_mv; + } + } + } else { + mv_search_params->find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &best_mv->as_mv, &dis, + &x->pred_sse[ref], NULL); + } + break; + case OBMC_CAUSAL: + av1_find_best_obmc_sub_pixel_tree_up(xd, cm, &ms_params, + subpel_start_mv, &best_mv->as_mv, + &dis, &x->pred_sse[ref], NULL); + break; + default: assert(0 && "Invalid motion mode!\n"); + } + } + *rate_mv = av1_mv_bit_cost(&best_mv->as_mv, &ref_mv, x->nmv_vec_cost, + x->mv_cost_stack, MV_COST_WEIGHT); + + if (cpi->sf.mv_sf.adaptive_motion_search && + mbmi->motion_mode == SIMPLE_TRANSLATION) + x->pred_mv[ref] = best_mv->as_mv; +} + +void av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int_mv *cur_mv, + const uint8_t *mask, int mask_stride, + int *rate_mv) { + const AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + const int pw = block_size_wide[bsize]; + const int ph = block_size_high[bsize]; + const int plane = 0; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + // This function should only ever be called for compound modes + assert(has_second_ref(mbmi)); + const int_mv init_mv[2] = { cur_mv[0], cur_mv[1] }; + const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] }; + int_mv ref_mv[2]; + int ite, ref; + + // Get the prediction block from the 'other' reference frame. + const int_interpfilters interp_filters = + av1_broadcast_interp_filter(EIGHTTAP_REGULAR); + + InterPredParams inter_pred_params; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + // Do joint motion search in compound mode to get more accurate mv. + struct buf_2d backup_yv12[2][MAX_MB_PLANE]; + int last_besterr[2] = { INT_MAX, INT_MAX }; + const YV12_BUFFER_CONFIG *const scaled_ref_frame[2] = { + av1_get_scaled_ref_frame(cpi, refs[0]), + av1_get_scaled_ref_frame(cpi, refs[1]) + }; + + // Prediction buffer from second frame. + DECLARE_ALIGNED(16, uint8_t, second_pred16[MAX_SB_SQUARE * sizeof(uint16_t)]); + uint8_t *second_pred = get_buf_by_bd(xd, second_pred16); + int_mv best_mv; + + // Allow joint search multiple times iteratively for each reference frame + // and break out of the search loop if it couldn't find a better mv. + for (ite = 0; ite < 4; ite++) { + struct buf_2d ref_yv12[2]; + int bestsme = INT_MAX; + int id = ite % 2; // Even iterations search in the first reference frame, + // odd iterations search in the second. The predictor + // found for the 'other' reference frame is factored in. + if (ite >= 2 && cur_mv[!id].as_int == init_mv[!id].as_int) { + if (cur_mv[id].as_int == init_mv[id].as_int) { + break; + } else { + int_mv cur_int_mv, init_int_mv; + cur_int_mv.as_mv.col = cur_mv[id].as_mv.col >> 3; + cur_int_mv.as_mv.row = cur_mv[id].as_mv.row >> 3; + init_int_mv.as_mv.row = init_mv[id].as_mv.row >> 3; + init_int_mv.as_mv.col = init_mv[id].as_mv.col >> 3; + if (cur_int_mv.as_int == init_int_mv.as_int) { + break; + } + } + } + for (ref = 0; ref < 2; ++ref) { + ref_mv[ref] = av1_get_ref_mv(x, ref); + // 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. + if (scaled_ref_frame[ref]) { + int i; + for (i = 0; i < num_planes; i++) + backup_yv12[ref][i] = xd->plane[i].pre[ref]; + av1_setup_pre_planes(xd, ref, scaled_ref_frame[ref], mi_row, mi_col, + NULL, num_planes); + } + } + + assert(IMPLIES(scaled_ref_frame[0] != NULL, + cm->width == scaled_ref_frame[0]->y_crop_width && + cm->height == scaled_ref_frame[0]->y_crop_height)); + assert(IMPLIES(scaled_ref_frame[1] != NULL, + cm->width == scaled_ref_frame[1]->y_crop_width && + cm->height == scaled_ref_frame[1]->y_crop_height)); + + // Initialize based on (possibly scaled) prediction buffers. + ref_yv12[0] = xd->plane[plane].pre[0]; + ref_yv12[1] = xd->plane[plane].pre[1]; + + av1_init_inter_params(&inter_pred_params, pw, ph, mi_row * MI_SIZE, + mi_col * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, + &cm->sf_identity, &ref_yv12[!id], interp_filters); + inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); + + // Since we have scaled the reference frames to match the size of the + // current frame we must use a unit scaling factor during mode selection. + av1_enc_build_one_inter_predictor(second_pred, pw, &cur_mv[!id].as_mv, + &inter_pred_params); + + const int order_idx = id != 0; + av1_dist_wtd_comp_weight_assign( + cm, mbmi, order_idx, &xd->jcp_param.fwd_offset, + &xd->jcp_param.bck_offset, &xd->jcp_param.use_dist_wtd_comp_avg, 1); + + // Do full-pixel compound motion search on the current reference frame. + if (id) xd->plane[plane].pre[0] = ref_yv12[id]; + + // Make motion search params + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, + &ref_mv[id].as_mv, NULL); + av1_set_ms_compound_refs(&full_ms_params.ms_buffers, second_pred, mask, + mask_stride, id); + + // Use the mv result from the single mode as mv predictor. + const FULLPEL_MV start_fullmv = get_fullmv_from_mv(&cur_mv[id].as_mv); + + // Small-range full-pixel motion search. + bestsme = av1_refining_search_8p_c(&full_ms_params, start_fullmv, + &best_mv.as_fullmv); + + if (bestsme < INT_MAX) { + bestsme = av1_get_mvpred_compound_var( + &full_ms_params.mv_cost_params, best_mv.as_fullmv, second_pred, mask, + mask_stride, id, &cpi->fn_ptr[bsize], &x->plane[0].src, + &ref_yv12[id]); + } + + // Restore the pointer to the first (possibly scaled) prediction buffer. + if (id) xd->plane[plane].pre[0] = ref_yv12[0]; + + for (ref = 0; ref < 2; ++ref) { + if (scaled_ref_frame[ref]) { + // Swap back the original buffers for subpel motion search. + for (int i = 0; i < num_planes; i++) { + xd->plane[i].pre[ref] = backup_yv12[ref][i]; + } + // Re-initialize based on unscaled prediction buffers. + ref_yv12[ref] = xd->plane[plane].pre[ref]; + } + } + + // Do sub-pixel compound motion search on the current reference frame. + if (id) xd->plane[plane].pre[0] = ref_yv12[id]; + + if (cpi->common.features.cur_frame_force_integer_mv) { + convert_fullmv_to_mv(&best_mv); + } + if (bestsme < INT_MAX && + cpi->common.features.cur_frame_force_integer_mv == 0) { + int dis; /* TODO: use dis in distortion calculation later. */ + unsigned int sse; + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, + &ref_mv[id].as_mv, NULL); + av1_set_ms_compound_refs(&ms_params.var_params.ms_buffers, second_pred, + mask, mask_stride, id); + ms_params.forced_stop = EIGHTH_PEL; + MV start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + bestsme = cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, start_mv, &best_mv.as_mv, &dis, &sse, NULL); + } + + // Restore the pointer to the first prediction buffer. + if (id) xd->plane[plane].pre[0] = ref_yv12[0]; + if (bestsme < last_besterr[id]) { + cur_mv[id] = best_mv; + last_besterr[id] = bestsme; + } else { + break; + } + } + + *rate_mv = 0; + + for (ref = 0; ref < 2; ++ref) { + const int_mv curr_ref_mv = av1_get_ref_mv(x, ref); + *rate_mv += + av1_mv_bit_cost(&cur_mv[ref].as_mv, &curr_ref_mv.as_mv, x->nmv_vec_cost, + x->mv_cost_stack, MV_COST_WEIGHT); + } +} + +// Search for the best mv for one component of a compound, +// given that the other component is fixed. +void av1_compound_single_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, MV *this_mv, + const uint8_t *second_pred, + const uint8_t *mask, int mask_stride, + int *rate_mv, int ref_idx) { + const AV1_COMMON *const cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + const int ref = mbmi->ref_frame[ref_idx]; + const int_mv ref_mv = av1_get_ref_mv(x, ref_idx); + struct macroblockd_plane *const pd = &xd->plane[0]; + + struct buf_2d backup_yv12[MAX_MB_PLANE]; + const YV12_BUFFER_CONFIG *const scaled_ref_frame = + av1_get_scaled_ref_frame(cpi, ref); + + // Check that this is either an interinter or an interintra block + assert(has_second_ref(mbmi) || (ref_idx == 0 && is_interintra_mode(mbmi))); + + // Store the first prediction buffer. + struct buf_2d orig_yv12; + struct buf_2d ref_yv12 = pd->pre[ref_idx]; + if (ref_idx) { + orig_yv12 = pd->pre[0]; + pd->pre[0] = pd->pre[ref_idx]; + } + + if (scaled_ref_frame) { + // Swap out the reference frame for a version that's been scaled to + // match the resolution of the current frame, allowing the existing + // full-pixel motion search code to be used without additional + // modifications. + for (int i = 0; i < num_planes; i++) { + backup_yv12[i] = xd->plane[i].pre[ref_idx]; + } + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, + num_planes); + } + + int bestsme = INT_MAX; + int_mv best_mv; + + // Make motion search params + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, + &ref_mv.as_mv, NULL); + av1_set_ms_compound_refs(&full_ms_params.ms_buffers, second_pred, mask, + mask_stride, ref_idx); + + // Use the mv result from the single mode as mv predictor. + const FULLPEL_MV start_fullmv = get_fullmv_from_mv(this_mv); + + // Small-range full-pixel motion search. + bestsme = av1_refining_search_8p_c(&full_ms_params, start_fullmv, + &best_mv.as_fullmv); + + if (bestsme < INT_MAX) { + bestsme = av1_get_mvpred_compound_var( + &full_ms_params.mv_cost_params, best_mv.as_fullmv, second_pred, mask, + mask_stride, ref_idx, &cpi->fn_ptr[bsize], &x->plane[0].src, &ref_yv12); + } + + if (scaled_ref_frame) { + // Swap back the original buffers for subpel motion search. + for (int i = 0; i < num_planes; i++) { + xd->plane[i].pre[ref_idx] = backup_yv12[i]; + } + } + + if (cpi->common.features.cur_frame_force_integer_mv) { + convert_fullmv_to_mv(&best_mv); + } + const int use_fractional_mv = + bestsme < INT_MAX && cpi->common.features.cur_frame_force_integer_mv == 0; + if (use_fractional_mv) { + int dis; /* TODO: use dis in distortion calculation later. */ + unsigned int sse; + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv.as_mv, + NULL); + av1_set_ms_compound_refs(&ms_params.var_params.ms_buffers, second_pred, + mask, mask_stride, ref_idx); + ms_params.forced_stop = EIGHTH_PEL; + MV start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + bestsme = cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, start_mv, &best_mv.as_mv, &dis, &sse, NULL); + } + + // Restore the pointer to the first unscaled prediction buffer. + if (ref_idx) pd->pre[0] = orig_yv12; + + if (bestsme < INT_MAX) *this_mv = best_mv.as_mv; + + *rate_mv = 0; + + *rate_mv += av1_mv_bit_cost(this_mv, &ref_mv.as_mv, x->nmv_vec_cost, + x->mv_cost_stack, MV_COST_WEIGHT); +} + +static AOM_INLINE void build_second_inter_pred(const AV1_COMP *cpi, + MACROBLOCK *x, BLOCK_SIZE bsize, + const MV *other_mv, int ref_idx, + uint8_t *second_pred) { + const AV1_COMMON *const cm = &cpi->common; + const int pw = block_size_wide[bsize]; + const int ph = block_size_high[bsize]; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + struct macroblockd_plane *const pd = &xd->plane[0]; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int p_col = ((mi_col * MI_SIZE) >> pd->subsampling_x); + const int p_row = ((mi_row * MI_SIZE) >> pd->subsampling_y); + + // This function should only ever be called for compound modes + assert(has_second_ref(mbmi)); + + const int plane = 0; + struct buf_2d ref_yv12 = xd->plane[plane].pre[!ref_idx]; + + struct scale_factors sf; + av1_setup_scale_factors_for_frame(&sf, ref_yv12.width, ref_yv12.height, + cm->width, cm->height); + + InterPredParams inter_pred_params; + + av1_init_inter_params(&inter_pred_params, pw, ph, p_row, p_col, + pd->subsampling_x, pd->subsampling_y, xd->bd, + is_cur_buf_hbd(xd), 0, &sf, &ref_yv12, + mbmi->interp_filters); + inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); + + // Get the prediction block from the 'other' reference frame. + av1_enc_build_one_inter_predictor(second_pred, pw, other_mv, + &inter_pred_params); + + av1_dist_wtd_comp_weight_assign(cm, mbmi, 0, &xd->jcp_param.fwd_offset, + &xd->jcp_param.bck_offset, + &xd->jcp_param.use_dist_wtd_comp_avg, 1); +} + +// Wrapper for av1_compound_single_motion_search, for the common case +// where the second prediction is also an inter mode. +void av1_compound_single_motion_search_interinter( + const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int_mv *cur_mv, + const uint8_t *mask, int mask_stride, int *rate_mv, int ref_idx) { + MACROBLOCKD *xd = &x->e_mbd; + // This function should only ever be called for compound modes + assert(has_second_ref(xd->mi[0])); + + // Prediction buffer from second frame. + DECLARE_ALIGNED(16, uint16_t, second_pred_alloc_16[MAX_SB_SQUARE]); + uint8_t *second_pred; + if (is_cur_buf_hbd(xd)) + second_pred = CONVERT_TO_BYTEPTR(second_pred_alloc_16); + else + second_pred = (uint8_t *)second_pred_alloc_16; + + MV *this_mv = &cur_mv[ref_idx].as_mv; + const MV *other_mv = &cur_mv[!ref_idx].as_mv; + build_second_inter_pred(cpi, x, bsize, other_mv, ref_idx, second_pred); + av1_compound_single_motion_search(cpi, x, bsize, this_mv, second_pred, mask, + mask_stride, rate_mv, ref_idx); +} + +static AOM_INLINE void do_masked_motion_search_indexed( + const AV1_COMP *const cpi, MACROBLOCK *x, const int_mv *const cur_mv, + const INTERINTER_COMPOUND_DATA *const comp_data, BLOCK_SIZE bsize, + int_mv *tmp_mv, int *rate_mv, int which) { + // NOTE: which values: 0 - 0 only, 1 - 1 only, 2 - both + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + BLOCK_SIZE sb_type = mbmi->sb_type; + const uint8_t *mask; + const int mask_stride = block_size_wide[bsize]; + + mask = av1_get_compound_type_mask(comp_data, sb_type); + + tmp_mv[0].as_int = cur_mv[0].as_int; + tmp_mv[1].as_int = cur_mv[1].as_int; + if (which == 0 || which == 1) { + av1_compound_single_motion_search_interinter(cpi, x, bsize, tmp_mv, mask, + mask_stride, rate_mv, which); + } else if (which == 2) { + av1_joint_motion_search(cpi, x, bsize, tmp_mv, mask, mask_stride, rate_mv); + } +} + +int av1_interinter_compound_motion_search(const AV1_COMP *const cpi, + MACROBLOCK *x, + const int_mv *const cur_mv, + const BLOCK_SIZE bsize, + const PREDICTION_MODE this_mode) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + int_mv tmp_mv[2]; + int tmp_rate_mv = 0; + mbmi->interinter_comp.seg_mask = xd->seg_mask; + const INTERINTER_COMPOUND_DATA *compound_data = &mbmi->interinter_comp; + + if (this_mode == NEW_NEWMV) { + do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize, + tmp_mv, &tmp_rate_mv, 2); + mbmi->mv[0].as_int = tmp_mv[0].as_int; + mbmi->mv[1].as_int = tmp_mv[1].as_int; + } else if (this_mode >= NEAREST_NEWMV && this_mode <= NEW_NEARMV) { + // which = 1 if this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV + // which = 0 if this_mode == NEW_NEARESTMV || this_mode == NEW_NEARMV + int which = (NEWMV == compound_ref1_mode(this_mode)); + do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize, + tmp_mv, &tmp_rate_mv, which); + mbmi->mv[which].as_int = tmp_mv[which].as_int; + } + return tmp_rate_mv; +} + +int_mv av1_simple_motion_search(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, int ref, + FULLPEL_MV start_mv, 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; + mbmi->interp_filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); + + 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 calculate the cost of the motion vector + const MV ref_mv = kZeroMv; + const int step_param = cpi->mv_search_params.mv_step_param; + const search_site_config *src_search_sites = + &cpi->mv_search_params.ss_cfg[SS_CFG_SRC]; + int cost_list[5]; + const int ref_idx = 0; + int var; + int_mv best_mv; + + av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col, + get_ref_scale_factors(cm, ref), num_planes); + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + 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); + } + + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &ref_mv, + src_search_sites); + + var = av1_full_pixel_search(start_mv, &full_ms_params, step_param, + cond_cost_list(cpi, cost_list), + &best_mv.as_fullmv, NULL); + + const int use_subpel_search = + var < INT_MAX && !cpi->common.features.cur_frame_force_integer_mv && + use_subpixel; + if (scaled_ref_frame) { + xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12; + } + if (use_subpel_search) { + int not_used = 0; + + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv, + cost_list); + // TODO(yunqing): integrate this into av1_make_default_subpel_ms_params(). + ms_params.forced_stop = cpi->sf.mv_sf.simple_motion_subpel_force_stop; + + MV subpel_start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + + cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &best_mv.as_mv, ¬_used, + &x->pred_sse[ref], NULL); + } else { + // Manually convert from units of pixel to 1/8-pixels if we are not doing + // subpel search + convert_fullmv_to_mv(&best_mv); + } + + mbmi->mv[0] = best_mv; + + // Get a copy of the prediction output + 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; + } + + return best_mv; +} + +int_mv av1_simple_motion_sse_var(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, + int mi_col, BLOCK_SIZE bsize, + const FULLPEL_MV start_mv, 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; + + int_mv best_mv = av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, + start_mv, 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); + + return best_mv; +} diff --git a/media/libaom/src/av1/encoder/motion_search_facade.h b/media/libaom/src/av1/encoder/motion_search_facade.h new file mode 100644 index 0000000000..3b86e93766 --- /dev/null +++ b/media/libaom/src/av1/encoder/motion_search_facade.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, 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_MOTION_SEARCH_H_ +#define AOM_AV1_ENCODER_MOTION_SEARCH_H_ + +#include "av1/encoder/encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int64_t rd; + int drl_cost; + + int rate_mv; + int_mv mv; + + int_mv full_search_mv; + int full_mv_rate; +} inter_mode_info; + +void av1_single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int ref_idx, int *rate_mv, + int search_range, inter_mode_info *mode_info, + int_mv *best_mv); + +void av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, int_mv *cur_mv, + const uint8_t *mask, int mask_stride, + int *rate_mv); + +int av1_interinter_compound_motion_search(const AV1_COMP *const cpi, + MACROBLOCK *x, + const int_mv *const cur_mv, + const BLOCK_SIZE bsize, + const PREDICTION_MODE this_mode); + +void av1_compound_single_motion_search_interinter( + const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int_mv *cur_mv, + const uint8_t *mask, int mask_stride, int *rate_mv, int ref_idx); + +void av1_compound_single_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, MV *this_mv, + const uint8_t *second_pred, + const uint8_t *mask, int mask_stride, + int *rate_mv, int ref_idx); + +// 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. +int_mv av1_simple_motion_search(struct AV1_COMP *const cpi, MACROBLOCK *x, + int mi_row, int mi_col, BLOCK_SIZE bsize, + int ref, FULLPEL_MV start_mv, int num_planes, + int use_subpixel); + +// Performs a simple motion search to calculate the sse and var of the residue +int_mv av1_simple_motion_sse_var(struct AV1_COMP *cpi, MACROBLOCK *x, + int mi_row, int mi_col, BLOCK_SIZE bsize, + const FULLPEL_MV start_mv, int use_subpixel, + unsigned int *sse, unsigned int *var); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_MOTION_SEARCH_H_ diff --git a/media/libaom/src/av1/encoder/mv_prec.c b/media/libaom/src/av1/encoder/mv_prec.c new file mode 100644 index 0000000000..8fcbde98e0 --- /dev/null +++ b/media/libaom/src/av1/encoder/mv_prec.c @@ -0,0 +1,430 @@ +/* + * 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 "config/aom_config.h" + +#include "aom_ports/system_state.h" + +#include "av1/encoder/encodemv.h" +#if !CONFIG_REALTIME_ONLY +#include "av1/encoder/misc_model_weights.h" +#endif // !CONFIG_REALTIME_ONLY +#include "av1/encoder/mv_prec.h" + +#if !CONFIG_REALTIME_ONLY +static AOM_INLINE int_mv get_ref_mv_for_mv_stats( + const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame, + int ref_idx) { + int ref_mv_idx = mbmi->ref_mv_idx; + if (mbmi->mode == NEAR_NEWMV || mbmi->mode == NEW_NEARMV) { + assert(has_second_ref(mbmi)); + ref_mv_idx += 1; + } + + const MV_REFERENCE_FRAME *ref_frames = mbmi->ref_frame; + const int8_t ref_frame_type = av1_ref_frame_type(ref_frames); + const CANDIDATE_MV *curr_ref_mv_stack = mbmi_ext_frame->ref_mv_stack; + + if (ref_frames[1] > INTRA_FRAME) { + assert(ref_idx == 0 || ref_idx == 1); + return ref_idx ? curr_ref_mv_stack[ref_mv_idx].comp_mv + : curr_ref_mv_stack[ref_mv_idx].this_mv; + } + + assert(ref_idx == 0); + return ref_mv_idx < mbmi_ext_frame->ref_mv_count + ? curr_ref_mv_stack[ref_mv_idx].this_mv + : mbmi_ext_frame->global_mvs[ref_frame_type]; +} + +static AOM_INLINE int get_symbol_cost(const aom_cdf_prob *cdf, int symbol) { + const aom_cdf_prob cur_cdf = AOM_ICDF(cdf[symbol]); + const aom_cdf_prob prev_cdf = symbol ? AOM_ICDF(cdf[symbol - 1]) : 0; + const aom_cdf_prob p15 = AOMMAX(cur_cdf - prev_cdf, EC_MIN_PROB); + + return av1_cost_symbol(p15); +} + +static AOM_INLINE int keep_one_comp_stat(MV_STATS *mv_stats, int comp_val, + int comp_idx, const AV1_COMP *cpi, + int *rates) { + assert(comp_val != 0 && "mv component should not have zero value!"); + const int sign = comp_val < 0; + const int mag = sign ? -comp_val : comp_val; + const int mag_minus_1 = mag - 1; + int offset; + const int mv_class = av1_get_mv_class(mag_minus_1, &offset); + const int int_part = offset >> 3; // int mv data + const int frac_part = (offset >> 1) & 3; // fractional mv data + const int high_part = offset & 1; // high precision mv data + const int use_hp = cpi->common.features.allow_high_precision_mv; + int r_idx = 0; + + const MACROBLOCK *const x = &cpi->td.mb; + const MACROBLOCKD *const xd = &x->e_mbd; + FRAME_CONTEXT *ec_ctx = xd->tile_ctx; + nmv_context *nmvc = &ec_ctx->nmvc; + nmv_component *mvcomp_ctx = nmvc->comps; + nmv_component *cur_mvcomp_ctx = &mvcomp_ctx[comp_idx]; + aom_cdf_prob *sign_cdf = cur_mvcomp_ctx->sign_cdf; + aom_cdf_prob *class_cdf = cur_mvcomp_ctx->classes_cdf; + aom_cdf_prob *class0_cdf = cur_mvcomp_ctx->class0_cdf; + aom_cdf_prob(*bits_cdf)[3] = cur_mvcomp_ctx->bits_cdf; + aom_cdf_prob *frac_part_cdf = mv_class + ? (cur_mvcomp_ctx->fp_cdf) + : (cur_mvcomp_ctx->class0_fp_cdf[int_part]); + aom_cdf_prob *high_part_cdf = + mv_class ? (cur_mvcomp_ctx->hp_cdf) : (cur_mvcomp_ctx->class0_hp_cdf); + + const int sign_rate = get_symbol_cost(sign_cdf, sign); + rates[r_idx++] = sign_rate; + update_cdf(sign_cdf, sign, 2); + + const int class_rate = get_symbol_cost(class_cdf, mv_class); + rates[r_idx++] = class_rate; + update_cdf(class_cdf, mv_class, MV_CLASSES); + + int int_bit_rate = 0; + if (mv_class == MV_CLASS_0) { + int_bit_rate = get_symbol_cost(class0_cdf, int_part); + update_cdf(class0_cdf, int_part, CLASS0_SIZE); + } else { + const int n = mv_class + CLASS0_BITS - 1; // number of bits + for (int i = 0; i < n; ++i) { + int_bit_rate += get_symbol_cost(bits_cdf[i], (int_part >> i) & 1); + update_cdf(bits_cdf[i], (int_part >> i) & 1, 2); + } + } + rates[r_idx++] = int_bit_rate; + const int frac_part_rate = get_symbol_cost(frac_part_cdf, frac_part); + rates[r_idx++] = frac_part_rate; + update_cdf(frac_part_cdf, frac_part, MV_FP_SIZE); + const int high_part_rate = + use_hp ? get_symbol_cost(high_part_cdf, high_part) : 0; + if (use_hp) { + update_cdf(high_part_cdf, high_part, 2); + } + rates[r_idx++] = high_part_rate; + + mv_stats->last_bit_zero += !high_part; + mv_stats->last_bit_nonzero += high_part; + const int total_rate = + (sign_rate + class_rate + int_bit_rate + frac_part_rate + high_part_rate); + return total_rate; +} + +static AOM_INLINE void keep_one_mv_stat(MV_STATS *mv_stats, const MV *ref_mv, + const MV *cur_mv, const AV1_COMP *cpi) { + const MACROBLOCK *const x = &cpi->td.mb; + const MACROBLOCKD *const xd = &x->e_mbd; + FRAME_CONTEXT *ec_ctx = xd->tile_ctx; + nmv_context *nmvc = &ec_ctx->nmvc; + aom_cdf_prob *joint_cdf = nmvc->joints_cdf; + const int use_hp = cpi->common.features.allow_high_precision_mv; + + const MV diff = { cur_mv->row - ref_mv->row, cur_mv->col - ref_mv->col }; + const int mv_joint = av1_get_mv_joint(&diff); + // TODO(chiyotsai@google.com): Estimate hp_diff when we are using lp + const MV hp_diff = diff; + const int hp_mv_joint = av1_get_mv_joint(&hp_diff); + const MV truncated_diff = { (diff.row / 2) * 2, (diff.col / 2) * 2 }; + const MV lp_diff = use_hp ? truncated_diff : diff; + const int lp_mv_joint = av1_get_mv_joint(&lp_diff); + + aom_clear_system_state(); + const int mv_joint_rate = get_symbol_cost(joint_cdf, mv_joint); + const int hp_mv_joint_rate = get_symbol_cost(joint_cdf, hp_mv_joint); + const int lp_mv_joint_rate = get_symbol_cost(joint_cdf, lp_mv_joint); + + update_cdf(joint_cdf, mv_joint, MV_JOINTS); + + mv_stats->total_mv_rate += mv_joint_rate; + mv_stats->hp_total_mv_rate += hp_mv_joint_rate; + mv_stats->lp_total_mv_rate += lp_mv_joint_rate; + mv_stats->mv_joint_count[mv_joint]++; + + for (int comp_idx = 0; comp_idx < 2; comp_idx++) { + const int comp_val = comp_idx ? diff.col : diff.row; + const int hp_comp_val = comp_idx ? hp_diff.col : hp_diff.row; + const int lp_comp_val = comp_idx ? lp_diff.col : lp_diff.row; + int rates[5]; + av1_zero_array(rates, 5); + + const int comp_rate = + comp_val ? keep_one_comp_stat(mv_stats, comp_val, comp_idx, cpi, rates) + : 0; + // TODO(chiyotsai@google.com): Properly get hp rate when use_hp is false + const int hp_rate = + hp_comp_val ? rates[0] + rates[1] + rates[2] + rates[3] + rates[4] : 0; + const int lp_rate = + lp_comp_val ? rates[0] + rates[1] + rates[2] + rates[3] : 0; + + mv_stats->total_mv_rate += comp_rate; + mv_stats->hp_total_mv_rate += hp_rate; + mv_stats->lp_total_mv_rate += lp_rate; + } +} + +static AOM_INLINE void collect_mv_stats_b(MV_STATS *mv_stats, + const AV1_COMP *cpi, int mi_row, + int mi_col) { + const AV1_COMMON *cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) { + return; + } + + const MB_MODE_INFO *mbmi = + mi_params->mi_grid_base[mi_row * mi_params->mi_stride + mi_col]; + const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame = + cpi->mbmi_ext_info.frame_base + + get_mi_ext_idx(mi_row, mi_col, cm->mi_params.mi_alloc_bsize, + cpi->mbmi_ext_info.stride); + + if (!is_inter_block(mbmi)) { + mv_stats->intra_count++; + return; + } + mv_stats->inter_count++; + + const PREDICTION_MODE mode = mbmi->mode; + const int is_compound = has_second_ref(mbmi); + + if (mode == NEWMV || mode == NEW_NEWMV) { + // All mvs are new + for (int ref_idx = 0; ref_idx < 1 + is_compound; ++ref_idx) { + const MV ref_mv = + get_ref_mv_for_mv_stats(mbmi, mbmi_ext_frame, ref_idx).as_mv; + const MV cur_mv = mbmi->mv[ref_idx].as_mv; + keep_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi); + } + } else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV || + mode == NEW_NEARESTMV || mode == NEW_NEARMV) { + // has exactly one new_mv + mv_stats->default_mvs += 1; + + const int ref_idx = (mode == NEAREST_NEWMV || mode == NEAR_NEWMV); + const MV ref_mv = + get_ref_mv_for_mv_stats(mbmi, mbmi_ext_frame, ref_idx).as_mv; + const MV cur_mv = mbmi->mv[ref_idx].as_mv; + + keep_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi); + } else { + // No new_mv + mv_stats->default_mvs += 1 + is_compound; + } + + // Add texture information + const BLOCK_SIZE bsize = mbmi->sb_type; + const int num_rows = block_size_high[bsize]; + const int num_cols = block_size_wide[bsize]; + const int y_stride = cpi->source->y_stride; + const int px_row = 4 * mi_row, px_col = 4 * mi_col; + const int buf_is_hbd = cpi->source->flags & YV12_FLAG_HIGHBITDEPTH; + const int bd = cm->seq_params.bit_depth; + if (buf_is_hbd) { + uint16_t *source_buf = + CONVERT_TO_SHORTPTR(cpi->source->y_buffer) + px_row * y_stride + px_col; + for (int row = 0; row < num_rows - 1; row++) { + for (int col = 0; col < num_cols - 1; col++) { + const int offset = row * y_stride + col; + const int horz_diff = + abs(source_buf[offset + 1] - source_buf[offset]) >> (bd - 8); + const int vert_diff = + abs(source_buf[offset + y_stride] - source_buf[offset]) >> (bd - 8); + mv_stats->horz_text += horz_diff; + mv_stats->vert_text += vert_diff; + mv_stats->diag_text += horz_diff * vert_diff; + } + } + } else { + uint8_t *source_buf = cpi->source->y_buffer + px_row * y_stride + px_col; + for (int row = 0; row < num_rows - 1; row++) { + for (int col = 0; col < num_cols - 1; col++) { + const int offset = row * y_stride + col; + const int horz_diff = abs(source_buf[offset + 1] - source_buf[offset]); + const int vert_diff = + abs(source_buf[offset + y_stride] - source_buf[offset]); + mv_stats->horz_text += horz_diff; + mv_stats->vert_text += vert_diff; + mv_stats->diag_text += horz_diff * vert_diff; + } + } + } +} + +// Split block +static AOM_INLINE void collect_mv_stats_sb(MV_STATS *mv_stats, + const AV1_COMP *cpi, int mi_row, + int mi_col, BLOCK_SIZE bsize) { + assert(bsize < BLOCK_SIZES_ALL); + const AV1_COMMON *cm = &cpi->common; + + if (mi_row >= cm->mi_params.mi_rows || mi_col >= cm->mi_params.mi_cols) + return; + + const PARTITION_TYPE partition = get_partition(cm, mi_row, mi_col, bsize); + const BLOCK_SIZE subsize = get_partition_subsize(bsize, partition); + + const int hbs = mi_size_wide[bsize] / 2; + const int qbs = mi_size_wide[bsize] / 4; + switch (partition) { + case PARTITION_NONE: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + break; + case PARTITION_HORZ: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col); + break; + case PARTITION_VERT: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs); + break; + case PARTITION_SPLIT: + collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize); + collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + hbs, subsize); + collect_mv_stats_sb(mv_stats, cpi, mi_row + hbs, mi_col, subsize); + collect_mv_stats_sb(mv_stats, cpi, mi_row + hbs, mi_col + hbs, subsize); + break; + case PARTITION_HORZ_A: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col); + break; + case PARTITION_HORZ_B: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col + hbs); + break; + case PARTITION_VERT_A: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs); + break; + case PARTITION_VERT_B: + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); + collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs); + collect_mv_stats_b(mv_stats, cpi, mi_row + hbs, mi_col + hbs); + break; + case PARTITION_HORZ_4: + for (int i = 0; i < 4; ++i) { + const int this_mi_row = mi_row + i * qbs; + collect_mv_stats_b(mv_stats, cpi, this_mi_row, mi_col); + } + break; + case PARTITION_VERT_4: + for (int i = 0; i < 4; ++i) { + const int this_mi_col = mi_col + i * qbs; + collect_mv_stats_b(mv_stats, cpi, mi_row, this_mi_col); + } + break; + default: assert(0); + } +} + +static AOM_INLINE void collect_mv_stats_tile(MV_STATS *mv_stats, + const AV1_COMP *cpi, + const TileInfo *tile_info) { + const AV1_COMMON *cm = &cpi->common; + const int mi_row_start = tile_info->mi_row_start; + const int mi_row_end = tile_info->mi_row_end; + const int mi_col_start = tile_info->mi_col_start; + const int mi_col_end = tile_info->mi_col_end; + const int sb_size_mi = cm->seq_params.mib_size; + BLOCK_SIZE sb_size = cm->seq_params.sb_size; + for (int mi_row = mi_row_start; mi_row < mi_row_end; mi_row += sb_size_mi) { + for (int mi_col = mi_col_start; mi_col < mi_col_end; mi_col += sb_size_mi) { + collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, sb_size); + } + } +} + +void av1_collect_mv_stats(AV1_COMP *cpi, int current_q) { + MV_STATS *mv_stats = &cpi->mv_stats; + const AV1_COMMON *cm = &cpi->common; + const int tile_cols = cm->tiles.cols; + const int tile_rows = cm->tiles.rows; + + for (int tile_row = 0; tile_row < tile_rows; tile_row++) { + TileInfo tile_info; + av1_tile_set_row(&tile_info, cm, tile_row); + for (int tile_col = 0; tile_col < tile_cols; tile_col++) { + const int tile_idx = tile_row * tile_cols + tile_col; + av1_tile_set_col(&tile_info, cm, tile_col); + cpi->tile_data[tile_idx].tctx = *cm->fc; + cpi->td.mb.e_mbd.tile_ctx = &cpi->tile_data[tile_idx].tctx; + collect_mv_stats_tile(mv_stats, cpi, &tile_info); + } + } + + mv_stats->q = current_q; + mv_stats->order = cpi->common.current_frame.order_hint; + mv_stats->valid = 1; +} + +static AOM_INLINE int get_smart_mv_prec(AV1_COMP *cpi, const MV_STATS *mv_stats, + int current_q) { + const AV1_COMMON *cm = &cpi->common; + const int order_hint = cpi->common.current_frame.order_hint; + const int order_diff = order_hint - mv_stats->order; + aom_clear_system_state(); + const float area = (float)(cm->width * cm->height); + float features[MV_PREC_FEATURE_SIZE] = { + (float)current_q, + (float)mv_stats->q, + (float)order_diff, + mv_stats->inter_count / area, + mv_stats->intra_count / area, + mv_stats->default_mvs / area, + mv_stats->mv_joint_count[0] / area, + mv_stats->mv_joint_count[1] / area, + mv_stats->mv_joint_count[2] / area, + mv_stats->mv_joint_count[3] / area, + mv_stats->last_bit_zero / area, + mv_stats->last_bit_nonzero / area, + mv_stats->total_mv_rate / area, + mv_stats->hp_total_mv_rate / area, + mv_stats->lp_total_mv_rate / area, + mv_stats->horz_text / area, + mv_stats->vert_text / area, + mv_stats->diag_text / area, + }; + + for (int f_idx = 0; f_idx < MV_PREC_FEATURE_SIZE; f_idx++) { + features[f_idx] = + (features[f_idx] - av1_mv_prec_mean[f_idx]) / av1_mv_prec_std[f_idx]; + } + float score = 0.0f; + + av1_nn_predict(features, &av1_mv_prec_dnn_config, 1, &score); + + const int use_high_hp = score >= 0.0f; + return use_high_hp; +} +#endif // !CONFIG_REALTIME_ONLY + +void av1_pick_and_set_high_precision_mv(AV1_COMP *cpi, int qindex) { + int use_hp = qindex < HIGH_PRECISION_MV_QTHRESH; + + if (cpi->sf.hl_sf.high_precision_mv_usage == QTR_ONLY) { + use_hp = 0; + } +#if !CONFIG_REALTIME_ONLY + else if (cpi->sf.hl_sf.high_precision_mv_usage == LAST_MV_DATA && + av1_frame_allows_smart_mv(cpi) && cpi->mv_stats.valid) { + use_hp = get_smart_mv_prec(cpi, &cpi->mv_stats, qindex); + } +#endif // !CONFIG_REALTIME_ONLY + + av1_set_high_precision_mv(cpi, use_hp, + cpi->common.features.cur_frame_force_integer_mv); +} diff --git a/media/libaom/src/av1/encoder/mv_prec.h b/media/libaom/src/av1/encoder/mv_prec.h new file mode 100644 index 0000000000..8df8b96dc6 --- /dev/null +++ b/media/libaom/src/av1/encoder/mv_prec.h @@ -0,0 +1,48 @@ +/* + * 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_MV_PREC_H_ +#define AOM_AV1_ENCODER_MV_PREC_H_ + +#include "av1/encoder/encoder.h" +#include "av1/encoder/speed_features.h" + +// Q threshold for high precision mv. +#define HIGH_PRECISION_MV_QTHRESH 128 +#if !CONFIG_REALTIME_ONLY +void av1_collect_mv_stats(AV1_COMP *cpi, int current_q); + +static AOM_INLINE int av1_frame_allows_smart_mv(const AV1_COMP *cpi) { + const int gf_group_index = cpi->gf_group.index; + const int gf_update_type = cpi->gf_group.update_type[gf_group_index]; + return !frame_is_intra_only(&cpi->common) && + !(gf_update_type == INTNL_OVERLAY_UPDATE || + gf_update_type == OVERLAY_UPDATE); +} +#endif // !CONFIG_REALTIME_ONLY + +static AOM_INLINE void av1_set_high_precision_mv( + AV1_COMP *cpi, int allow_high_precision_mv, + int cur_frame_force_integer_mv) { + MACROBLOCK *const x = &cpi->td.mb; + const int copy_hp = cpi->common.features.allow_high_precision_mv = + allow_high_precision_mv && !cur_frame_force_integer_mv; + x->nmvcost[0] = &x->nmv_costs[0][MV_MAX]; + x->nmvcost[1] = &x->nmv_costs[1][MV_MAX]; + x->nmvcost_hp[0] = &x->nmv_costs_hp[0][MV_MAX]; + x->nmvcost_hp[1] = &x->nmv_costs_hp[1][MV_MAX]; + int *(*src)[2] = copy_hp ? &x->nmvcost_hp : &x->nmvcost; + x->mv_cost_stack = *src; +} + +void av1_pick_and_set_high_precision_mv(AV1_COMP *cpi, int qindex); + +#endif // AOM_AV1_ENCODER_MV_PREC_H_ diff --git a/media/libaom/src/av1/encoder/nonrd_pickmode.c b/media/libaom/src/av1/encoder/nonrd_pickmode.c index 4c5e740138..a1180015c7 100644 --- a/media/libaom/src/av1/encoder/nonrd_pickmode.c +++ b/media/libaom/src/av1/encoder/nonrd_pickmode.c @@ -25,6 +25,7 @@ #include "aom_ports/mem.h" #include "aom_ports/system_state.h" +#include "av1/encoder/model_rd.h" #include "av1/common/mvref_common.h" #include "av1/common/pred_common.h" #include "av1/common/reconinter.h" @@ -57,6 +58,10 @@ typedef struct { PREDICTION_MODE pred_mode; } REF_MODE; +static const int pos_shift_16x16[4][4] = { + { 9, 10, 13, 14 }, { 11, 12, 15, 16 }, { 17, 18, 21, 22 }, { 19, 20, 23, 24 } +}; + #define RT_INTER_MODES 9 static const REF_MODE ref_mode_set[RT_INTER_MODES] = { { LAST_FRAME, NEARESTMV }, { LAST_FRAME, NEARMV }, @@ -91,11 +96,6 @@ static INLINE int mode_offset(const PREDICTION_MODE mode) { } } -typedef struct { - PREDICTION_MODE mode; - MV_REFERENCE_FRAME ref_frame[2]; -} MODE_DEFINITION; - enum { // INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << NEWMV), INTER_NEAREST = (1 << NEARESTMV), @@ -124,14 +124,12 @@ static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x, const int num_planes = av1_num_planes(cm); MB_MODE_INFO *mi = xd->mi[0]; struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } }; - int step_param = cpi->mv_step_param; - const int sadpb = x->sadperbit16; - MV mvp_full; + int step_param = cpi->mv_search_params.mv_step_param; + FULLPEL_MV start_mv; const int ref = mi->ref_frame[0]; const MV ref_mv = av1_get_ref_mv(x, mi->ref_mv_idx).as_mv; MV center_mv; int dis; - const MvLimits tmp_mv_limits = x->mv_limits; int rv = 0; int cost_list[5]; int search_subpel = 1; @@ -147,28 +145,26 @@ static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x, av1_setup_pre_planes(xd, 0, scaled_ref_frame, mi_row, mi_col, NULL, num_planes); } - av1_set_mv_search_range(&x->mv_limits, &ref_mv); - mvp_full = ref_mv; - - mvp_full.col >>= 3; - mvp_full.row >>= 3; + start_mv = get_fullmv_from_mv(&ref_mv); if (!use_base_mv) center_mv = ref_mv; else center_mv = tmp_mv->as_mv; - av1_full_pixel_search( - cpi, x, bsize, &mvp_full, step_param, cpi->sf.mv.search_method, 0, sadpb, - cond_cost_list(cpi, cost_list), ¢er_mv, INT_MAX, 0, - (MI_SIZE * mi_col), (MI_SIZE * mi_row), 0, &cpi->ss_cfg[SS_CFG_SRC], 0); + const search_site_config *src_search_sites = + &cpi->mv_search_params.ss_cfg[SS_CFG_SRC]; + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, ¢er_mv, + src_search_sites); + + av1_full_pixel_search(start_mv, &full_ms_params, step_param, + cond_cost_list(cpi, cost_list), &tmp_mv->as_fullmv, + NULL); - x->mv_limits = tmp_mv_limits; - *tmp_mv = x->best_mv; // calculate the bit cost on motion vector - mvp_full.row = tmp_mv->as_mv.row * 8; - mvp_full.col = tmp_mv->as_mv.col * 8; + MV mvp_full = get_mv_from_fullmv(&tmp_mv->as_fullmv); *rate_mv = av1_mv_bit_cost(&mvp_full, &ref_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT); @@ -177,14 +173,14 @@ static int combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x, rv = !(RDCOST(x->rdmult, (*rate_mv), 0) > best_rd_sofar); if (rv && search_subpel) { - SUBPEL_FORCE_STOP subpel_force_stop = cpi->sf.mv.subpel_force_stop; - cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &ref_mv, cpi->common.allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[bsize], subpel_force_stop, - cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list), - x->nmv_vec_cost, x->mv_cost_stack, &dis, &x->pred_sse[ref], NULL, NULL, - 0, 0, 0, 0, 0, 1); - *tmp_mv = x->best_mv; + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv, + cost_list); + MV subpel_start_mv = get_mv_from_fullmv(&tmp_mv->as_fullmv); + cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &tmp_mv->as_mv, &dis, + &x->pred_sse[ref], NULL); + *rate_mv = av1_mv_bit_cost(&tmp_mv->as_mv, &ref_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT); } @@ -200,12 +196,10 @@ static int search_new_mv(AV1_COMP *cpi, MACROBLOCK *x, int_mv frame_mv[][REF_FRAMES], MV_REFERENCE_FRAME ref_frame, int gf_temporal_ref, BLOCK_SIZE bsize, int mi_row, int mi_col, - int best_pred_sad, int *rate_mv, - int64_t best_sse_sofar, RD_STATS *best_rdc) { + int best_pred_sad, int *rate_mv, RD_STATS *best_rdc) { MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mi = xd->mi[0]; AV1_COMMON *cm = &cpi->common; - (void)best_sse_sofar; if (ref_frame > LAST_FRAME && gf_temporal_ref && cpi->oxcf.rc_mode == AOM_CBR) { int tmp_sad; @@ -222,9 +216,9 @@ static int search_new_mv(AV1_COMP *cpi, MACROBLOCK *x, if (tmp_sad + (num_pels_log2_lookup[bsize] << 4) > best_pred_sad) return -1; frame_mv[NEWMV][ref_frame].as_int = mi->mv[0].as_int; - x->best_mv.as_int = mi->mv[0].as_int; - x->best_mv.as_mv.row >>= 3; - x->best_mv.as_mv.col >>= 3; + int_mv best_mv = mi->mv[0]; + best_mv.as_mv.row >>= 3; + best_mv.as_mv.col >>= 3; MV ref_mv = av1_get_ref_mv(x, 0).as_mv; *rate_mv = @@ -233,13 +227,14 @@ static int search_new_mv(AV1_COMP *cpi, MACROBLOCK *x, frame_mv[NEWMV][ref_frame].as_mv.row >>= 3; frame_mv[NEWMV][ref_frame].as_mv.col >>= 3; - 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, &dis, &x->pred_sse[ref_frame], NULL, - NULL, 0, 0, 0, 0, 0, 1); - frame_mv[NEWMV][ref_frame].as_int = x->best_mv.as_int; + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv, + cost_list); + MV start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, start_mv, &best_mv.as_mv, &dis, + &x->pred_sse[ref_frame], NULL); + frame_mv[NEWMV][ref_frame].as_int = best_mv.as_int; } else if (!combined_motion_search(cpi, x, bsize, mi_row, mi_col, &frame_mv[NEWMV][ref_frame], rate_mv, best_rdc->rdcost, 0)) { @@ -251,10 +246,10 @@ static int search_new_mv(AV1_COMP *cpi, MACROBLOCK *x, static INLINE void find_predictors( AV1_COMP *cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame, - int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES], int const_motion[REF_FRAMES], - int *ref_frame_skip_mask, const int flag_list[4], TileDataEnc *tile_data, - int mi_row, int mi_col, struct buf_2d yv12_mb[8][MAX_MB_PLANE], - BLOCK_SIZE bsize, int force_skip_low_temp_var, int comp_pred_allowed) { + int_mv frame_mv[MB_MODE_COUNT][REF_FRAMES], int *ref_frame_skip_mask, + const int flag_list[4], TileDataEnc *tile_data, + struct buf_2d yv12_mb[8][MAX_MB_PLANE], BLOCK_SIZE bsize, + int force_skip_low_temp_var) { AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; @@ -262,8 +257,6 @@ static INLINE void find_predictors( const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref_frame); const int num_planes = av1_num_planes(cm); (void)tile_data; - (void)const_motion; - (void)comp_pred_allowed; x->pred_mv_sad[ref_frame] = INT_MAX; frame_mv[NEWMV][ref_frame].as_int = INVALID_MV; @@ -271,27 +264,26 @@ static INLINE void find_predictors( if ((cpi->ref_frame_flags & flag_list[ref_frame]) && (yv12 != NULL)) { const struct scale_factors *const sf = get_ref_scale_factors_const(cm, ref_frame); - av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf, - num_planes); + av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, sf, sf, num_planes); av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs, - mi_row, mi_col, mbmi_ext->mode_context); + mbmi_ext->mode_context); // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs. av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame); - av1_find_best_ref_mvs_from_stack(cm->allow_high_precision_mv, mbmi_ext, - ref_frame, &frame_mv[NEARESTMV][ref_frame], - &frame_mv[NEARMV][ref_frame], 0); - // Early exit for golden frame if force_skip_low_temp_var is set. + av1_find_best_ref_mvs_from_stack( + cm->features.allow_high_precision_mv, mbmi_ext, ref_frame, + &frame_mv[NEARESTMV][ref_frame], &frame_mv[NEARMV][ref_frame], 0); + // Early exit for non-LAST frame if force_skip_low_temp_var is set. if (!av1_is_scaled(sf) && bsize >= BLOCK_8X8 && - !(force_skip_low_temp_var && ref_frame == GOLDEN_FRAME)) { + !(force_skip_low_temp_var && ref_frame != LAST_FRAME)) { av1_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride, ref_frame, bsize); } } else { *ref_frame_skip_mask |= (1 << ref_frame); } - av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); + av1_count_overlappable_neighbors(cm, xd); mbmi->num_proj_ref = 1; } @@ -452,61 +444,15 @@ static void estimate_comp_ref_frame_costs( } } -static void model_rd_with_curvfit(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, int *rate, - int64_t *dist) { - (void)cpi; - (void)plane_bsize; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int qstep = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1); - - if (sse == 0) { - if (rate) *rate = 0; - if (dist) *dist = 0; - return; - } - aom_clear_system_state(); - const double sse_norm = (double)sse / num_samples; - const double qstepsqr = (double)qstep * qstep; - 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, - &dist_by_sse_norm_f); - // 9.0 gives the best quality gain on a test video - // but it likely shall be qstep dependent - if (rate_f < 9.0) rate_f = 0.0; - const double dist_f = dist_by_sse_norm_f * sse_norm; - int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5); - int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5); - aom_clear_system_state(); - - // Check if skip is better - if (rate_i == 0) { - dist_i = sse << 4; - } else if (RDCOST(x->rdmult, rate_i, dist_i) >= - RDCOST(x->rdmult, 0, sse << 4)) { - rate_i = 0; - dist_i = sse << 4; - } - - if (rate) *rate = rate_i; - if (dist) *dist = dist_i; -} - static TX_SIZE calculate_tx_size(const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *const x, unsigned int var, unsigned int sse) { MACROBLOCKD *const xd = &x->e_mbd; TX_SIZE tx_size; - if (x->tx_mode == TX_MODE_SELECT) { + if (x->tx_mode_search_type == TX_MODE_SELECT) { if (sse > (var << 2)) tx_size = AOMMIN(max_txsize_lookup[bsize], - tx_mode_to_biggest_tx_size[x->tx_mode]); + tx_mode_to_biggest_tx_size[x->tx_mode_search_type]); else tx_size = TX_8X8; @@ -517,9 +463,12 @@ static TX_SIZE calculate_tx_size(const AV1_COMP *const cpi, BLOCK_SIZE bsize, tx_size = TX_16X16; } else { tx_size = AOMMIN(max_txsize_lookup[bsize], - tx_mode_to_biggest_tx_size[x->tx_mode]); + tx_mode_to_biggest_tx_size[x->tx_mode_search_type]); } - if (bsize > BLOCK_32X32) tx_size = TX_16X16; + + if (x->tx_mode_search_type != ONLY_4X4 && bsize > BLOCK_32X32) + tx_size = TX_16X16; + return AOMMIN(tx_size, TX_16X16); } @@ -588,10 +537,11 @@ static int ac_thr_factor(const int speed, const int width, const int height, } static void model_skip_for_sb_y_large(AV1_COMP *cpi, BLOCK_SIZE bsize, - MACROBLOCK *x, MACROBLOCKD *xd, - int *out_rate, int64_t *out_dist, - unsigned int *var_y, unsigned int *sse_y, - int *early_term, int calculate_rd) { + int mi_row, int mi_col, MACROBLOCK *x, + MACROBLOCKD *xd, int *out_rate, + int64_t *out_dist, unsigned int *var_y, + unsigned int *sse_y, int *early_term, + int calculate_rd) { // Note our transform coeffs are 8 times an orthogonal transform. // Hence quantizer step is also 8 times. To get effective quantizer // we need to divide by 8 before sending to modeling function. @@ -680,7 +630,40 @@ static void model_skip_for_sb_y_large(AV1_COMP *cpi, BLOCK_SIZE bsize, } if (ac_test && dc_test) { - *early_term = 1; + int skip_uv[2] = { 0 }; + unsigned int var_uv[2]; + unsigned int sse_uv[2]; + AV1_COMMON *const cm = &cpi->common; + // Transform skipping test in UV planes. + for (int i = 1; i <= 2; i++) { + int j = i - 1; + skip_uv[j] = 1; + if (x->color_sensitivity[j]) { + skip_uv[j] = 0; + struct macroblock_plane *const puv = &x->plane[i]; + struct macroblockd_plane *const puvd = &xd->plane[i]; + const BLOCK_SIZE uv_bsize = get_plane_block_size( + bsize, puvd->subsampling_x, puvd->subsampling_y); + // Adjust these thresholds for UV. + const int64_t uv_dc_thr = + (puv->dequant_QTX[0] * puv->dequant_QTX[0]) >> 3; + const int64_t uv_ac_thr = + (puv->dequant_QTX[1] * puv->dequant_QTX[1]) >> 3; + av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, i, + i); + var_uv[j] = cpi->fn_ptr[uv_bsize].vf(puv->src.buf, puv->src.stride, + puvd->dst.buf, puvd->dst.stride, + &sse_uv[j]); + if ((var_uv[j] < uv_ac_thr || var_uv[j] == 0) && + (sse_uv[j] - var_uv[j] < uv_dc_thr || sse_uv[j] == var_uv[j])) + skip_uv[j] = 1; + else + break; + } + } + if (skip_uv[0] & skip_uv[1]) { + *early_term = 1; + } } } if (calculate_rd && out_dist != NULL && out_rate != NULL) { @@ -694,7 +677,7 @@ static void model_skip_for_sb_y_large(AV1_COMP *cpi, BLOCK_SIZE bsize, if (*early_term) { *out_rate = 0; - *out_dist = (sse - var) << 4; + *out_dist = sse << 4; } } } @@ -762,14 +745,24 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, const int bw = 4 * num_4x4_w; const int bh = 4 * num_4x4_h; - assert(tx_size > 0 && tx_size <= 4); - (void)mi_row; (void)mi_col; (void)cpi; +#if CONFIG_AV1_HIGHBITDEPTH + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { + aom_highbd_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, + p->src.stride, pd->dst.buf, pd->dst.stride, + x->e_mbd.bd); + } else { + aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, + pd->dst.buf, pd->dst.stride); + } +#else aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride); +#endif + *skippable = 1; // Keep track of the row and column of the blocks we use so that we know // if we are in the unrestricted motion border. @@ -778,9 +771,15 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, if (c < max_blocks_wide) { const SCAN_ORDER *const scan_order = &av1_default_scan_orders[tx_size]; const int block_offset = BLOCK_OFFSET(block); +#if CONFIG_AV1_HIGHBITDEPTH tran_low_t *const coeff = p->coeff + block_offset; tran_low_t *const qcoeff = p->qcoeff + block_offset; tran_low_t *const dqcoeff = pd->dqcoeff + block_offset; +#else + int16_t *const low_coeff = (int16_t *)p->coeff + block_offset; + int16_t *const low_qcoeff = (int16_t *)p->qcoeff + block_offset; + int16_t *const low_dqcoeff = (int16_t *)pd->dqcoeff + block_offset; +#endif uint16_t *const eob = &p->eobs[block]; const int diff_stride = bw; const int16_t *src_diff; @@ -791,12 +790,9 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, assert(0); // Not implemented break; case TX_32X32: - aom_hadamard_32x32(src_diff, diff_stride, coeff); - av1_quantize_fp(coeff, 32 * 32, p->zbin_QTX, p->round_fp_QTX, - p->quant_fp_QTX, p->quant_shift_QTX, qcoeff, - dqcoeff, p->dequant_QTX, eob, scan_order->scan, - scan_order->iscan); + assert(0); // Not used break; +#if CONFIG_AV1_HIGHBITDEPTH case TX_16X16: aom_hadamard_16x16(src_diff, diff_stride, coeff); av1_quantize_fp(coeff, 16 * 16, p->zbin_QTX, p->round_fp_QTX, @@ -811,7 +807,27 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, dqcoeff, p->dequant_QTX, eob, scan_order->scan, scan_order->iscan); break; - default: assert(0); break; +#else + case TX_16X16: + aom_hadamard_lp_16x16(src_diff, diff_stride, low_coeff); + av1_quantize_lp(low_coeff, 16 * 16, p->round_fp_QTX, + p->quant_fp_QTX, low_qcoeff, low_dqcoeff, + p->dequant_QTX, eob, scan_order->scan); + break; + case TX_8X8: + aom_hadamard_lp_8x8(src_diff, diff_stride, low_coeff); + av1_quantize_lp(low_coeff, 8 * 8, p->round_fp_QTX, p->quant_fp_QTX, + low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, + scan_order->scan); + break; + default: + assert(tx_size == TX_4X4); + x->fwd_txfm4x4(src_diff, low_coeff, diff_stride); + av1_quantize_lp(low_coeff, 4 * 4, p->round_fp_QTX, p->quant_fp_QTX, + low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, + scan_order->scan); + break; +#endif } *skippable &= (*eob == 0); eob_cost += 1; @@ -834,12 +850,13 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, for (int r = 0; r < max_blocks_high; r += block_step) { for (int c = 0; c < num_4x4_w; c += block_step) { if (c < max_blocks_wide) { - int64_t dummy; const int block_offset = BLOCK_OFFSET(block); + uint16_t *const eob = &p->eobs[block]; +#if CONFIG_AV1_HIGHBITDEPTH + int64_t dummy; tran_low_t *const coeff = p->coeff + block_offset; tran_low_t *const qcoeff = p->qcoeff + block_offset; tran_low_t *const dqcoeff = pd->dqcoeff + block_offset; - uint16_t *const eob = &p->eobs[block]; if (*eob == 1) this_rdc->rate += (int)abs(qcoeff[0]); @@ -848,6 +865,19 @@ static void block_yrd(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, this_rdc->dist += av1_block_error(coeff, dqcoeff, step << 4, &dummy) >> 2; +#else + int16_t *const low_coeff = (int16_t *)p->coeff + block_offset; + int16_t *const low_qcoeff = (int16_t *)p->qcoeff + block_offset; + int16_t *const low_dqcoeff = (int16_t *)pd->dqcoeff + block_offset; + + if (*eob == 1) + this_rdc->rate += (int)abs(low_qcoeff[0]); + else if (*eob > 1) + this_rdc->rate += aom_satd_lp(low_qcoeff, step << 4); + + this_rdc->dist += + av1_block_error_lp(low_coeff, low_dqcoeff, step << 4) >> 2; +#endif } block += step; } @@ -875,7 +905,7 @@ static INLINE void init_mbmi(MB_MODE_INFO *mbmi, PREDICTION_MODE pred_mode, mbmi->motion_mode = SIMPLE_TRANSLATION; mbmi->num_proj_ref = 1; mbmi->interintra_mode = 0; - set_default_interp_filters(mbmi, cm->interp_filter); + set_default_interp_filters(mbmi, cm->features.interp_filter); } #if CONFIG_INTERNAL_STATS @@ -888,15 +918,18 @@ static void store_coding_context(MACROBLOCK *x, PICK_MODE_CONTEXT *ctx) { // Take a snapshot of the coding context so it can be // restored if we decide to encode this way - ctx->rd_stats.skip = x->skip; - memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - ctx->skippable = x->skip; + ctx->rd_stats.skip = x->force_skip; + memset(ctx->blk_skip, 0, sizeof(ctx->blk_skip[0]) * ctx->num_4x4_blk); + memset(ctx->tx_type_map, DCT_DCT, + sizeof(ctx->tx_type_map[0]) * ctx->num_4x4_blk); + ctx->skippable = x->force_skip; #if CONFIG_INTERNAL_STATS ctx->best_mode_index = mode_index; #endif // CONFIG_INTERNAL_STATS ctx->mic = *xd->mi[0]; - ctx->mbmi_ext = *x->mbmi_ext; + ctx->skippable = x->force_skip; + av1_copy_mbmi_ext_to_mbmi_ext_frame(&ctx->mbmi_ext_best, x->mbmi_ext, + av1_ref_frame_type(xd->mi[0]->ref_frame)); ctx->comp_pred_diff = 0; ctx->hybrid_pred_diff = 0; ctx->single_pred_diff = 0; @@ -949,7 +982,7 @@ static int cost_mv_ref(const MACROBLOCK *const x, PREDICTION_MODE mode, static void newmv_diff_bias(MACROBLOCKD *xd, PREDICTION_MODE this_mode, RD_STATS *this_rdc, BLOCK_SIZE bsize, int mv_row, - int mv_col) { + int mv_col, int speed, uint32_t spatial_variance) { // Bias against MVs associated with NEWMV mode that are very different from // top/left neighbors. if (this_mode == NEWMV) { @@ -986,12 +1019,17 @@ static void newmv_diff_bias(MACROBLOCKD *xd, PREDICTION_MODE this_mode, } row_diff = al_mv_average_row - mv_row; col_diff = al_mv_average_col - mv_col; - if (row_diff > 48 || row_diff < -48 || col_diff > 48 || col_diff < -48) { - if (bsize > BLOCK_32X32) + if (row_diff > 80 || row_diff < -80 || col_diff > 80 || col_diff < -80) { + if (bsize >= BLOCK_32X32) this_rdc->rdcost = this_rdc->rdcost << 1; else this_rdc->rdcost = 5 * this_rdc->rdcost >> 2; } + } else { + // Bias for speed >= 8 for low spatial variance. + if (speed >= 8 && spatial_variance < 150 && + (mv_row > 64 || mv_row < -64 || mv_col > 64 || mv_col < -64)) + this_rdc->rdcost = 5 * this_rdc->rdcost >> 2; } } @@ -1116,60 +1154,129 @@ static INLINE void update_thresh_freq_fact(AV1_COMP *cpi, MACROBLOCK *x, if (thr_mode_idx == best_mode_idx) { *freq_fact -= (*freq_fact >> 4); } else { - *freq_fact = AOMMIN(*freq_fact + RD_THRESH_INC, - cpi->sf.adaptive_rd_thresh * RD_THRESH_MAX_FACT); + *freq_fact = + AOMMIN(*freq_fact + RD_THRESH_INC, + cpi->sf.inter_sf.adaptive_rd_thresh * RD_THRESH_MAX_FACT); } } +static INLINE int get_force_skip_low_temp_var_small_sb(uint8_t *variance_low, + int mi_row, int mi_col, + BLOCK_SIZE bsize) { + // Relative indices of MB inside the superblock. + const int mi_x = mi_row & 0xF; + const int mi_y = mi_col & 0xF; + // Relative indices of 16x16 block inside the superblock. + const int i = mi_x >> 2; + const int j = mi_y >> 2; + int force_skip_low_temp_var = 0; + // Set force_skip_low_temp_var based on the block size and block offset. + switch (bsize) { + case BLOCK_64X64: force_skip_low_temp_var = variance_low[0]; break; + case BLOCK_64X32: + if (!mi_y && !mi_x) { + force_skip_low_temp_var = variance_low[1]; + } else if (!mi_y && mi_x) { + force_skip_low_temp_var = variance_low[2]; + } + break; + case BLOCK_32X64: + if (!mi_y && !mi_x) { + force_skip_low_temp_var = variance_low[3]; + } else if (mi_y && !mi_x) { + force_skip_low_temp_var = variance_low[4]; + } + break; + case BLOCK_32X32: + if (!mi_y && !mi_x) { + force_skip_low_temp_var = variance_low[5]; + } else if (mi_y && !mi_x) { + force_skip_low_temp_var = variance_low[6]; + } else if (!mi_y && mi_x) { + force_skip_low_temp_var = variance_low[7]; + } else if (mi_y && mi_x) { + force_skip_low_temp_var = variance_low[8]; + } + break; + case BLOCK_32X16: + case BLOCK_16X32: + case BLOCK_16X16: + force_skip_low_temp_var = variance_low[pos_shift_16x16[i][j]]; + break; + default: break; + } + + return force_skip_low_temp_var; +} + static INLINE int get_force_skip_low_temp_var(uint8_t *variance_low, int mi_row, int mi_col, BLOCK_SIZE bsize) { int force_skip_low_temp_var = 0; int x, y; + x = (mi_col & 0x1F) >> 4; + // y = (mi_row & 0x1F) >> 4; + // const int idx64 = (y << 1) + x; + y = (mi_row & 0x17) >> 3; + const int idx64 = y + x; + + x = (mi_col & 0xF) >> 3; + // y = (mi_row & 0xF) >> 3; + // const int idx32 = (y << 1) + x; + y = (mi_row & 0xB) >> 2; + const int idx32 = y + x; + + x = (mi_col & 0x7) >> 2; + // y = (mi_row & 0x7) >> 2; + // const int idx16 = (y << 1) + x; + y = (mi_row & 0x5) >> 1; + const int idx16 = y + x; // Set force_skip_low_temp_var based on the block size and block offset. switch (bsize) { case BLOCK_128X128: force_skip_low_temp_var = variance_low[0]; break; + case BLOCK_128X64: + assert((mi_col & 0x1F) == 0); + force_skip_low_temp_var = variance_low[1 + ((mi_row & 0x1F) != 0)]; + break; + case BLOCK_64X128: + assert((mi_row & 0x1F) == 0); + force_skip_low_temp_var = variance_low[3 + ((mi_col & 0x1F) != 0)]; + break; case BLOCK_64X64: + // Location of this 64x64 block inside the 128x128 superblock + force_skip_low_temp_var = variance_low[5 + idx64]; + break; + case BLOCK_64X32: + x = (mi_col & 0x1F) >> 4; + y = (mi_row & 0x1F) >> 3; + /* + .---------------.---------------. + | x=0,y=0,idx=0 | x=0,y=0,idx=2 | + :---------------+---------------: + | x=0,y=1,idx=1 | x=1,y=1,idx=3 | + :---------------+---------------: + | x=0,y=2,idx=4 | x=1,y=2,idx=6 | + :---------------+---------------: + | x=0,y=3,idx=5 | x=1,y=3,idx=7 | + '---------------'---------------' + */ + const int idx64x32 = (x << 1) + (y % 2) + ((y >> 1) << 2); + force_skip_low_temp_var = variance_low[9 + idx64x32]; + break; + case BLOCK_32X64: + x = (mi_col & 0x1F) >> 3; + y = (mi_row & 0x1F) >> 4; + const int idx32x64 = (y << 2) + x; + force_skip_low_temp_var = variance_low[17 + idx32x64]; + break; case BLOCK_32X32: + force_skip_low_temp_var = variance_low[25 + (idx64 << 2) + idx32]; + break; + case BLOCK_32X16: + case BLOCK_16X32: case BLOCK_16X16: - x = mi_col % 32; - y = mi_row % 32; - if (bsize == BLOCK_64X64) { - assert((x == 0 || x == 16) && (y == 0 || y == 16)); - } - x >>= 4; - y >>= 4; - const int idx64 = y * 2 + x; - if (bsize == BLOCK_64X64) { - force_skip_low_temp_var = variance_low[1 + idx64]; - break; - } - - x = mi_col % 16; - y = mi_row % 16; - if (bsize == BLOCK_32X32) { - assert((x == 0 || x == 8) && (y == 0 || y == 8)); - } - x >>= 3; - y >>= 3; - const int idx32 = y * 2 + x; - if (bsize == BLOCK_32X32) { - force_skip_low_temp_var = variance_low[5 + (idx64 << 2) + idx32]; - break; - } - - x = mi_col % 8; - y = mi_row % 8; - if (bsize == BLOCK_16X16) { - assert((x == 0 || x == 4) && (y == 0 || y == 4)); - } - x >>= 2; - y >>= 2; - const int idx16 = y * 2 + x; - if (bsize == BLOCK_16X16) { - force_skip_low_temp_var = - variance_low[21 + (idx64 << 4) + (idx32 << 2) + idx16]; - break; - } + force_skip_low_temp_var = + variance_low[41 + (idx64 << 4) + (idx32 << 2) + idx16]; + break; default: break; } return force_skip_low_temp_var; @@ -1181,18 +1288,14 @@ static void search_filter_ref(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *this_rdc, BLOCK_SIZE bsize, int reuse_inter_pred, PRED_BUFFER **this_mode_pred, unsigned int *var_y, unsigned int *sse_y, int *this_early_term, - int use_model_yrd_large, int64_t *sse_block_yrd, - int *block_yrd_computed) { + int use_model_yrd_large, int64_t *sse_block_yrd) { AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; struct macroblockd_plane *const pd = &xd->plane[0]; MB_MODE_INFO *const mi = xd->mi[0]; const int bw = block_size_wide[bsize]; - RD_STATS this_rdc_fil; - int is_skippable; int pf_rate[FILTER_SEARCH_SIZE] = { 0 }; int64_t pf_dist[FILTER_SEARCH_SIZE] = { 0 }; - int curr_rate[FILTER_SEARCH_SIZE] = { 0 }; unsigned int pf_var[FILTER_SEARCH_SIZE] = { 0 }; unsigned int pf_sse[FILTER_SEARCH_SIZE] = { 0 }; int64_t pf_sse_block_yrd[FILTER_SEARCH_SIZE] = { 0 }; @@ -1210,28 +1313,15 @@ static void search_filter_ref(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *this_rdc, int64_t cost; InterpFilter filter = filters[i]; mi->interp_filters = av1_broadcast_interp_filter(filter); - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); + av1_enc_build_inter_predictor_y(xd, mi_row, mi_col); if (use_model_yrd_large) - model_skip_for_sb_y_large(cpi, bsize, x, xd, &pf_rate[i], &pf_dist[i], - &pf_var[i], &pf_sse[i], this_early_term, - !cpi->sf.nonrd_use_blockyrd_interp_filter); + model_skip_for_sb_y_large(cpi, bsize, mi_row, mi_col, x, xd, &pf_rate[i], + &pf_dist[i], &pf_var[i], &pf_sse[i], + this_early_term, 1); else model_rd_for_sb_y(cpi, bsize, x, xd, &pf_rate[i], &pf_dist[i], - &skip_txfm[i], NULL, &pf_var[i], &pf_sse[i], - !cpi->sf.nonrd_use_blockyrd_interp_filter); - if (cpi->sf.nonrd_use_blockyrd_interp_filter) { - int64_t this_sse = (int64_t)pf_sse[i]; - block_yrd(cpi, x, mi_row, mi_col, &this_rdc_fil, &is_skippable, &this_sse, - bsize, mi->tx_size); - pf_rate[i] = this_rdc_fil.rate; - pf_dist[i] = this_rdc_fil.dist; - pf_sse_block_yrd[i] = this_sse; - skip_txfm[i] = this_rdc_fil.skip; - *block_yrd_computed = 1; - } - curr_rate[i] = pf_rate[i]; - pf_rate[i] += av1_get_switchable_rate(cm, x, xd); + &skip_txfm[i], NULL, &pf_var[i], &pf_sse[i], 1); + pf_rate[i] += av1_get_switchable_rate(x, xd, cm->features.interp_filter); cost = RDCOST(x->rdmult, pf_rate[i], pf_dist[i]); pf_tx_size[i] = mi->tx_size; if (cost < best_cost) { @@ -1256,7 +1346,7 @@ static void search_filter_ref(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *this_rdc, mi->interp_filters = av1_broadcast_interp_filter(filters[best_filter_index]); mi->tx_size = pf_tx_size[best_filter_index]; - this_rdc->rate = curr_rate[best_filter_index]; + this_rdc->rate = pf_rate[best_filter_index]; this_rdc->dist = pf_dist[best_filter_index]; *var_y = pf_var[best_filter_index]; *sse_y = pf_sse[best_filter_index]; @@ -1267,8 +1357,7 @@ static void search_filter_ref(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *this_rdc, pd->dst.buf = (*this_mode_pred)->data; pd->dst.stride = (*this_mode_pred)->stride; } else if (best_filter_index < FILTER_SEARCH_SIZE - 1) { - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); + av1_enc_build_inter_predictor_y(xd, mi_row, mi_col); } } @@ -1326,11 +1415,67 @@ static void compute_intra_yprediction(const AV1_COMMON *cm, pd->dst.buf = dst_buf_base; } -void av1_fast_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) { +void av1_pick_intra_mode(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost, + BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) { + AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mi = xd->mi[0]; + RD_STATS this_rdc, best_rdc; + struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0 }; + const TX_SIZE intra_tx_size = + AOMMIN(max_txsize_lookup[bsize], + tx_mode_to_biggest_tx_size[x->tx_mode_search_type]); + int *bmode_costs; + const MB_MODE_INFO *above_mi = xd->above_mbmi; + const MB_MODE_INFO *left_mi = xd->left_mbmi; + const PREDICTION_MODE A = av1_above_block_mode(above_mi); + const PREDICTION_MODE L = av1_left_block_mode(left_mi); + bmode_costs = x->y_mode_costs[A][L]; + + av1_invalid_rd_stats(&best_rdc); + av1_invalid_rd_stats(&this_rdc); + + init_mbmi(mi, DC_PRED, INTRA_FRAME, NONE_FRAME, cm); + mi->mv[0].as_int = mi->mv[1].as_int = INVALID_MV; + + // Change the limit of this loop to add other intra prediction + // mode tests. + for (int i = 0; i < 4; ++i) { + PREDICTION_MODE this_mode = intra_mode_list[i]; + this_rdc.dist = this_rdc.rate = 0; + args.mode = this_mode; + args.skippable = 1; + args.rdc = &this_rdc; + mi->tx_size = intra_tx_size; + av1_foreach_transformed_block_in_plane(xd, bsize, 0, estimate_block_intra, + &args); + if (args.skippable) { + this_rdc.rate = av1_cost_symbol(av1_get_skip_cdf(xd)[1]); + } else { + this_rdc.rate += av1_cost_symbol(av1_get_skip_cdf(xd)[0]); + } + this_rdc.rate += bmode_costs[this_mode]; + this_rdc.rdcost = RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist); + + if (this_rdc.rdcost < best_rdc.rdcost) { + best_rdc = this_rdc; + mi->mode = this_mode; + } + } + + *rd_cost = best_rdc; + +#if CONFIG_INTERNAL_STATS + store_coding_context(x, ctx, mi->mode); +#else + store_coding_context(x, ctx); +#endif // CONFIG_INTERNAL_STATS +} + +void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, + MACROBLOCK *x, RD_STATS *rd_cost, + BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, + int64_t best_rd_so_far) { AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mi = xd->mi[0]; @@ -1355,38 +1500,41 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, const int *const rd_threshes = cpi->rd.threshes[mi->segment_id][bsize]; const int *const rd_thresh_freq_fact = x->thresh_freq_fact[bsize]; InterpFilter filter_ref; - int const_motion[REF_FRAMES] = { 0 }; int ref_frame_skip_mask = 0; int best_pred_sad = INT_MAX; int best_early_term = 0; unsigned int ref_costs_single[REF_FRAMES], ref_costs_comp[REF_FRAMES][REF_FRAMES]; - int use_golden_nonzeromv = 1; int force_skip_low_temp_var = 0; int skip_ref_find_pred[8] = { 0 }; unsigned int sse_zeromv_norm = UINT_MAX; const unsigned int thresh_skip_golden = 500; - int64_t best_sse_sofar = INT64_MAX; int gf_temporal_ref = 0; const struct segmentation *const seg = &cm->seg; - int comp_modes = 0; int num_inter_modes = RT_INTER_MODES; unsigned char segment_id = mi->segment_id; PRED_BUFFER tmp[4]; DECLARE_ALIGNED(16, uint8_t, pred_buf[3 * 128 * 128]); PRED_BUFFER *this_mode_pred = NULL; - const int reuse_inter_pred = cpi->sf.reuse_inter_pred_nonrd; + const int reuse_inter_pred = + cpi->sf.rt_sf.reuse_inter_pred_nonrd && cm->seq_params.bit_depth == 8; const int bh = block_size_high[bsize]; const int bw = block_size_wide[bsize]; const int pixels_in_block = bh * bw; struct buf_2d orig_dst = pd->dst; + const CommonQuantParams *quant_params = &cm->quant_params; #if COLLECT_PICK_MODE_STAT aom_usec_timer_start(&ms_stat.timer2); #endif - const int intra_cost_penalty = av1_get_intra_cost_penalty( - cm->base_qindex, cm->y_dc_delta_q, cm->seq_params.bit_depth); - const int64_t inter_mode_thresh = RDCOST(x->rdmult, intra_cost_penalty, 0); - const int perform_intra_pred = cpi->sf.check_intra_pred_nonrd; + int intra_cost_penalty = av1_get_intra_cost_penalty( + quant_params->base_qindex, quant_params->y_dc_delta_q, + cm->seq_params.bit_depth); + int64_t inter_mode_thresh = RDCOST(x->rdmult, intra_cost_penalty, 0); + const int perform_intra_pred = cpi->sf.rt_sf.check_intra_pred_nonrd; + int use_modeled_non_rd_cost = 0; + int enable_filter_search = 0; + InterpFilter default_interp_filter = EIGHTTAP_REGULAR; + int64_t thresh_sad_pred = INT64_MAX; (void)best_rd_so_far; @@ -1397,8 +1545,6 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, // TODO(kyslov) Move this to Speed Features inter_mode_mask[BLOCK_128X128] = INTER_NEAREST_NEAR; - x->source_variance = UINT_MAX; - struct scale_factors *const sf_last = get_ref_scale_factors(cm, LAST_FRAME); struct scale_factors *const sf_golden = get_ref_scale_factors(cm, GOLDEN_FRAME); @@ -1411,10 +1557,9 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, } av1_collect_neighbors_ref_counts(xd); - av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); estimate_single_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single); - if (cpi->sf.use_comp_ref_nonrd) + if (cpi->sf.rt_sf.use_comp_ref_nonrd) estimate_comp_ref_frame_costs(cm, xd, x, segment_id, ref_costs_comp); memset(&mode_checked[0][0], 0, MB_MODE_COUNT * REF_FRAMES); @@ -1429,13 +1574,13 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, tmp[3].in_use = 0; } - x->skip = 0; + x->force_skip = 0; // Instead of using av1_get_pred_context_switchable_interp(xd) to assign // filter_ref, we use a less strict condition on assigning filter_ref. // This is to reduce the probabily of entering the flow of not assigning // filter_ref and then skip filter search. - filter_ref = cm->interp_filter; + filter_ref = cm->features.interp_filter; // initialize mode decisions av1_invalid_rd_stats(&best_rdc); @@ -1446,27 +1591,30 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, mi->ref_frame[1] = NONE_FRAME; usable_ref_frame = - cpi->sf.use_nonrd_altref_frame ? ALTREF_FRAME : GOLDEN_FRAME; + cpi->sf.rt_sf.use_nonrd_altref_frame ? ALTREF_FRAME : GOLDEN_FRAME; if (cpi->rc.frames_since_golden == 0 && gf_temporal_ref) { - usable_ref_frame = LAST_FRAME; + skip_ref_find_pred[GOLDEN_FRAME] = 1; + if (!cpi->sf.rt_sf.use_nonrd_altref_frame) usable_ref_frame = LAST_FRAME; } - if (cpi->sf.short_circuit_low_temp_var) { - force_skip_low_temp_var = - get_force_skip_low_temp_var(&x->variance_low[0], mi_row, mi_col, bsize); - // If force_skip_low_temp_var is set, and for short circuit mode = 1 and 3, - // skip golden reference. - if ((cpi->sf.short_circuit_low_temp_var == 1 || - cpi->sf.short_circuit_low_temp_var == 3) && - force_skip_low_temp_var) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int is_small_sb = (cm->seq_params.sb_size == BLOCK_64X64); + if (cpi->sf.rt_sf.short_circuit_low_temp_var && + x->nonrd_prune_ref_frame_search) { + if (is_small_sb) + force_skip_low_temp_var = get_force_skip_low_temp_var_small_sb( + &x->variance_low[0], mi_row, mi_col, bsize); + else + force_skip_low_temp_var = get_force_skip_low_temp_var( + &x->variance_low[0], mi_row, mi_col, bsize); + // If force_skip_low_temp_var is set, skip golden reference. + if (force_skip_low_temp_var) { usable_ref_frame = LAST_FRAME; } } - if (!(cpi->ref_frame_flags & flag_list[GOLDEN_FRAME])) - use_golden_nonzeromv = 0; - // If the segment reference frame feature is enabled and it's set to GOLDEN // reference, then make sure we don't skip checking GOLDEN, this is to // prevent possibility of not picking any mode. @@ -1483,21 +1631,53 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, skip_ref_find_pred[ref_frame_iter] = !(cpi->ref_frame_flags & flag_list[ref_frame_iter]); if (!skip_ref_find_pred[ref_frame_iter]) { - find_predictors(cpi, x, ref_frame_iter, frame_mv, const_motion, - &ref_frame_skip_mask, flag_list, tile_data, mi_row, - mi_col, yv12_mb, bsize, force_skip_low_temp_var, - comp_modes > 0); + find_predictors(cpi, x, ref_frame_iter, frame_mv, &ref_frame_skip_mask, + flag_list, tile_data, yv12_mb, bsize, + force_skip_low_temp_var); } } + + thresh_sad_pred = ((int64_t)x->pred_mv_sad[LAST_FRAME]) << 1; + // Increase threshold for less agressive pruning. + if (cpi->sf.rt_sf.nonrd_prune_ref_frame_search == 1) + thresh_sad_pred += (x->pred_mv_sad[LAST_FRAME] >> 2); + const int large_block = bsize >= BLOCK_32X32; const int use_model_yrd_large = cpi->oxcf.rc_mode == AOM_CBR && large_block && !cyclic_refresh_segment_id_boosted(xd->mi[0]->segment_id) && - cm->base_qindex; + quant_params->base_qindex && cm->seq_params.bit_depth == 8; #if COLLECT_PICK_MODE_STAT ms_stat.num_blocks[bsize]++; #endif + init_mbmi(mi, DC_PRED, NONE_FRAME, NONE_FRAME, cm); + mi->tx_size = + AOMMIN(AOMMIN(max_txsize_lookup[bsize], + tx_mode_to_biggest_tx_size[x->tx_mode_search_type]), + TX_16X16); + + // TODO(marpan): Look into reducing these conditions. For now constrain + // it to avoid significant bdrate loss. + if (cpi->sf.rt_sf.use_modeled_non_rd_cost && + quant_params->base_qindex > 120 && x->source_variance > 100 && + bsize <= BLOCK_16X16 && x->content_state_sb != kLowVarHighSumdiff && + x->content_state_sb != kHighSad) + use_modeled_non_rd_cost = 1; + + if (cpi->sf.rt_sf.use_nonrd_filter_search) { + enable_filter_search = 1; + if (cpi->sf.interp_sf.cb_pred_filter_search) { + const int bsl = mi_size_wide_log2[bsize]; + enable_filter_search = + (((mi_row + mi_col) >> bsl) + + get_chessboard_index(cm->current_frame.frame_number)) & + 0x1; + } + if (x->source_variance <= + cpi->sf.interp_sf.disable_filter_search_var_thresh) + enable_filter_search = 0; + } for (int idx = 0; idx < num_inter_modes; ++idx) { int rate_mv = 0; @@ -1509,7 +1689,6 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, int skip_this_mv = 0; int comp_pred = 0; int force_mv_inter_layer = 0; - int block_yrd_computed = 0; PREDICTION_MODE this_mode; MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; second_ref_frame = NONE_FRAME; @@ -1521,15 +1700,8 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, aom_usec_timer_start(&ms_stat.timer1); ms_stat.num_searches[bsize][this_mode]++; #endif - init_mbmi(mi, this_mode, ref_frame, NONE_FRAME, cm); - - mi->tx_size = AOMMIN(AOMMIN(max_txsize_lookup[bsize], - tx_mode_to_biggest_tx_size[x->tx_mode]), - TX_16X16); - memset(mi->inter_tx_size, mi->tx_size, sizeof(mi->inter_tx_size)); - memset(xd->tx_type_map, DCT_DCT, - sizeof(xd->tx_type_map[0]) * ctx->num_4x4_blk); - av1_zero(x->blk_skip); + mi->mode = this_mode; + mi->ref_frame[0] = ref_frame; if (ref_frame > usable_ref_frame) continue; if (skip_ref_find_pred[ref_frame]) continue; @@ -1556,15 +1728,16 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (!(inter_mode_mask[bsize] & (1 << this_mode))) continue; - if (const_motion[ref_frame] && this_mode == NEARMV) continue; + // Skip testing non-LAST if this flag is set. + if (x->nonrd_prune_ref_frame_search) { + if (x->nonrd_prune_ref_frame_search > 1 && ref_frame != LAST_FRAME && + (bsize > BLOCK_64X64 || (bsize > BLOCK_16X16 && this_mode == NEWMV))) + continue; - if (ref_frame != LAST_FRAME && - (bsize > BLOCK_64X64 || (bsize > BLOCK_16X16 && this_mode == NEWMV))) - continue; + if (ref_frame != LAST_FRAME && this_mode == NEARMV) continue; + } - if (ref_frame != LAST_FRAME && this_mode == NEARMV) continue; - - // Skip non-zeromv mode search for golden frame if force_skip_low_temp_var + // Skip non-zeromv mode search for non-LAST frame if force_skip_low_temp_var // is set. If nearestmv for golden frame is 0, zeromv mode will be skipped // later. if (!force_mv_inter_layer && force_skip_low_temp_var && @@ -1572,7 +1745,6 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, continue; } -// TODO(kyslov) Refine logic of pruning reference . #if 0 if (x->content_state_sb != kVeryHighSad && (cpi->sf.short_circuit_low_temp_var >= 2 || @@ -1581,37 +1753,21 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, NEWMV) { continue; } - - // 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. - if (!segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME)) { - if (sf->reference_masking && - !(frame_mv[this_mode][ref_frame].as_int == 0 && - ref_frame == LAST_FRAME)) { - if (usable_ref_frame < ALTREF_FRAME) { - if (!force_skip_low_temp_var && usable_ref_frame > LAST_FRAME) { - i = (ref_frame == LAST_FRAME) ? GOLDEN_FRAME : LAST_FRAME; - if ((cpi->ref_frame_flags & flag_list[i])) - if (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[i] << 1)) - ref_frame_skip_mask |= (1 << ref_frame); - } - } else if (!cpi->rc.is_src_frame_alt_ref && - !(frame_mv[this_mode][ref_frame].as_int == 0 && - ref_frame == ALTREF_FRAME)) { - int ref1 = (ref_frame == GOLDEN_FRAME) ? LAST_FRAME : - GOLDEN_FRAME; int ref2 = (ref_frame == ALTREF_FRAME) ? LAST_FRAME : - ALTREF_FRAME; if (((cpi->ref_frame_flags & flag_list[ref1]) && - (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref1] << 1))) || - ((cpi->ref_frame_flags & flag_list[ref2]) && - (x->pred_mv_sad[ref_frame] > (x->pred_mv_sad[ref2] << 1)))) - ref_frame_skip_mask |= (1 << ref_frame); - } - } - if (ref_frame_skip_mask & (1 << ref_frame)) continue; - } #endif + // 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. + if (!segfeature_active(seg, mi->segment_id, SEG_LVL_REF_FRAME)) { + // Check for skipping GOLDEN and ALTREF based pred_mv_sad. + if (cpi->sf.rt_sf.nonrd_prune_ref_frame_search > 0 && + x->pred_mv_sad[ref_frame] != INT_MAX && ref_frame != LAST_FRAME) { + if ((int64_t)(x->pred_mv_sad[ref_frame]) > thresh_sad_pred) + ref_frame_skip_mask |= (1 << ref_frame); + } + if (ref_frame_skip_mask & (1 << ref_frame)) continue; + } + // Select prediction reference frames. for (int i = 0; i < MAX_MB_PLANE; i++) { xd->plane[i].pre[0] = yv12_mb[ref_frame][i]; @@ -1626,10 +1782,13 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, ? rd_threshes[mode_index] << 1 : rd_threshes[mode_index]; - // Increase mode_rd_thresh value for GOLDEN_FRAME for improved encoding + // Increase mode_rd_thresh value for non-LAST for improved encoding // speed - if (ref_frame != LAST_FRAME && cpi->rc.frames_since_golden > 4) - mode_rd_thresh = mode_rd_thresh << 3; + if (ref_frame != LAST_FRAME) { + mode_rd_thresh = mode_rd_thresh << 1; + if (ref_frame == GOLDEN_FRAME && cpi->rc.frames_since_golden > 4) + mode_rd_thresh = mode_rd_thresh << 1; + } if (rd_less_than_thresh(best_rdc.rdcost, mode_rd_thresh, rd_thresh_freq_fact[mode_index])) @@ -1637,8 +1796,7 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (this_mode == NEWMV && !force_mv_inter_layer) { if (search_new_mv(cpi, x, frame_mv, ref_frame, gf_temporal_ref, bsize, - mi_row, mi_col, best_pred_sad, &rate_mv, best_sse_sofar, - &best_rdc)) + mi_row, mi_col, best_pred_sad, &rate_mv, &best_rdc)) continue; } @@ -1647,8 +1805,7 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (inter_mv_mode == this_mode || comp_pred) continue; if (mode_checked[inter_mv_mode][ref_frame] && frame_mv[this_mode][ref_frame].as_int == - frame_mv[inter_mv_mode][ref_frame].as_int && - frame_mv[inter_mv_mode][ref_frame].as_int == 0) { + frame_mv[inter_mv_mode][ref_frame].as_int) { skip_this_mv = 1; break; } @@ -1656,25 +1813,6 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (skip_this_mv) continue; - // If use_golden_nonzeromv is false, NEWMV mode is skipped for golden, no - // need to compute best_pred_sad which is only used to skip golden NEWMV. - if (use_golden_nonzeromv && this_mode == NEWMV && ref_frame == LAST_FRAME && - frame_mv[NEWMV][LAST_FRAME].as_int != INVALID_MV) { - const int pre_stride = xd->plane[0].pre[0].stride; - const uint8_t *const pre_buf = - xd->plane[0].pre[0].buf + - (frame_mv[NEWMV][LAST_FRAME].as_mv.row >> 3) * pre_stride + - (frame_mv[NEWMV][LAST_FRAME].as_mv.col >> 3); - best_pred_sad = cpi->fn_ptr[bsize].sdf( - x->plane[0].src.buf, x->plane[0].src.stride, pre_buf, pre_stride); - x->pred_mv_sad[LAST_FRAME] = best_pred_sad; - } - - if (this_mode != NEARESTMV && !comp_pred && - frame_mv[this_mode][ref_frame].as_int == - frame_mv[NEARESTMV][ref_frame].as_int) - continue; - mi->mode = this_mode; mi->mv[0].as_int = frame_mv[this_mode][ref_frame].as_int; mi->mv[1].as_int = 0; @@ -1690,30 +1828,26 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, #if COLLECT_PICK_MODE_STAT ms_stat.num_nonskipped_searches[bsize][this_mode]++; #endif - if (cpi->sf.use_nonrd_filter_search && + if (enable_filter_search && ((mi->mv[0].as_mv.row & 0x07) || (mi->mv[0].as_mv.col & 0x07)) && - ref_frame == LAST_FRAME) { + (ref_frame == LAST_FRAME || !x->nonrd_prune_ref_frame_search)) { search_filter_ref(cpi, x, &this_rdc, mi_row, mi_col, tmp, bsize, reuse_inter_pred, &this_mode_pred, &var_y, &sse_y, - &this_early_term, use_model_yrd_large, &this_sse, - &block_yrd_computed); + &this_early_term, use_model_yrd_large, &this_sse); } else { - mi->interp_filters = (filter_ref == SWITCHABLE) - ? av1_broadcast_interp_filter(EIGHTTAP_REGULAR) - : av1_broadcast_interp_filter(filter_ref); - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - if (cpi->sf.use_modeled_non_rd_cost) { - model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, - &this_rdc.skip, NULL, &var_y, &sse_y, 1); + mi->interp_filters = + (filter_ref == SWITCHABLE) + ? av1_broadcast_interp_filter(default_interp_filter) + : av1_broadcast_interp_filter(filter_ref); + av1_enc_build_inter_predictor_y(xd, mi_row, mi_col); + if (use_model_yrd_large) { + model_skip_for_sb_y_large(cpi, bsize, mi_row, mi_col, x, xd, NULL, NULL, + &var_y, &sse_y, &this_early_term, + use_modeled_non_rd_cost); } else { - if (use_model_yrd_large) { - model_skip_for_sb_y_large(cpi, bsize, x, xd, NULL, NULL, &var_y, - &sse_y, &this_early_term, 0); - } else { - model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, - &this_rdc.skip, NULL, &var_y, &sse_y, 0); - } + model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, + &this_rdc.skip, NULL, &var_y, &sse_y, + use_modeled_non_rd_cost); } } @@ -1722,24 +1856,20 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, sse_y >> (b_width_log2_lookup[bsize] + b_height_log2_lookup[bsize]); } - if (sse_y < best_sse_sofar) best_sse_sofar = sse_y; - const int skip_ctx = av1_get_skip_context(xd); const int skip_cost = x->skip_cost[skip_ctx][1]; const int no_skip_cost = x->skip_cost[skip_ctx][0]; if (!this_early_term) { - if (cpi->sf.use_modeled_non_rd_cost) { + if (use_modeled_non_rd_cost) { if (this_rdc.skip) { this_rdc.rate = skip_cost; } else { this_rdc.rate += no_skip_cost; } } else { - if (!block_yrd_computed) { - this_sse = (int64_t)sse_y; - block_yrd(cpi, x, mi_row, mi_col, &this_rdc, &is_skippable, &this_sse, - bsize, mi->tx_size); - } + this_sse = (int64_t)sse_y; + block_yrd(cpi, x, mi_row, mi_col, &this_rdc, &is_skippable, &this_sse, + bsize, mi->tx_size); if (this_rdc.skip) { this_rdc.rate = skip_cost; } else { @@ -1789,10 +1919,11 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, this_rdc.rate += ref_costs_single[ref_frame]; this_rdc.rdcost = RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist); - if (cpi->oxcf.rc_mode == AOM_CBR && cpi->oxcf.speed >= 8) { + if (cpi->oxcf.rc_mode == AOM_CBR) { newmv_diff_bias(xd, this_mode, &this_rdc, bsize, frame_mv[this_mode][ref_frame].as_mv.row, - frame_mv[this_mode][ref_frame].as_mv.col); + frame_mv[this_mode][ref_frame].as_mv.col, cpi->speed, + x->source_variance); } mode_checked[this_mode][ref_frame] = 1; @@ -1818,7 +1949,7 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (reuse_inter_pred) free_pred_buffer(this_mode_pred); } if (best_early_term && idx > 0) { - x->skip = 1; + x->force_skip = 1; break; } } @@ -1831,23 +1962,50 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, mi->mv[0].as_int = frame_mv[best_pickmode.best_mode][best_pickmode.best_ref_frame].as_int; mi->ref_frame[1] = best_pickmode.best_second_ref_frame; - x->skip = best_rdc.skip; + x->force_skip = best_rdc.skip; // Perform intra prediction search, if the best SAD is above a certain // threshold. mi->angle_delta[PLANE_TYPE_Y] = 0; mi->angle_delta[PLANE_TYPE_UV] = 0; mi->filter_intra_mode_info.use_filter_intra = 0; - // TODO(kyslov@) Need to adjust inter_mode_thresh - if (best_rdc.rdcost == INT64_MAX || (perform_intra_pred && !best_early_term && - best_rdc.rdcost > inter_mode_thresh && - bsize <= cpi->sf.max_intra_bsize)) { + + uint32_t spatial_var_thresh = 50; + int motion_thresh = 32; + // Adjust thresholds to make intra mode likely tested if the other + // references (golden, alt) are skipped/not checked. + if (cpi->sf.rt_sf.use_nonrd_altref_frame == 0 && + cpi->sf.rt_sf.nonrd_prune_ref_frame_search > 0) { + spatial_var_thresh = 150; + motion_thresh = 0; + } + int do_early_exit_rdthresh = 1; + // Some adjustments to checking intra mode based on source variance. + if (x->source_variance < spatial_var_thresh) { + // If the best inter mode is large motion or non-LAST ref reduce intra cost + // penalty, so intra mode is more likely tested. + if (best_pickmode.best_ref_frame != LAST_FRAME || + abs(mi->mv[0].as_mv.row) >= motion_thresh || + abs(mi->mv[0].as_mv.col) >= motion_thresh) { + intra_cost_penalty = intra_cost_penalty >> 2; + inter_mode_thresh = RDCOST(x->rdmult, intra_cost_penalty, 0); + do_early_exit_rdthresh = 0; + } + // For big blocks worth checking intra (since only DC will be checked), + // even if best_early_term is set. + if (bsize >= BLOCK_32X32) best_early_term = 0; + } + + if (best_rdc.rdcost == INT64_MAX || + (perform_intra_pred && !best_early_term && + best_rdc.rdcost > inter_mode_thresh && + bsize <= cpi->sf.part_sf.max_intra_bsize)) { int64_t this_sse = INT64_MAX; struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0 }; PRED_BUFFER *const best_pred = best_pickmode.best_pred; TX_SIZE intra_tx_size = AOMMIN(AOMMIN(max_txsize_lookup[bsize], - tx_mode_to_biggest_tx_size[x->tx_mode]), + tx_mode_to_biggest_tx_size[x->tx_mode_search_type]), TX_16X16); if (reuse_inter_pred && best_pred != NULL) { @@ -1871,7 +2029,8 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (this_mode > 0 && bsize >= BLOCK_32X32) continue; if (rd_less_than_thresh(best_rdc.rdcost, mode_rd_thresh, - rd_thresh_freq_fact[mode_index])) { + rd_thresh_freq_fact[mode_index]) && + (do_early_exit_rdthresh || this_mode == SMOOTH_PRED)) { continue; } const BLOCK_SIZE uv_bsize = get_plane_block_size( @@ -1888,15 +2047,21 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, mi->tx_size = intra_tx_size; compute_intra_yprediction(cm, this_mode, bsize, x, xd); // Look into selecting tx_size here, based on prediction residual. - block_yrd(cpi, x, mi_row, mi_col, &this_rdc, &args.skippable, &this_sse, - bsize, mi->tx_size); + if (use_modeled_non_rd_cost) + model_rd_for_sb_y(cpi, bsize, x, xd, &this_rdc.rate, &this_rdc.dist, + &this_rdc.skip, NULL, &var_y, &sse_y, 1); + else + block_yrd(cpi, x, mi_row, mi_col, &this_rdc, &args.skippable, &this_sse, + bsize, mi->tx_size); // TODO(kyslov@) Need to account for skippable - if (x->color_sensitivity[0]) + if (x->color_sensitivity[0]) { av1_foreach_transformed_block_in_plane(xd, uv_bsize, 1, estimate_block_intra, &args); - if (x->color_sensitivity[1]) + } + if (x->color_sensitivity[1]) { av1_foreach_transformed_block_in_plane(xd, uv_bsize, 2, estimate_block_intra, &args); + } int mode_cost = 0; if (av1_is_directional_mode(this_mode) && av1_use_angle_delta(bsize)) { @@ -1948,19 +2113,18 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, pd->dst.stride, 0, 0, 0, 0, bw, bh); } } - if (cpi->sf.adaptive_rd_thresh) { + if (cpi->sf.inter_sf.adaptive_rd_thresh) { THR_MODES best_mode_idx = mode_idx[best_pickmode.best_ref_frame][mode_offset(mi->mode)]; if (best_pickmode.best_ref_frame == INTRA_FRAME) { // Only consider the modes that are included in the intra_mode_list. int intra_modes = sizeof(intra_mode_list) / sizeof(PREDICTION_MODE); - int i; - for (i = 0; i < intra_modes; i++) { + for (int i = 0; i < intra_modes; i++) { update_thresh_freq_fact(cpi, x, bsize, INTRA_FRAME, best_mode_idx, intra_mode_list[i]); } } else { - for (ref_frame = LAST_FRAME; ref_frame <= GOLDEN_FRAME; ++ref_frame) { + for (ref_frame = LAST_FRAME; ref_frame <= usable_ref_frame; ++ref_frame) { PREDICTION_MODE this_mode; if (best_pickmode.best_ref_frame != ref_frame) continue; for (this_mode = NEARESTMV; this_mode <= NEWMV; ++this_mode) { @@ -1980,8 +2144,8 @@ void av1_fast_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, aom_usec_timer_mark(&ms_stat.timer2); ms_stat.avg_block_times[bsize] += aom_usec_timer_elapsed(&ms_stat.timer2); // - if ((mi_row + mi_size_high[bsize] >= (cpi->common.mi_rows)) && - (mi_col + mi_size_wide[bsize] >= (cpi->common.mi_cols))) { + if ((mi_row + mi_size_high[bsize] >= (cpi->common.mi_params.mi_rows)) && + (mi_col + mi_size_wide[bsize] >= (cpi->common.mi_params.mi_cols))) { int i, j; PREDICTION_MODE used_modes[3] = { NEARESTMV, NEARMV, NEWMV }; BLOCK_SIZE bss[5] = { BLOCK_8X8, BLOCK_16X16, BLOCK_32X32, BLOCK_64X64, diff --git a/media/libaom/src/av1/encoder/partition_model_weights.h b/media/libaom/src/av1/encoder/partition_model_weights.h index 44958738f7..71c1ace782 100644 --- a/media/libaom/src/av1/encoder/partition_model_weights.h +++ b/media/libaom/src/av1/encoder/partition_model_weights.h @@ -18,6 +18,10 @@ extern "C" { #include "av1/encoder/ml.h" +// TODO(chiyotsai@google.com): The performance of these models are getting worse +// due the changes in the encoder. We should retrain the models here to get +// better performance once we have the time. + #define FEATURE_SIZE 10 #define LABEL_SIZE 16 // nn model for ab partition pruning, 128x128. @@ -2445,7 +2449,7 @@ static const NN_CONFIG av1_rect_partition_nnconfig_128 = { // Thresholds // The first index level is for aggresiveness, and the second is frame // resolution, third is bsize -static const float av1_simple_motion_search_split_thresh[3][3][5] = { +static const float av1_simple_motion_search_split_thresh[4][3][5] = { // Aggressiveness = 0 { // lowres @@ -2527,9 +2531,21 @@ static const float av1_simple_motion_search_split_thresh[3][3][5] = { 1.655562f, // p = 0.839641385729 }, }, + // Aggressiveness = 3 + { + // lowres + { 100.000000f, 1.41409519484f, 0.606066095487f, 0.0993410805635f, + 0.762099214988f }, + // midres + { 100.000000f, 0.702207995397f, 0.503550081119f, 0.0403228785199f, + 0.557298794638f }, + // hdres + { 1.21895384144f, 1.26798450469f, 0.872537808115f, 0.975869438148f, + 1.86572095242f }, + }, }; -static const float av1_simple_motion_search_no_split_thresh[3][3][5] = { +static const float av1_simple_motion_search_no_split_thresh[4][3][5] = { // Aggressiveness = 0 { // lowres @@ -2611,6 +2627,18 @@ static const float av1_simple_motion_search_no_split_thresh[3][3][5] = { -1.972387f, // p = 0.122132728355 }, }, + // Aggressiveness = 3 + { + // lowres + { -100.000000f, -2.04766486133f, -1.00442099188f, -1.15077982642f, + -1.0830321897f }, + // midres + { -100.000000f, -0.985686808303f, -0.757739584866f, -0.890120107569f, + -0.228236297886f }, + // hdres + { -1.03535679263f, -1.57431743203f, -0.564851540156f, -0.35442301663f, + -1.36741555171f }, + }, }; static const float av1_simple_motion_search_split_mean_128[17] = { @@ -3280,7 +3308,7 @@ static const NN_CONFIG *const av1_simple_motion_search_split_nn_config[5] = { // Model based on simple_motion_search for pruning rect // Thresholds. The first idx level is aggresiveness, second is frame resolution, // third is bsize -static const float av1_simple_motion_search_prune_rect_thresh[3][3][5] = { +static const float av1_simple_motion_search_prune_rect_thresh[4][3][5] = { // Aggressivness = 0 { // Lowres @@ -3347,6 +3375,18 @@ static const float av1_simple_motion_search_prune_rect_thresh[3][3][5] = { 0.067608f, }, }, + // Aggressiveness = 3 + { + // Lowres + { 0.0f, 0.352338114654f, 0.171190796972f, 0.322629318068f, + 0.287219697095f }, + // Midres + { 0.0f, 0.30938393361f, 0.271772875141f, 0.240627957104f, + 0.178833795641f }, + // Hdres + { 0.285731215187f, 0.37521798723f, 0.142380566244f, 0.338288917819f, + 0.21329309279f }, + }, }; // Mean and std diff --git a/media/libaom/src/av1/encoder/partition_strategy.c b/media/libaom/src/av1/encoder/partition_strategy.c index 7170fdda16..cc820ba242 100644 --- a/media/libaom/src/av1/encoder/partition_strategy.c +++ b/media/libaom/src/av1/encoder/partition_strategy.c @@ -25,6 +25,7 @@ #endif #include "av1/encoder/encoder.h" +#include "av1/encoder/motion_search_facade.h" #include "av1/encoder/partition_strategy.h" #include "av1/encoder/rdopt.h" @@ -63,6 +64,10 @@ void av1_intra_mode_cnn_partition(const AV1_COMMON *const cm, MACROBLOCK *x, "Invalid sb_size for intra_cnn!"); const int bsize_idx = convert_bsize_to_idx(bsize); + if (bsize == BLOCK_128X128) { + return; + } + // Precompute the CNN part and cache the result in MACROBLOCK if (bsize == BLOCK_64X64 && !x->cnn_output_valid) { aom_clear_system_state(); @@ -264,7 +269,7 @@ void av1_simple_motion_search_based_split( const float *ml_std = av1_simple_motion_search_split_std[bsize_idx]; const NN_CONFIG *nn_config = av1_simple_motion_search_split_nn_config[bsize_idx]; - const int agg = cpi->sf.simple_motion_search_prune_agg; + const int agg = cpi->sf.part_sf.simple_motion_search_prune_agg; const float split_only_thresh = av1_simple_motion_search_split_thresh[agg][res_idx][bsize_idx]; @@ -291,7 +296,8 @@ void av1_simple_motion_search_based_split( *do_rectangular_split = 0; } - if (cpi->sf.simple_motion_search_split >= 2 && score < no_split_thresh) { + if (cpi->sf.part_sf.simple_motion_search_split >= 2 && + score < no_split_thresh) { *do_square_split = 0; } } @@ -310,7 +316,7 @@ static int simple_motion_search_get_best_ref( const AV1_COMMON *const cm = &cpi->common; int best_ref = -1; - if (mi_col >= cm->mi_cols || mi_row >= cm->mi_rows) { + if (mi_col >= cm->mi_params.mi_cols || mi_row >= cm->mi_params.mi_rows) { // If the whole block is outside of the image, set the var and sse to 0. *best_var = 0; *best_sse = 0; @@ -321,7 +327,6 @@ static int simple_motion_search_get_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; @@ -331,9 +336,11 @@ static int simple_motion_search_get_best_ref( const int ref = refs[ref_idx]; if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref]) { + const FULLPEL_MV *start_mvs = pc_tree->start_mvs; 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); + int_mv best_mv = + av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, + start_mvs[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); @@ -344,18 +351,14 @@ static int simple_motion_search_get_best_ref( } if (save_mv) { - const int new_mv_row = x->best_mv.as_mv.row / 8; - const int new_mv_col = x->best_mv.as_mv.col / 8; - - pc_tree->mv_ref_fulls[ref].row = new_mv_row; - pc_tree->mv_ref_fulls[ref].col = new_mv_col; + pc_tree->start_mvs[ref].row = best_mv.as_mv.row / 8; + pc_tree->start_mvs[ref].col = best_mv.as_mv.col / 8; if (bsize >= BLOCK_8X8) { for (int r_idx = 0; r_idx < 4; r_idx++) { // Propagate the new motion vectors to a lower level PC_TREE *sub_tree = pc_tree->split[r_idx]; - sub_tree->mv_ref_fulls[ref].row = new_mv_row; - sub_tree->mv_ref_fulls[ref].col = new_mv_col; + sub_tree->start_mvs[ref] = pc_tree->start_mvs[ref]; } } } @@ -511,7 +514,7 @@ void av1_simple_motion_search_prune_rect(AV1_COMP *const cpi, MACROBLOCK *x, const float *ml_mean = av1_simple_motion_search_prune_rect_mean[bsize_idx], *ml_std = av1_simple_motion_search_prune_rect_std[bsize_idx]; - const int agg = cpi->sf.simple_motion_search_prune_agg; + const int agg = cpi->sf.part_sf.simple_motion_search_prune_agg; const float prune_thresh = av1_simple_motion_search_prune_rect_thresh[agg][res_idx][bsize_idx]; @@ -542,7 +545,8 @@ void av1_simple_motion_search_prune_rect(AV1_COMP *const cpi, MACROBLOCK *x, 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) && + if (cpi->sf.part_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; @@ -657,14 +661,13 @@ void av1_get_max_min_partition_features(AV1_COMP *const cpi, MACROBLOCK *x, 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); + const FULLPEL_MV start_mv = kZeroFullMv; + int_mv best_mv = av1_simple_motion_sse_var( + cpi, x, this_mi_row, this_mi_col, mb_size, start_mv, 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 mv_row = (float)(best_mv.as_mv.row / 8); + const float mv_col = (float)(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); @@ -717,14 +720,16 @@ BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x, 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); + assert(cpi->sf.part_sf.auto_max_partition_based_on_simple_motion != + NOT_IN_USE); aom_clear_system_state(); av1_nn_predict(features, nn_config, 1, 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) { + if (cpi->sf.part_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) { @@ -733,7 +738,7 @@ BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x, result = i; } } - } else if (cpi->sf.auto_max_partition_based_on_simple_motion == + } else if (cpi->sf.part_sf.auto_max_partition_based_on_simple_motion == RELAXED_PRED) { for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0; --result) { @@ -742,7 +747,8 @@ BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x, } if (probs[result] > 0.2) break; } - } else if (cpi->sf.auto_max_partition_based_on_simple_motion == ADAPT_PRED) { + } else if (cpi->sf.part_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, @@ -848,7 +854,7 @@ void av1_ml_early_term_after_split(AV1_COMP *const cpi, MACROBLOCK *const x, if (!nn_config) return; // Use more conservative threshold for level 1. - if (cpi->sf.ml_early_term_after_part_split_level < 2) thresh -= 0.3f; + if (cpi->sf.part_sf.ml_early_term_after_part_split_level < 2) thresh -= 0.3f; const MACROBLOCKD *const xd = &x->e_mbd; const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8); @@ -1227,23 +1233,23 @@ int av1_ml_predict_breakout(const AV1_COMP *const cpi, BLOCK_SIZE bsize, switch (bsize) { case BLOCK_8X8: nn_config = &av1_partition_breakout_nnconfig_8; - thresh = cpi->sf.ml_partition_search_breakout_thresh[0]; + thresh = cpi->sf.part_sf.ml_partition_search_breakout_thresh[0]; break; case BLOCK_16X16: nn_config = &av1_partition_breakout_nnconfig_16; - thresh = cpi->sf.ml_partition_search_breakout_thresh[1]; + thresh = cpi->sf.part_sf.ml_partition_search_breakout_thresh[1]; break; case BLOCK_32X32: nn_config = &av1_partition_breakout_nnconfig_32; - thresh = cpi->sf.ml_partition_search_breakout_thresh[2]; + thresh = cpi->sf.part_sf.ml_partition_search_breakout_thresh[2]; break; case BLOCK_64X64: nn_config = &av1_partition_breakout_nnconfig_64; - thresh = cpi->sf.ml_partition_search_breakout_thresh[3]; + thresh = cpi->sf.part_sf.ml_partition_search_breakout_thresh[3]; break; case BLOCK_128X128: nn_config = &av1_partition_breakout_nnconfig_128; - thresh = cpi->sf.ml_partition_search_breakout_thresh[4]; + thresh = cpi->sf.part_sf.ml_partition_search_breakout_thresh[4]; break; default: assert(0 && "Unexpected bsize."); } diff --git a/media/libaom/src/av1/encoder/partition_strategy.h b/media/libaom/src/av1/encoder/partition_strategy.h index a4a266c9c5..f9b4d8bfde 100644 --- a/media/libaom/src/av1/encoder/partition_strategy.h +++ b/media/libaom/src/av1/encoder/partition_strategy.h @@ -140,12 +140,14 @@ static INLINE void set_offsets_for_motion_search(const AV1_COMP *const cpi, int mi_row, int mi_col, BLOCK_SIZE bsize) { const AV1_COMMON *const cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; 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_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, 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, @@ -153,27 +155,29 @@ static INLINE void set_offsets_for_motion_search(const AV1_COMP *const cpi, // 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; + av1_set_mv_limits(mi_params, &x->mv_limits, mi_row, mi_col, mi_height, + mi_width, cpi->oxcf.border_in_pixels); set_plane_n4(xd, mi_width, mi_height, num_planes); + xd->mi_row = mi_row; + xd->mi_col = mi_col; + // 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; + xd->mb_to_top_edge = -GET_MV_SUBPEL(mi_row * MI_SIZE); + xd->mb_to_bottom_edge = + GET_MV_SUBPEL((mi_params->mi_rows - mi_height - mi_row) * MI_SIZE); + xd->mb_to_left_edge = -GET_MV_SUBPEL(mi_col * MI_SIZE); + xd->mb_to_right_edge = + GET_MV_SUBPEL((mi_params->mi_cols - mi_width - mi_col) * MI_SIZE); // Set up source buffers. av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, bsize); } static INLINE void init_simple_motion_search_mvs(PC_TREE *pc_tree) { - av1_zero(pc_tree->mv_ref_fulls); + av1_zero(pc_tree->start_mvs); av1_zero(pc_tree->sms_none_feat); av1_zero(pc_tree->sms_rect_feat); @@ -188,24 +192,29 @@ static INLINE void init_simple_motion_search_mvs(PC_TREE *pc_tree) { } } -static INLINE int is_full_sb(AV1_COMMON *const cm, int mi_row, int mi_col, - BLOCK_SIZE sb_size) { +static INLINE int is_full_sb(const CommonModeInfoParams *const mi_params, + 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; + return (mi_row + sb_mi_high) <= mi_params->mi_rows && + (mi_col + sb_mi_wide) <= mi_params->mi_cols; } +// Do not use this criteria for screen content videos. +// Since screen content videos could often find good predictors and the largest +// block size is likely to be used. static INLINE int use_auto_max_partition(AV1_COMP *const cpi, BLOCK_SIZE sb_size, int mi_row, int mi_col) { assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); 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) && + return !frame_is_intra_only(cm) && !cpi->is_screen_content_type && + cpi->sf.part_sf.auto_max_partition_based_on_simple_motion != + NOT_IN_USE && + sb_size == BLOCK_128X128 && + is_full_sb(&cm->mi_params, mi_row, mi_col, sb_size) && cpi->gf_group.update_type[cpi->gf_group.index] != OVERLAY_UPDATE && cpi->gf_group.update_type[cpi->gf_group.index] != INTNL_OVERLAY_UPDATE; } diff --git a/media/libaom/src/av1/encoder/pass2_strategy.c b/media/libaom/src/av1/encoder/pass2_strategy.c index fc0d8976cb..6adc1fbf9d 100644 --- a/media/libaom/src/av1/encoder/pass2_strategy.c +++ b/media/libaom/src/av1/encoder/pass2_strategy.c @@ -19,16 +19,21 @@ #include "aom_ports/system_state.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/encoder/encoder.h" #include "av1/encoder/firstpass.h" #include "av1/encoder/gop_structure.h" +#include "av1/encoder/pass2_strategy.h" #include "av1/encoder/ratectrl.h" +#include "av1/encoder/tpl_model.h" #include "av1/encoder/use_flat_gop_model_params.h" +#include "av1/encoder/encode_strategy.h" #define DEFAULT_KF_BOOST 2300 #define DEFAULT_GF_BOOST 2000 +#define GROUP_ADAPTIVE_MAXQ 1 +static void init_gf_stats(GF_GROUP_STATS *gf_stats); // Calculate an active area of the image that discounts formatting // bars and partially discounts other 0 energy areas. @@ -50,7 +55,10 @@ static double calculate_modified_err(const FRAME_INFO *frame_info, const TWO_PASS *twopass, const AV1EncoderConfig *oxcf, const FIRSTPASS_STATS *this_frame) { - const FIRSTPASS_STATS *const stats = &twopass->total_stats; + const FIRSTPASS_STATS *const stats = twopass->stats_buf_ctx->total_stats; + if (stats == NULL) { + return 0; + } const double av_weight = stats->weight / stats->count; const double av_err = (stats->coded_error * av_weight) / stats->count; double modified_error = @@ -77,17 +85,29 @@ static void reset_fpf_position(TWO_PASS *p, const FIRSTPASS_STATS *position) { } static int input_stats(TWO_PASS *p, FIRSTPASS_STATS *fps) { - if (p->stats_in >= p->stats_in_end) return EOF; + if (p->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF; *fps = *p->stats_in; ++p->stats_in; return 1; } +static int input_stats_lap(TWO_PASS *p, FIRSTPASS_STATS *fps) { + if (p->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF; + + *fps = *p->stats_in; + /* Move old stats[0] out to accommodate for next frame stats */ + memmove(p->frame_stats_arr[0], p->frame_stats_arr[1], + (p->stats_buf_ctx->stats_in_end - p->stats_in - 1) * + sizeof(FIRSTPASS_STATS)); + p->stats_buf_ctx->stats_in_end--; + 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)) { + if ((offset >= 0 && p->stats_in + offset >= p->stats_buf_ctx->stats_in_end) || + (offset < 0 && p->stats_in + offset < p->stats_buf_ctx->stats_in_start)) { return NULL; } @@ -135,25 +155,21 @@ static int frame_max_bits(const RATE_CONTROL *rc, 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. +static const double q_pow_term[(QINDEX_RANGE >> 5) + 1] = { 0.65, 0.70, 0.75, + 0.80, 0.85, 0.90, + 0.95, 0.95, 0.95 }; +#define ERR_DIVISOR 96.0 +static double calc_correction_factor(double err_per_mb, int q) { + const double error_term = err_per_mb / ERR_DIVISOR; + const int index = q >> 5; + // Adjustment to power term based on qindex 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); - + q_pow_term[index] + + (((q_pow_term[index + 1] - q_pow_term[index]) * (q % 32)) / 32.0); + assert(error_term >= 0.0); return fclamp(pow(error_term, power_term), 0.05, 5.0); } -#define ERR_DIVISOR 96.0 -#define FACTOR_PT_LOW 0.70 -#define FACTOR_PT_HIGH 0.90 - static void twopass_update_bpm_factor(TWO_PASS *twopass) { // Based on recent history adjust expectations of bits per macroblock. double last_group_rate_err = @@ -164,11 +180,15 @@ static void twopass_update_bpm_factor(TWO_PASS *twopass) { twopass->bpm_factor = AOMMAX(0.25, AOMMIN(4.0, twopass->bpm_factor)); } +static int qbpm_enumerator(int rate_err_tol) { + return 1350000 + ((300000 * AOMMIN(75, AOMMAX(rate_err_tol - 25, 0))) / 75); +} + // 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 group_weight_factor, int best_qindex, + int desired_bits_per_mb, aom_bit_depth_t bit_depth, double error_per_mb, + double group_weight_factor, int rate_err_tol, int best_qindex, int worst_qindex) { assert(best_qindex <= worst_qindex); int low = best_qindex; @@ -176,25 +196,18 @@ static int find_qindex_by_rate_with_correction( while (low < high) { const int mid = (low + high) >> 1; - const double mid_factor = - calc_correction_factor(error_per_mb, ERR_DIVISOR, 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); + const double mid_factor = calc_correction_factor(error_per_mb, mid); + const double q = av1_convert_qindex_to_q(mid, bit_depth); + const int enumerator = qbpm_enumerator(rate_err_tol); + const int mid_bits_per_mb = + (int)((enumerator * mid_factor * group_weight_factor) / q); + 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, 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; } @@ -212,19 +225,21 @@ static int get_twopass_worst_quality(AV1_COMP *cpi, const double section_err, } else { const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs - : cpi->common.MBs; + : cpi->common.mi_params.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; + int rate_err_tol = + AOMMIN(cpi->oxcf.under_shoot_pct, cpi->oxcf.over_shoot_pct); twopass_update_bpm_factor(&cpi->twopass); // 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, group_weight_factor, rc->best_quality, + target_norm_bits_per_mb, cpi->common.seq_params.bit_depth, + av_err_per_mb, group_weight_factor, rate_err_tol, rc->best_quality, rc->worst_quality); // Restriction on active max q for constrained quality mode. @@ -292,39 +307,35 @@ static double get_prediction_decay_rate(const FRAME_INFO *frame_info, // 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; - +static int detect_transition_to_still(TWO_PASS *const twopass, + const int min_gf_interval, + const int frame_interval, + const int still_interval, + const double loop_decay_rate, + const double last_decay_rate) { // 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 && + if (frame_interval > 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 >= twopass->stats_buf_ctx->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) { +static int detect_flash(const TWO_PASS *twopass, const 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 @@ -339,16 +350,13 @@ static int detect_flash(const TWO_PASS *twopass, int offset) { // 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) { + GF_GROUP_STATS *gf_stats) { 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); + gf_stats->this_frame_mv_in_out = stats->mv_in_out_count * pct; + gf_stats->mv_in_out_accumulator += gf_stats->this_frame_mv_in_out; + gf_stats->abs_mv_in_out_accumulator += fabs(gf_stats->this_frame_mv_in_out); // Accumulate a measure of how uniform (or conversely how random) the motion // field is (a ratio of abs(mv) / mv). @@ -358,13 +366,122 @@ static void accumulate_frame_motion_stats(const FIRSTPASS_STATS *stats, const double mvc_ratio = fabs(stats->mvc_abs) / DOUBLE_DIVIDE_CHECK(fabs(stats->MVc)); - *mv_ratio_accumulator += + gf_stats->mv_ratio_accumulator += pct * (mvr_ratio < stats->mvr_abs ? mvr_ratio : stats->mvr_abs); - *mv_ratio_accumulator += + gf_stats->mv_ratio_accumulator += pct * (mvc_ratio < stats->mvc_abs ? mvc_ratio : stats->mvc_abs); } } +static void accumulate_this_frame_stats(const FIRSTPASS_STATS *stats, + const double mod_frame_err, + GF_GROUP_STATS *gf_stats) { + gf_stats->gf_group_err += mod_frame_err; +#if GROUP_ADAPTIVE_MAXQ + gf_stats->gf_group_raw_error += stats->coded_error; +#endif + gf_stats->gf_group_skip_pct += stats->intra_skip_pct; + gf_stats->gf_group_inactive_zone_rows += stats->inactive_zone_rows; +} + +static void accumulate_next_frame_stats( + const FIRSTPASS_STATS *stats, const FRAME_INFO *frame_info, + TWO_PASS *const twopass, const int flash_detected, + const int frames_since_key, const int cur_idx, const int can_disable_arf, + const int min_gf_interval, GF_GROUP_STATS *gf_stats) { + accumulate_frame_motion_stats(stats, gf_stats); + // sum up the metric values of current gf group + gf_stats->avg_sr_coded_error += stats->sr_coded_error; + gf_stats->avg_tr_coded_error += stats->tr_coded_error; + gf_stats->avg_pcnt_second_ref += stats->pcnt_second_ref; + gf_stats->avg_pcnt_third_ref += stats->pcnt_third_ref; + gf_stats->avg_new_mv_count += stats->new_mv_count; + gf_stats->avg_wavelet_energy += stats->frame_avg_wavelet_energy; + if (fabs(stats->raw_error_stdev) > 0.000001) { + gf_stats->non_zero_stdev_count++; + gf_stats->avg_raw_err_stdev += stats->raw_error_stdev; + } + + // Accumulate the effect of prediction quality decay + if (!flash_detected) { + gf_stats->last_loop_decay_rate = gf_stats->loop_decay_rate; + gf_stats->loop_decay_rate = get_prediction_decay_rate(frame_info, stats); + + gf_stats->decay_accumulator = + gf_stats->decay_accumulator * gf_stats->loop_decay_rate; + + // Monitor for static sections. + if ((frames_since_key + cur_idx - 1) > 1) { + gf_stats->zero_motion_accumulator = + AOMMIN(gf_stats->zero_motion_accumulator, + get_zero_motion_factor(frame_info, stats)); + } + + // Break clause to detect very still sections after motion. For example, + // a static image after a fade or other transition. + if (can_disable_arf && + detect_transition_to_still(twopass, min_gf_interval, cur_idx, 5, + gf_stats->loop_decay_rate, + gf_stats->last_loop_decay_rate)) { + gf_stats->allow_alt_ref = 0; + } + } +} + +static void average_gf_stats(const int total_frame, + const FIRSTPASS_STATS *last_stat, + GF_GROUP_STATS *gf_stats) { + if (total_frame) { + gf_stats->avg_sr_coded_error /= total_frame; + gf_stats->avg_tr_coded_error /= total_frame; + gf_stats->avg_pcnt_second_ref /= total_frame; + if (total_frame - 1) { + gf_stats->avg_pcnt_third_ref_nolast = + (gf_stats->avg_pcnt_third_ref - last_stat->pcnt_third_ref) / + (total_frame - 1); + } else { + gf_stats->avg_pcnt_third_ref_nolast = + gf_stats->avg_pcnt_third_ref / total_frame; + } + gf_stats->avg_pcnt_third_ref /= total_frame; + gf_stats->avg_new_mv_count /= total_frame; + gf_stats->avg_wavelet_energy /= total_frame; + } + + if (gf_stats->non_zero_stdev_count) + gf_stats->avg_raw_err_stdev /= gf_stats->non_zero_stdev_count; +} + +static void get_features_from_gf_stats(const GF_GROUP_STATS *gf_stats, + const GF_FRAME_STATS *first_frame, + const GF_FRAME_STATS *last_frame, + const int num_mbs, + const int constrained_gf_group, + const int kf_zeromotion_pct, + const int num_frames, float *features) { + *features++ = (float)gf_stats->abs_mv_in_out_accumulator; + *features++ = (float)(gf_stats->avg_new_mv_count / num_mbs); + *features++ = (float)gf_stats->avg_pcnt_second_ref; + *features++ = (float)gf_stats->avg_pcnt_third_ref; + *features++ = (float)gf_stats->avg_pcnt_third_ref_nolast; + *features++ = (float)(gf_stats->avg_sr_coded_error / num_mbs); + *features++ = (float)(gf_stats->avg_tr_coded_error / num_mbs); + *features++ = (float)(gf_stats->avg_wavelet_energy / num_mbs); + *features++ = (float)(constrained_gf_group); + *features++ = (float)gf_stats->decay_accumulator; + *features++ = (float)(first_frame->frame_coded_error / num_mbs); + *features++ = (float)(first_frame->frame_sr_coded_error / num_mbs); + *features++ = (float)(first_frame->frame_tr_coded_error / num_mbs); + *features++ = (float)(first_frame->frame_err / num_mbs); + *features++ = (float)(kf_zeromotion_pct); + *features++ = (float)(last_frame->frame_coded_error / num_mbs); + *features++ = (float)(last_frame->frame_sr_coded_error / num_mbs); + *features++ = (float)(last_frame->frame_tr_coded_error / num_mbs); + *features++ = (float)num_frames; + *features++ = (float)gf_stats->mv_ratio_accumulator; + *features++ = (float)gf_stats->non_zero_stdev_count; +} + #define BOOST_FACTOR 12.5 static double baseline_err_per_mb(const FRAME_INFO *frame_info) { unsigned int screen_area = frame_info->frame_height * frame_info->frame_width; @@ -445,20 +562,42 @@ static double calc_kf_frame_boost(const RATE_CONTROL *rc, return AOMMIN(frame_boost, max_boost * boost_q_correction); } +static int get_projected_gfu_boost(const RATE_CONTROL *rc, int gfu_boost, + int frames_to_project, + int num_stats_used_for_gfu_boost) { + /* + * If frames_to_project is equal to num_stats_used_for_gfu_boost, + * it means that gfu_boost was calculated over frames_to_project to + * begin with(ie; all stats required were available), hence return + * the original boost. + */ + if (num_stats_used_for_gfu_boost >= frames_to_project) return gfu_boost; + + double min_boost_factor = sqrt(rc->baseline_gf_interval); + // Get the current tpl factor (number of frames = frames_to_project). + double tpl_factor = av1_get_gfu_boost_projection_factor( + min_boost_factor, MAX_GFUBOOST_FACTOR, frames_to_project); + // Get the tpl factor when number of frames = num_stats_used_for_prior_boost. + double tpl_factor_num_stats = av1_get_gfu_boost_projection_factor( + min_boost_factor, MAX_GFUBOOST_FACTOR, num_stats_used_for_gfu_boost); + int projected_gfu_boost = + (int)rint((tpl_factor * gfu_boost) / tpl_factor_num_stats); + return projected_gfu_boost; +} + #define GF_MAX_BOOST 90.0 #define MIN_DECAY_FACTOR 0.01 int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc, FRAME_INFO *frame_info, int offset, int f_frames, - int b_frames) { + int b_frames, int *num_fpstats_used, + int *num_fpstats_required) { 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; + GF_GROUP_STATS gf_stats; + init_gf_stats(&gf_stats); + double boost_score = (double)NORMAL_BOOST; int arf_boost; int flash_detected = 0; + if (num_fpstats_used) *num_fpstats_used = 0; // Search forward from the proposed arf/next gf position. for (i = 0; i < f_frames; ++i) { @@ -466,9 +605,7 @@ int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc, 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); + accumulate_frame_motion_stats(this_frame, &gf_stats); // We want to discount the flash frame itself and the recovery // frame that follows as both will have poor scores. @@ -477,36 +614,32 @@ int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc, // Accumulate the effect of prediction quality decay. if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(frame_info, this_frame); - decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR - ? MIN_DECAY_FACTOR - : decay_accumulator; + gf_stats.decay_accumulator *= + get_prediction_decay_rate(frame_info, this_frame); + gf_stats.decay_accumulator = gf_stats.decay_accumulator < MIN_DECAY_FACTOR + ? MIN_DECAY_FACTOR + : gf_stats.decay_accumulator; } - boost_score += decay_accumulator * - calc_frame_boost(rc, frame_info, this_frame, - this_frame_mv_in_out, GF_MAX_BOOST); + boost_score += + gf_stats.decay_accumulator * + calc_frame_boost(rc, frame_info, this_frame, + gf_stats.this_frame_mv_in_out, GF_MAX_BOOST); + if (num_fpstats_used) (*num_fpstats_used)++; } arf_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; - + init_gf_stats(&gf_stats); // 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); + accumulate_frame_motion_stats(this_frame, &gf_stats); // We want to discount the the flash frame itself and the recovery // frame that follows as both will have poor scores. @@ -515,21 +648,31 @@ int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc, // Cumulative effect of prediction quality decay. if (!flash_detected) { - decay_accumulator *= get_prediction_decay_rate(frame_info, this_frame); - decay_accumulator = decay_accumulator < MIN_DECAY_FACTOR - ? MIN_DECAY_FACTOR - : decay_accumulator; + gf_stats.decay_accumulator *= + get_prediction_decay_rate(frame_info, this_frame); + gf_stats.decay_accumulator = gf_stats.decay_accumulator < MIN_DECAY_FACTOR + ? MIN_DECAY_FACTOR + : gf_stats.decay_accumulator; } - boost_score += decay_accumulator * - calc_frame_boost(rc, frame_info, this_frame, - this_frame_mv_in_out, GF_MAX_BOOST); + boost_score += + gf_stats.decay_accumulator * + calc_frame_boost(rc, frame_info, this_frame, + gf_stats.this_frame_mv_in_out, GF_MAX_BOOST); + if (num_fpstats_used) (*num_fpstats_used)++; } arf_boost += (int)boost_score; + if (num_fpstats_required) { + *num_fpstats_required = f_frames + b_frames; + if (num_fpstats_used) { + arf_boost = get_projected_gfu_boost(rc, arf_boost, *num_fpstats_required, + *num_fpstats_used); + } + } + if (arf_boost < ((b_frames + f_frames) * 50)) arf_boost = ((b_frames + f_frames) * 50); - arf_boost = AOMMAX(arf_boost, MIN_ARF_GF_BOOST); return arf_boost; } @@ -589,7 +732,9 @@ static int calculate_boost_bits(int frame_count, int boost, 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; + if (!boost || (total_group_bits <= 0)) return 0; + + if (frame_count <= 0) return (int)(AOMMIN(total_group_bits, INT_MAX)); allocation_chunks = (frame_count * 100) + boost; @@ -616,7 +761,8 @@ static int calculate_boost_factor(int frame_count, int bits, // Reduce the number of bits assigned to keyframe or arf if necessary, to // prevent bitrate spikes that may break level constraints. // frame_type: 0: keyframe; 1: arf. -static int adjust_boost_bits_for_target_level(AV1_COMP *const cpi, +static int adjust_boost_bits_for_target_level(const AV1_COMP *const cpi, + RATE_CONTROL *const rc, int bits_assigned, int64_t group_bits, int frame_type) { @@ -631,7 +777,8 @@ static int adjust_boost_bits_for_target_level(AV1_COMP *const cpi, continue; } - const AV1_LEVEL target_level = cpi->target_seq_level_idx[index]; + const AV1_LEVEL target_level = + cpi->level_params.target_seq_level_idx[index]; if (target_level >= SEQ_LEVELS) continue; assert(is_valid_seq_level_idx(target_level)); @@ -640,7 +787,6 @@ static int adjust_boost_bits_for_target_level(AV1_COMP *const cpi, target_level, seq_params->tier[0], seq_params->profile); const int target_bits_per_frame = (int)(level_bitrate_limit / cpi->framerate); - RATE_CONTROL *const rc = &cpi->rc; if (frame_type == 0) { // Maximum bits for keyframe is 8 times the target_bits_per_frame. const int level_enforced_max_kf_bits = target_bits_per_frame * 8; @@ -667,11 +813,87 @@ static int adjust_boost_bits_for_target_level(AV1_COMP *const cpi, return bits_assigned; } -static void allocate_gf_group_bits( - GF_GROUP *gf_group, RATE_CONTROL *const rc, int64_t gf_group_bits, - int gf_arf_bits, int max_bits, - const EncodeFrameParams *const frame_params) { - const int key_frame = (frame_params->frame_type == KEY_FRAME); +// Compile time switch on alternate algorithm to allocate bits in ARF groups +// #define ALT_ARF_ALLOCATION +#ifdef ALT_ARF_ALLOCATION +double layer_fraction[MAX_ARF_LAYERS + 1] = { 1.0, 0.70, 0.55, 0.60, + 0.60, 1.0, 1.0 }; +static void allocate_gf_group_bits(GF_GROUP *gf_group, RATE_CONTROL *const rc, + int64_t gf_group_bits, int gf_arf_bits, + int key_frame, int use_arf) { + int64_t total_group_bits = gf_group_bits; + int base_frame_bits; + const int gf_group_size = gf_group->size; + int layer_frames[MAX_ARF_LAYERS + 1] = { 0 }; + + // Subtract the extra bits set aside for ARF frames from the Group Total + if (use_arf || !key_frame) total_group_bits -= gf_arf_bits; + + if (rc->baseline_gf_interval) + base_frame_bits = (int)(total_group_bits / rc->baseline_gf_interval); + else + base_frame_bits = (int)1; + + // 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] = + base_frame_bits + (int)(gf_arf_bits * layer_fraction[1]); + } + frame_index++; + + // Check the number of frames in each layer in case we have a + // non standard group length. + int max_arf_layer = gf_group->max_layer_depth - 1; + for (int idx = frame_index; idx < gf_group_size; ++idx) { + if ((gf_group->update_type[idx] == ARF_UPDATE) || + (gf_group->update_type[idx] == INTNL_ARF_UPDATE)) { + // max_arf_layer = AOMMAX(max_arf_layer, gf_group->layer_depth[idx]); + layer_frames[gf_group->layer_depth[idx]]++; + } + } + + // Allocate extra bits to each ARF layer + int i; + int layer_extra_bits[MAX_ARF_LAYERS + 1] = { 0 }; + for (i = 1; i <= max_arf_layer; ++i) { + double fraction = (i == max_arf_layer) ? 1.0 : layer_fraction[i]; + layer_extra_bits[i] = + (int)((gf_arf_bits * fraction) / AOMMAX(1, layer_frames[i])); + gf_arf_bits -= (int)(gf_arf_bits * fraction); + } + + // Now combine ARF layer and baseline bits to give total bits for each frame. + int arf_extra_bits; + for (int idx = frame_index; idx < gf_group_size; ++idx) { + switch (gf_group->update_type[idx]) { + case ARF_UPDATE: + case INTNL_ARF_UPDATE: + arf_extra_bits = layer_extra_bits[gf_group->layer_depth[idx]]; + gf_group->bit_allocation[idx] = base_frame_bits + arf_extra_bits; + break; + case INTNL_OVERLAY_UPDATE: + case OVERLAY_UPDATE: gf_group->bit_allocation[idx] = 0; break; + default: gf_group->bit_allocation[idx] = base_frame_bits; break; + } + } + + // Set the frame following the current GOP to 0 bit allocation. For ARF + // groups, this next frame will be overlay frame, which is the first frame + // in the next GOP. For GF group, next GOP will overwrite the rate allocation. + // Setting this frame to use 0 bit (of out the current GOP budget) will + // simplify logics in reference frame management. + gf_group->bit_allocation[gf_group_size] = 0; +} +#else +static void allocate_gf_group_bits(GF_GROUP *gf_group, RATE_CONTROL *const rc, + int64_t gf_group_bits, int gf_arf_bits, + int key_frame, int use_arf) { int64_t total_group_bits = gf_group_bits; // For key frames the frame target rate is already set and it @@ -687,13 +909,13 @@ static void allocate_gf_group_bits( // 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; + if (use_arf || !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) { + if (use_arf) { gf_group->bit_allocation[frame_index] = gf_arf_bits; ++frame_index; } @@ -702,52 +924,40 @@ static void allocate_gf_group_bits( int arf_depth_bits[MAX_ARF_LAYERS + 1] = { 0 }; int arf_depth_count[MAX_ARF_LAYERS + 1] = { 0 }; int arf_depth_boost[MAX_ARF_LAYERS + 1] = { 0 }; - int total_arfs = rc->source_alt_ref_pending; + int total_arfs = 0; + int total_overlays = rc->source_alt_ref_active; for (int idx = 0; idx < gf_group_size; ++idx) { if (gf_group->update_type[idx] == ARF_UPDATE || - gf_group->update_type[idx] == INTNL_ARF_UPDATE) { + gf_group->update_type[idx] == INTNL_ARF_UPDATE || + gf_group->update_type[idx] == LF_UPDATE) { arf_depth_boost[gf_group->layer_depth[idx]] += gf_group->arf_boost[idx]; ++arf_depth_count[gf_group->layer_depth[idx]]; } } - for (int idx = 2; idx < MAX_ARF_LAYERS; ++idx) { - if (arf_depth_boost[idx] == 0) break; - arf_depth_bits[idx] = calculate_boost_bits( - rc->baseline_gf_interval - total_arfs - arf_depth_count[idx], - arf_depth_boost[idx], total_group_bits); - + for (int idx = 2; idx <= MAX_ARF_LAYERS; ++idx) { + arf_depth_bits[idx] = + calculate_boost_bits(rc->baseline_gf_interval - total_arfs - + total_overlays - arf_depth_count[idx], + arf_depth_boost[idx], total_group_bits); total_group_bits -= arf_depth_bits[idx]; total_arfs += arf_depth_count[idx]; } - int normal_frames = rc->baseline_gf_interval - total_arfs; - int normal_frame_bits; - - if (normal_frames > 1) - normal_frame_bits = (int)(total_group_bits / normal_frames); - else - normal_frame_bits = (int)total_group_bits; - - // TODO(jingning): Currently assume even budget distribution for all the - // regular frames. Can this be improved? - int target_frame_size = normal_frame_bits; - target_frame_size = - clamp(target_frame_size, 0, AOMMIN(max_bits, (int)total_group_bits)); - for (int idx = frame_index; idx < gf_group_size; ++idx) { switch (gf_group->update_type[idx]) { case ARF_UPDATE: case INTNL_ARF_UPDATE: + case LF_UPDATE: gf_group->bit_allocation[idx] = (int)(((int64_t)arf_depth_bits[gf_group->layer_depth[idx]] * gf_group->arf_boost[idx]) / arf_depth_boost[gf_group->layer_depth[idx]]); break; case INTNL_OVERLAY_UPDATE: - case OVERLAY_UPDATE: gf_group->bit_allocation[idx] = 0; break; - default: gf_group->bit_allocation[idx] = target_frame_size; break; + case OVERLAY_UPDATE: + default: gf_group->bit_allocation[idx] = 0; break; } } @@ -758,13 +968,7 @@ static void allocate_gf_group_bits( // simplify logics in reference frame management. gf_group->bit_allocation[gf_group_size] = 0; } - -// 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; -} +#endif // 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) { @@ -773,12 +977,451 @@ static INLINE int is_almost_static(double gf_zero_motion, int kf_zero_motion) { } #define ARF_ABS_ZOOM_THRESH 4.4 -#define GROUP_ADAPTIVE_MAXQ 1 +static INLINE int detect_gf_cut(AV1_COMP *cpi, int frame_index, int cur_start, + int flash_detected, int active_max_gf_interval, + int active_min_gf_interval, + GF_GROUP_STATS *gf_stats) { + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + // Motion breakout threshold for loop below depends on image size. + const double mv_ratio_accumulator_thresh = + (cpi->initial_height + cpi->initial_width) / 4.0; + + if (!flash_detected) { + // 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( + twopass, rc->min_gf_interval, frame_index - cur_start, 5, + gf_stats->loop_decay_rate, gf_stats->last_loop_decay_rate)) { + return 1; + } + } + + // Some conditions to breakout after min interval. + if (frame_index - cur_start >= active_min_gf_interval && + // If possible don't break very close to a kf + (rc->frames_to_key - frame_index >= rc->min_gf_interval) && + ((frame_index - cur_start) & 0x01) && !flash_detected && + (gf_stats->mv_ratio_accumulator > mv_ratio_accumulator_thresh || + gf_stats->abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) { + return 1; + } + + // If almost totally static, we will not use the the max GF length later, + // so we can continue for more frames. + if (((frame_index - cur_start) >= active_max_gf_interval + 1) && + !is_almost_static(gf_stats->zero_motion_accumulator, + twopass->kf_zeromotion_pct)) { + return 1; + } + return 0; +} + +#define MAX_PAD_GF_CHECK 6 // padding length to check for gf length +#define AVG_SI_THRES 0.6 // thres for average silouette +#define GF_SHRINK_OUTPUT 0 // print output for gf length decision +int determine_high_err_gf(double *errs, int *is_high, double *si, int len, + double *ratio, int gf_start, int gf_end, + int before_pad) { + (void)gf_start; + (void)gf_end; + (void)before_pad; + // alpha and beta controls the threshold placement + // e.g. a smaller alpha makes the lower group more rigid + const double alpha = 0.5; + const double beta = 1 - alpha; + double mean = 0; + double mean_low = 0; + double mean_high = 0; + double prev_mean_low = 0; + double prev_mean_high = 0; + int count_low = 0; + int count_high = 0; + // calculate mean of errs + for (int i = 0; i < len; i++) { + mean += errs[i]; + } + mean /= len; + // separate into two initial groups with greater / lower than mean + for (int i = 0; i < len; i++) { + if (errs[i] <= mean) { + is_high[i] = 0; + count_low++; + prev_mean_low += errs[i]; + } else { + is_high[i] = 1; + count_high++; + prev_mean_high += errs[i]; + } + } + prev_mean_low /= count_low; + prev_mean_high /= count_high; + // kmeans to refine + int count = 0; + while (count < 10) { + // re-group + mean_low = 0; + mean_high = 0; + count_low = 0; + count_high = 0; + double thres = prev_mean_low * alpha + prev_mean_high * beta; + for (int i = 0; i < len; i++) { + if (errs[i] <= thres) { + is_high[i] = 0; + count_low++; + mean_low += errs[i]; + } else { + is_high[i] = 1; + count_high++; + mean_high += errs[i]; + } + } + mean_low /= count_low; + mean_high /= count_high; + + // break if not changed much + if (fabs((mean_low - prev_mean_low) / (prev_mean_low + 0.00001)) < + 0.00001 && + fabs((mean_high - prev_mean_high) / (prev_mean_high + 0.00001)) < + 0.00001) + break; + + // update means + prev_mean_high = mean_high; + prev_mean_low = mean_low; + + count++; + } + + // count how many jumps of group changes + int num_change = 0; + for (int i = 0; i < len - 1; i++) { + if (is_high[i] != is_high[i + 1]) num_change++; + } + + // get silhouette as a measure of the classification quality + double avg_si = 0; + // ai: avg dist of its own class, bi: avg dist to the other class + double ai, bi; + if (count_low > 1 && count_high > 1) { + for (int i = 0; i < len; i++) { + ai = 0; + bi = 0; + // calculate average distance to everyone in the same group + // and in the other group + for (int j = 0; j < len; j++) { + if (i == j) continue; + if (is_high[i] == is_high[j]) { + ai += fabs(errs[i] - errs[j]); + } else { + bi += fabs(errs[i] - errs[j]); + } + } + if (is_high[i] == 0) { + ai = ai / (count_low - 1); + bi = bi / count_high; + } else { + ai = ai / (count_high - 1); + bi = bi / count_low; + } + if (ai <= bi) { + si[i] = 1 - ai / (bi + 0.00001); + } else { + si[i] = bi / (ai + 0.00001) - 1; + } + avg_si += si[i]; + } + avg_si /= len; + } + + int reset = 0; + *ratio = mean_high / (mean_low + 0.00001); + // if the two groups too similar, or + // if too many numbers of changes, or + // silhouette is too small, not confident + // reset everything to 0 later so we fallback to the original decision + if (*ratio < 1.3 || num_change > AOMMAX(len / 3, 6) || + avg_si < AVG_SI_THRES) { + reset = 1; + } + +#if GF_SHRINK_OUTPUT + printf("\n"); + for (int i = 0; i < len; i++) { + printf("%d: err %.1f, ishigh %d, si %.2f, (i=%d)\n", + gf_start + i - before_pad, errs[i], is_high[i], si[i], gf_end); + } + printf( + "count: %d, mean_high: %.1f, mean_low: %.1f, avg_si: %.2f, num_change: " + "%d, ratio %.2f, reset: %d\n", + count, mean_high, mean_low, avg_si, num_change, + mean_high / (mean_low + 0.000001), reset); +#endif + + if (reset) { + memset(is_high, 0, sizeof(is_high[0]) * len); + memset(si, 0, sizeof(si[0]) * len); + } + return reset; +} + #if GROUP_ADAPTIVE_MAXQ #define RC_FACTOR_MIN 0.75 -#define RC_FACTOR_MAX 1.75 +#define RC_FACTOR_MAX 1.25 #endif // GROUP_ADAPTIVE_MAXQ #define MIN_FWD_KF_INTERVAL 8 +#define MIN_SHRINK_LEN 6 // the minimum length of gf if we are shrinking +#define SI_HIGH AVG_SI_THRES // high quality classification +#define SI_LOW 0.3 // very unsure classification +// this function finds an low error frame previously to the current last frame +// in the gf group, and set the last frame to it. +// The resulting last frame is then returned by *cur_last_ptr +// *cur_start_ptr and cut_pos[n] could also change due to shrinking +// previous gf groups +void set_last_prev_low_err(int *cur_start_ptr, int *cur_last_ptr, int *cut_pos, + int count_cuts, int before_pad, double ratio, + int *is_high, double *si, int prev_lows) { + int n; + int cur_start = *cur_start_ptr; + int cur_last = *cur_last_ptr; + for (n = cur_last; n >= cur_start + MIN_SHRINK_LEN; n--) { + // try to find a point that is very probable to be good + if (is_high[n - cur_start + before_pad] == 0 && + si[n - cur_start + before_pad] > SI_HIGH) { + *cur_last_ptr = n; + return; + } + } + // could not find a low-err point, then let's try find an "unsure" + // point at least + for (n = cur_last; n >= cur_start + MIN_SHRINK_LEN; n--) { + if ((is_high[n - cur_start + before_pad] == 0) || + (is_high[n - cur_start + before_pad] && + si[n - cur_start + before_pad] < SI_LOW)) { + *cur_last_ptr = n; + return; + } + } + if (prev_lows) { + // try with shrinking previous all_zero interval + for (n = cur_start + MIN_SHRINK_LEN - 1; n > cur_start; n--) { + if (is_high[n - cur_start + before_pad] == 0 && + si[n - cur_start + before_pad] > SI_HIGH) { + int tentative_start = n - MIN_SHRINK_LEN; + // check if the previous interval can shrink this much + int available = + tentative_start - cut_pos[count_cuts - 2] > MIN_SHRINK_LEN && + cur_start - tentative_start < prev_lows; + // shrinking too agressively may worsen performance + // set stricter thres for shorter length + double ratio_thres = + 1.0 * (cur_start - tentative_start) / (double)(MIN_SHRINK_LEN) + + 1.0; + + if (available && (ratio > ratio_thres)) { + cut_pos[count_cuts - 1] = tentative_start; + *cur_start_ptr = tentative_start; + *cur_last_ptr = n; + return; + } + } + } + } + if (prev_lows) { + // try with shrinking previous all_zero interval with unsure points + for (n = cur_start + MIN_SHRINK_LEN - 1; n > cur_start; n--) { + if ((is_high[n - cur_start + before_pad] == 0) || + (is_high[n - cur_start + before_pad] && + si[n - cur_start + before_pad] < SI_LOW)) { + int tentative_start = n - MIN_SHRINK_LEN; + // check if the previous interval can shrink this much + int available = + tentative_start - cut_pos[count_cuts - 2] > MIN_SHRINK_LEN && + cur_start - tentative_start < prev_lows; + // shrinking too agressively may worsen performance + double ratio_thres = + 1.0 * (cur_start - tentative_start) / (double)(MIN_SHRINK_LEN) + + 1.0; + + if (available && (ratio > ratio_thres)) { + cut_pos[count_cuts - 1] = tentative_start; + *cur_start_ptr = tentative_start; + *cur_last_ptr = n; + return; + } + } + } + } // prev_lows + return; +} + +// This function decides the gf group length of future frames in batch +// rc->gf_intervals is modified to store the group lengths +static void calculate_gf_length(AV1_COMP *cpi, int max_gop_length, + int max_intervals) { + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + FIRSTPASS_STATS next_frame; + const FIRSTPASS_STATS *const start_pos = twopass->stats_in; + FRAME_INFO *frame_info = &cpi->frame_info; + int i; + + int flash_detected; + + aom_clear_system_state(); + av1_zero(next_frame); + + if (has_no_stats_stage(cpi)) { + for (i = 0; i < MAX_NUM_GF_INTERVALS; i++) { + rc->gf_intervals[i] = AOMMIN(rc->max_gf_interval, max_gop_length); + } + rc->cur_gf_index = 0; + rc->intervals_till_gf_calculate_due = MAX_NUM_GF_INTERVALS; + return; + } + + // 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, max_gop_length); + + i = 0; + max_intervals = cpi->lap_enabled ? 1 : max_intervals; + int cut_pos[MAX_NUM_GF_INTERVALS + 1] = { 0 }; + int count_cuts = 1; + int cur_start = 0, cur_last; + int cut_here; + int prev_lows = 0; + GF_GROUP_STATS gf_stats; + init_gf_stats(&gf_stats); + while (count_cuts < max_intervals + 1) { + ++i; + + // reaches next key frame, break here + if (i >= rc->frames_to_key) { + cut_pos[count_cuts] = i - 1; + count_cuts++; + break; + } + + // reached maximum len, but nothing special yet (almost static) + // let's look at the next interval + if (i - cur_start >= rc->static_scene_max_gf_interval) { + cut_here = 1; + } else { + // reaches last frame, break + if (EOF == input_stats(twopass, &next_frame)) { + cut_pos[count_cuts] = i - 1; + count_cuts++; + 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); + // TODO(bohanli): remove redundant accumulations here, or unify + // this and the ones in define_gf_group + accumulate_next_frame_stats(&next_frame, frame_info, twopass, + flash_detected, rc->frames_since_key, i, 0, + rc->min_gf_interval, &gf_stats); + + cut_here = detect_gf_cut(cpi, i, cur_start, flash_detected, + active_max_gf_interval, active_min_gf_interval, + &gf_stats); + } + if (cut_here) { + cur_last = i - 1; // the current last frame in the gf group + // only try shrinking if interval smaller than active_max_gf_interval + if (cur_last - cur_start <= active_max_gf_interval) { + // determine in the current decided gop the higher and lower errs + int n; + double ratio; + + // load neighboring coded errs + int is_high[MAX_GF_INTERVAL + 1 + MAX_PAD_GF_CHECK * 2] = { 0 }; + double errs[MAX_GF_INTERVAL + 1 + MAX_PAD_GF_CHECK * 2] = { 0 }; + double si[MAX_GF_INTERVAL + 1 + MAX_PAD_GF_CHECK * 2] = { 0 }; + int before_pad = + AOMMIN(MAX_PAD_GF_CHECK, rc->frames_since_key - 1 + cur_start); + int after_pad = + AOMMIN(MAX_PAD_GF_CHECK, rc->frames_to_key - cur_last - 1); + for (n = cur_start - before_pad; n <= cur_last + after_pad; n++) { + if (start_pos + n - 1 > twopass->stats_buf_ctx->stats_in_end) { + after_pad = n - cur_last - 1; + assert(after_pad >= 0); + break; + } else if (start_pos + n - 1 < + twopass->stats_buf_ctx->stats_in_start) { + before_pad = cur_start - n - 1; + continue; + } + errs[n + before_pad - cur_start] = (start_pos + n - 1)->coded_error; + } + const int len = before_pad + after_pad + cur_last - cur_start + 1; + const int reset = determine_high_err_gf( + errs, is_high, si, len, &ratio, cur_start, cur_last, before_pad); + + // if the current frame may have high error, try shrinking + if (is_high[cur_last - cur_start + before_pad] == 1 || + (!reset && si[cur_last - cur_start + before_pad] < SI_LOW)) { + // try not to cut in high err area + set_last_prev_low_err(&cur_start, &cur_last, cut_pos, count_cuts, + before_pad, ratio, is_high, si, prev_lows); + } // if current frame high error + // count how many trailing lower error frames we have in this decided + // gf group + prev_lows = 0; + for (n = cur_last - 1; n > cur_start + MIN_SHRINK_LEN; n--) { + if (is_high[n - cur_start + before_pad] == 0 && + (si[n - cur_start + before_pad] > SI_HIGH || reset)) { + prev_lows++; + } else { + break; + } + } + } + cut_pos[count_cuts] = cur_last; + count_cuts++; + + // reset pointers to the shrinked location + twopass->stats_in = start_pos + cur_last; + cur_start = cur_last; + i = cur_last; + + // reset accumulators + init_gf_stats(&gf_stats); + } + } + + // save intervals + rc->intervals_till_gf_calculate_due = count_cuts - 1; + for (int n = 1; n < count_cuts; n++) { + rc->gf_intervals[n - 1] = cut_pos[n] + 1 - cut_pos[n - 1]; + } + rc->cur_gf_index = 0; + twopass->stats_in = start_pos; + +#if GF_SHRINK_OUTPUT + printf("\nf_to_key: %d, count_cut: %d. ", rc->frames_to_key, count_cuts); + for (int n = 0; n < count_cuts; n++) { + printf("%d ", cut_pos[n]); + } + printf("\n"); + + for (int n = 0; n < rc->intervals_till_gf_calculate_due; n++) { + printf("%d ", rc->gf_intervals[n]); + } + printf("\n\n"); +#endif +} + +static void correct_frames_to_key(AV1_COMP *cpi) { + int lookahead_size = + (int)av1_lookahead_depth(cpi->lookahead, cpi->compressor_stage) + 1; + if (lookahead_size < + av1_lookahead_pop_sz(cpi->lookahead, cpi->compressor_stage)) { + cpi->rc.frames_to_key = AOMMIN(cpi->rc.frames_to_key, lookahead_size); + } +} static void define_gf_group_pass0(AV1_COMP *cpi, const EncodeFrameParams *const frame_params) { @@ -786,10 +1429,16 @@ static void define_gf_group_pass0(AV1_COMP *cpi, GF_GROUP *const gf_group = &cpi->gf_group; int target; - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_set_golden_update(cpi); - else - rc->baseline_gf_interval = MAX_GF_INTERVAL; + } else { + rc->baseline_gf_interval = rc->gf_intervals[rc->cur_gf_index]; + rc->intervals_till_gf_calculate_due--; + rc->cur_gf_index++; + } + + // correct frames_to_key when lookahead queue is flushing + correct_frames_to_key(cpi); if (rc->baseline_gf_interval > rc->frames_to_key) rc->baseline_gf_interval = rc->frames_to_key; @@ -830,10 +1479,77 @@ static void define_gf_group_pass0(AV1_COMP *cpi, } } +static INLINE void set_baseline_gf_interval(AV1_COMP *cpi, int arf_position, + int active_max_gf_interval, + int use_alt_ref, + int is_final_pass) { + RATE_CONTROL *const rc = &cpi->rc; + TWO_PASS *const twopass = &cpi->twopass; + // 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 && use_alt_ref && + ((twopass->stats_in - arf_position + rc->frames_to_key) < + twopass->stats_buf_ctx->stats_in_end) && + cpi->rc.next_is_fwd_key) { + if (arf_position == rc->frames_to_key) { + rc->baseline_gf_interval = arf_position; + // if the last gf group will be smaller than MIN_FWD_KF_INTERVAL + } else if ((rc->frames_to_key - arf_position < + AOMMAX(MIN_FWD_KF_INTERVAL, rc->min_gf_interval)) && + (rc->frames_to_key != arf_position)) { + // 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 (is_final_pass) rc->intervals_till_gf_calculate_due = 0; + // 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; + if (is_final_pass) rc->intervals_till_gf_calculate_due = 0; + } + } else { + rc->baseline_gf_interval = arf_position - rc->source_alt_ref_pending; + } + } else { + rc->baseline_gf_interval = arf_position - rc->source_alt_ref_pending; + } +} + +// initialize GF_GROUP_STATS +static void init_gf_stats(GF_GROUP_STATS *gf_stats) { + gf_stats->gf_group_err = 0.0; + gf_stats->gf_group_raw_error = 0.0; + gf_stats->gf_group_skip_pct = 0.0; + gf_stats->gf_group_inactive_zone_rows = 0.0; + + gf_stats->mv_ratio_accumulator = 0.0; + gf_stats->decay_accumulator = 1.0; + gf_stats->zero_motion_accumulator = 1.0; + gf_stats->loop_decay_rate = 1.0; + gf_stats->last_loop_decay_rate = 1.0; + gf_stats->this_frame_mv_in_out = 0.0; + gf_stats->mv_in_out_accumulator = 0.0; + gf_stats->abs_mv_in_out_accumulator = 0.0; + + gf_stats->avg_sr_coded_error = 0.0; + gf_stats->avg_tr_coded_error = 0.0; + gf_stats->avg_pcnt_second_ref = 0.0; + gf_stats->avg_pcnt_third_ref = 0.0; + gf_stats->avg_pcnt_third_ref_nolast = 0.0; + gf_stats->avg_new_mv_count = 0.0; + gf_stats->avg_wavelet_energy = 0.0; + gf_stats->avg_raw_err_stdev = 0.0; + gf_stats->non_zero_stdev_count = 0; + + gf_stats->allow_alt_ref = 0; +} + // Analyse and define a gf/arf group. #define MAX_GF_BOOST 5400 static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, - const EncodeFrameParams *const frame_params) { + const EncodeFrameParams *const frame_params, + int max_gop_length, int is_final_pass) { AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; AV1EncoderConfig *const oxcf = &cpi->oxcf; @@ -844,32 +1560,8 @@ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, FRAME_INFO *frame_info = &cpi->frame_info; 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 flash_detected; int64_t gf_group_bits; - 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; @@ -885,215 +1577,133 @@ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, aom_clear_system_state(); av1_zero(next_frame); - if (oxcf->pass == 0) { + if (has_no_stats_stage(cpi)) { define_gf_group_pass0(cpi, frame_params); return; } + // correct frames_to_key when lookahead queue is emptying + if (cpi->lap_enabled) { + correct_frames_to_key(cpi); + } + + GF_GROUP_STATS gf_stats; + init_gf_stats(&gf_stats); + GF_FRAME_STATS first_frame_stats, last_frame_stats; + + gf_stats.allow_alt_ref = is_altref_enabled(cpi); + const int can_disable_arf = (oxcf->gf_min_pyr_height == MIN_PYRAMID_LVL); + // Load stats for the current frame. - mod_frame_err = calculate_modified_err(frame_info, twopass, oxcf, this_frame); + double mod_frame_err = + calculate_modified_err(frame_info, 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; - - const double first_frame_coded_error = this_frame->coded_error; - const double first_frame_sr_coded_error = this_frame->sr_coded_error; - const double first_frame_tr_coded_error = this_frame->tr_coded_error; + first_frame_stats.frame_err = mod_frame_err; + first_frame_stats.frame_coded_error = this_frame->coded_error; + first_frame_stats.frame_sr_coded_error = this_frame->sr_coded_error; + first_frame_stats.frame_tr_coded_error = this_frame->tr_coded_error; // 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; + gf_stats.gf_group_err -= first_frame_stats.frame_err; #if GROUP_ADAPTIVE_MAXQ - gf_group_raw_error -= this_frame->coded_error; + gf_stats.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; + gf_stats.gf_group_skip_pct -= this_frame->intra_skip_pct; + gf_stats.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_tr_coded_error = 0; - - double avg_pcnt_second_ref = 0; - double avg_pcnt_third_ref = 0; - - double avg_new_mv_count = 0; - - double avg_wavelet_energy = 0; - - double avg_raw_err_stdev = 0; - int non_zero_stdev_count = 0; + AOMMIN(rc->max_gf_interval, max_gop_length); i = 0; - while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) { + // get the determined gf group length from rc->gf_intervals + while (i < rc->gf_intervals[rc->cur_gf_index]) { ++i; - // Accumulate error score of frames in this gf group. mod_frame_err = calculate_modified_err(frame_info, 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; + // accumulate stats for this frame + accumulate_this_frame_stats(this_frame, mod_frame_err, &gf_stats); + // read in the next frame 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; - avg_tr_coded_error += next_frame.tr_coded_error; - avg_pcnt_second_ref += next_frame.pcnt_second_ref; - avg_pcnt_third_ref += next_frame.pcnt_third_ref; - avg_new_mv_count += next_frame.new_mv_count; - avg_wavelet_energy += next_frame.frame_avg_wavelet_energy; - if (fabs(next_frame.raw_error_stdev) > 0.000001) { - non_zero_stdev_count++; - avg_raw_err_stdev += next_frame.raw_error_stdev; - } + // accumulate stats for next frame + accumulate_next_frame_stats( + &next_frame, frame_info, twopass, flash_detected, rc->frames_since_key, + i, can_disable_arf, rc->min_gf_interval, &gf_stats); - // Accumulate the effect of prediction quality decay. - if (!flash_detected) { - last_loop_decay_rate = loop_decay_rate; - loop_decay_rate = get_prediction_decay_rate(frame_info, &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(frame_info, &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(rc, frame_info, &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; } + // save the errs for the last frame + last_frame_stats.frame_coded_error = next_frame.coded_error; + last_frame_stats.frame_sr_coded_error = next_frame.sr_coded_error; + last_frame_stats.frame_tr_coded_error = next_frame.tr_coded_error; + + if (is_final_pass) { + rc->intervals_till_gf_calculate_due--; + rc->cur_gf_index++; + } // 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; + const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) + ? cpi->initial_mbs + : cm->mi_params.MBs; assert(num_mbs > 0); - const double last_frame_coded_error = next_frame.coded_error; - const double last_frame_sr_coded_error = next_frame.sr_coded_error; - const double last_frame_tr_coded_error = next_frame.tr_coded_error; - double avg_pcnt_third_ref_nolast = avg_pcnt_third_ref; - if (i) { - avg_sr_coded_error /= i; - avg_tr_coded_error /= i; - avg_pcnt_second_ref /= i; - if (i - 1) { - avg_pcnt_third_ref_nolast = - (avg_pcnt_third_ref - next_frame.pcnt_third_ref) / (i - 1); - } else { - avg_pcnt_third_ref_nolast = avg_pcnt_third_ref / i; - } - avg_pcnt_third_ref /= i; - avg_new_mv_count /= i; - avg_wavelet_energy /= i; - } - if (non_zero_stdev_count) avg_raw_err_stdev /= non_zero_stdev_count; + average_gf_stats(i, &next_frame, &gf_stats); // 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) { + const int can_disable_internal_arfs = + (oxcf->gf_min_pyr_height <= MIN_PYRAMID_LVL + 1); + if (can_disable_internal_arfs && + gf_stats.zero_motion_accumulator > MIN_ZERO_MOTION && + gf_stats.avg_sr_coded_error / num_mbs < MAX_SR_CODED_ERROR && + gf_stats.avg_raw_err_stdev < MAX_RAW_ERR_VAR) { cpi->internal_altref_allowed = 0; } - 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); + int use_alt_ref; + if (can_disable_arf) { + use_alt_ref = !is_almost_static(gf_stats.zero_motion_accumulator, + twopass->kf_zeromotion_pct) && + gf_stats.allow_alt_ref && (i < cpi->oxcf.lag_in_frames) && + (i >= MIN_GF_INTERVAL) && + (cpi->oxcf.gf_max_pyr_height > MIN_PYRAMID_LVL); - // TODO(urvang): Improve and use model for VBR, CQ etc as well. - if (use_alt_ref && cpi->oxcf.rc_mode == AOM_Q && cpi->oxcf.cq_level <= 200) { - aom_clear_system_state(); - - /* clang-format off */ - // Generate features. - const float features[] = { - (float)abs_mv_in_out_accumulator, - (float)(avg_new_mv_count / num_mbs), - (float)avg_pcnt_second_ref, - (float)avg_pcnt_third_ref, - (float)avg_pcnt_third_ref_nolast, - (float)(avg_sr_coded_error / num_mbs), - (float)(avg_tr_coded_error / num_mbs), - (float)(avg_wavelet_energy / num_mbs), - (float)(rc->constrained_gf_group), - (float)decay_accumulator, - (float)(first_frame_coded_error / num_mbs), - (float)(first_frame_sr_coded_error / num_mbs), - (float)(first_frame_tr_coded_error / num_mbs), - (float)(gf_first_frame_err / num_mbs), - (float)(twopass->kf_zeromotion_pct), - (float)(last_frame_coded_error / num_mbs), - (float)(last_frame_sr_coded_error / num_mbs), - (float)(last_frame_tr_coded_error / num_mbs), - (float)i, - (float)mv_ratio_accumulator, - (float)non_zero_stdev_count - }; - /* clang-format on */ - // Infer using ML model. - float score; - av1_nn_predict(features, &av1_use_flat_gop_nn_config, 1, &score); - use_alt_ref = (score <= 0.0); + // TODO(urvang): Improve and use model for VBR, CQ etc as well. + if (use_alt_ref && cpi->oxcf.rc_mode == AOM_Q && + cpi->oxcf.cq_level <= 200) { + aom_clear_system_state(); + float features[21]; + get_features_from_gf_stats( + &gf_stats, &first_frame_stats, &last_frame_stats, num_mbs, + rc->constrained_gf_group, twopass->kf_zeromotion_pct, i, features); + // Infer using ML model. + float score; + av1_nn_predict(features, &av1_use_flat_gop_nn_config, 1, &score); + use_alt_ref = (score <= 0.0); + } + } else { + assert(cpi->oxcf.gf_max_pyr_height > MIN_PYRAMID_LVL); + use_alt_ref = + gf_stats.allow_alt_ref && (i < cpi->oxcf.lag_in_frames) && (i > 2); } #define REDUCE_GF_LENGTH_THRESH 4 @@ -1129,54 +1739,50 @@ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, if (i - roll_back >= active_min_gf_interval + 1) { alt_offset = -roll_back; i -= roll_back; + if (is_final_pass) rc->intervals_till_gf_calculate_due = 0; } } } // Should we use the alternate reference frame. if (use_alt_ref) { + rc->source_alt_ref_pending = 1; + gf_group->max_layer_depth_allowed = cpi->oxcf.gf_max_pyr_height; + set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref, + is_final_pass); + const int forward_frames = (rc->frames_to_key - i >= i - 1) ? i - 1 : AOMMAX(0, rc->frames_to_key - i); // Calculate the boost for alt ref. - rc->gfu_boost = av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, - forward_frames, (i - 1)); - rc->source_alt_ref_pending = 1; - gf_group->max_layer_depth_allowed = cpi->oxcf.gf_max_pyr_height; + rc->gfu_boost = av1_calc_arf_boost( + twopass, rc, frame_info, alt_offset, forward_frames, (i - 1), + cpi->lap_enabled ? &rc->num_stats_used_for_gfu_boost : NULL, + cpi->lap_enabled ? &rc->num_stats_required_for_gfu_boost : NULL); } else { reset_fpf_position(twopass, start_pos); - rc->gfu_boost = AOMMIN( - MAX_GF_BOOST, - av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, (i - 1), 0)); rc->source_alt_ref_pending = 0; gf_group->max_layer_depth_allowed = 0; + set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref, + is_final_pass); + + rc->gfu_boost = AOMMIN( + MAX_GF_BOOST, + av1_calc_arf_boost( + twopass, rc, frame_info, alt_offset, (i - 1), 0, + cpi->lap_enabled ? &rc->num_stats_used_for_gfu_boost : NULL, + cpi->lap_enabled ? &rc->num_stats_required_for_gfu_boost : NULL)); } - // 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; + // rc->gf_intervals assumes the usage of alt_ref, therefore adding one overlay + // frame to the next gf. If no alt_ref is used, should substract 1 frame from + // the next gf group. + // TODO(bohanli): should incorporate the usage of alt_ref into + // calculate_gf_length + if (is_final_pass && rc->source_alt_ref_pending == 0 && + rc->intervals_till_gf_calculate_due > 0) { + rc->gf_intervals[rc->cur_gf_index]--; } #define LAST_ALR_BOOST_FACTOR 0.2f @@ -1195,7 +1801,8 @@ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, 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); + gf_group_bits = calculate_total_gf_group_bits(cpi, gf_stats.gf_group_err); + rc->gf_group_bits = gf_group_bits; #if GROUP_ADAPTIVE_MAXQ // Calculate an estimate of the maxq needed for the group. @@ -1206,58 +1813,85 @@ static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, 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_err = + gf_stats.gf_group_raw_error / rc->baseline_gf_interval; const double group_av_skip_pct = - gf_group_skip_pct / rc->baseline_gf_interval; + gf_stats.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)); + ((gf_stats.gf_group_inactive_zone_rows * 2) / + (rc->baseline_gf_interval * (double)cm->mi_params.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); + int64_t bits = cpi->oxcf.target_bandwidth; + + if (bits > 0) { + int rate_error; + + rate_error = (int)((rc->vbr_bits_off_target * 100) / bits); + rate_error = clamp(rate_error, -100, 100); + if (rate_error > 0) { + rc_factor = AOMMAX(RC_FACTOR_MIN, (double)(100 - rate_error) / 100.0); + } else { + rc_factor = AOMMIN(RC_FACTOR_MAX, (double)(100 - rate_error) / 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); + vbr_group_bits_per_frame, rc_factor); rc->active_worst_quality = AOMMAX(tmp_q, rc->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); - gf_arf_bits = - adjust_boost_bits_for_target_level(cpi, gf_arf_bits, gf_group_bits, 1); - // Adjust KF group bits and error remaining. - twopass->kf_group_error_left -= (int64_t)gf_group_err; + if (is_final_pass) + twopass->kf_group_error_left -= (int64_t)gf_stats.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, rc, gf_group_bits, gf_arf_bits, - frame_max_bits(rc, oxcf), 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); + start_pos, twopass->stats_buf_ctx->stats_in_end, + rc->baseline_gf_interval); } // Reset rolling actual and target bits counters for ARF groups. twopass->rolling_arf_group_target_bits = 1; twopass->rolling_arf_group_actual_bits = 1; + + av1_gop_bit_allocation(cpi, rc, gf_group, + frame_params->frame_type == KEY_FRAME, use_alt_ref, + gf_group_bits); +} + +// #define FIXED_ARF_BITS +#ifdef FIXED_ARF_BITS +#define ARF_BITS_FRACTION 0.75 +#endif +void av1_gop_bit_allocation(const AV1_COMP *cpi, RATE_CONTROL *const rc, + GF_GROUP *gf_group, int is_key_frame, int use_arf, + int64_t gf_group_bits) { + // Calculate the extra bits to be used for boosted frame(s) +#ifdef FIXED_ARF_BITS + int gf_arf_bits = (int)(ARF_BITS_FRACTION * gf_group_bits); +#else + int gf_arf_bits = calculate_boost_bits(rc->baseline_gf_interval, + rc->gfu_boost, gf_group_bits); +#endif + + gf_arf_bits = adjust_boost_bits_for_target_level(cpi, rc, gf_arf_bits, + gf_group_bits, 1); + + // Allocate bits to each of the frames in the GF group. + allocate_gf_group_bits(gf_group, rc, gf_group_bits, gf_arf_bits, is_key_frame, + use_arf); } // Minimum % intra coding observed in first pass (1.0 = 100%) @@ -1340,7 +1974,7 @@ static int test_candidate_kf(TWO_PASS *twopass, double decay_accumulator = 1.0; // Examine how well the key frame predicts subsequent frames. - for (i = 0; i < 16; ++i) { + for (i = 0; i < SCENE_CUT_KEY_TEST_INTERVAL; ++i) { double next_iiratio = (BOOST_FACTOR * local_next_frame.intra_error / DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error)); @@ -1389,9 +2023,140 @@ static int test_candidate_kf(TWO_PASS *twopass, #define FRAMES_TO_CHECK_DECAY 8 #define KF_MIN_FRAME_BOOST 80.0 #define KF_MAX_FRAME_BOOST 128.0 -#define MIN_KF_BOOST 600 // Minimum boost for non-static KF interval +#define MIN_KF_BOOST 600 // Minimum boost for non-static KF interval +#define MAX_KF_BOOST 3200 #define MIN_STATIC_KF_BOOST 5400 // Minimum boost for static KF interval +static int detect_app_forced_key(AV1_COMP *cpi) { + if (cpi->oxcf.fwd_kf_enabled) cpi->rc.next_is_fwd_key = 1; + int num_frames_to_app_forced_key = is_forced_keyframe_pending( + cpi->lookahead, cpi->lookahead->max_sz, cpi->compressor_stage); + if (num_frames_to_app_forced_key != -1) cpi->rc.next_is_fwd_key = 0; + return num_frames_to_app_forced_key; +} + +static int get_projected_kf_boost(AV1_COMP *cpi) { + /* + * If num_stats_used_for_kf_boost >= frames_to_key, then + * all stats needed for prior boost calculation are available. + * Hence projecting the prior boost is not needed in this cases. + */ + if (cpi->rc.num_stats_used_for_kf_boost >= cpi->rc.frames_to_key) + return cpi->rc.kf_boost; + + // Get the current tpl factor (number of frames = frames_to_key). + double tpl_factor = av1_get_kf_boost_projection_factor(cpi->rc.frames_to_key); + // Get the tpl factor when number of frames = num_stats_used_for_kf_boost. + double tpl_factor_num_stats = + av1_get_kf_boost_projection_factor(cpi->rc.num_stats_used_for_kf_boost); + int projected_kf_boost = + (int)rint((tpl_factor * cpi->rc.kf_boost) / tpl_factor_num_stats); + return projected_kf_boost; +} + +static int define_kf_interval(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame, + double *kf_group_err, + int num_frames_to_detect_scenecut) { + TWO_PASS *const twopass = &cpi->twopass; + RATE_CONTROL *const rc = &cpi->rc; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; + FIRSTPASS_STATS last_frame; + double decay_accumulator = 1.0; + int i = 0, j; + int frames_to_key = 1; + int frames_since_key = rc->frames_since_key + 1; + FRAME_INFO *const frame_info = &cpi->frame_info; + int num_stats_used_for_kf_boost = 1; + int scenecut_detected = 0; + + int num_frames_to_next_key = detect_app_forced_key(cpi); + + if (num_frames_to_detect_scenecut == 0) { + if (num_frames_to_next_key != -1) + return num_frames_to_next_key; + else + return rc->frames_to_key; + } + + if (num_frames_to_next_key != -1) + num_frames_to_detect_scenecut = + AOMMIN(num_frames_to_detect_scenecut, num_frames_to_next_key); + + // 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; + + i = 0; + while (twopass->stats_in < twopass->stats_buf_ctx->stats_in_end && + frames_to_key < num_frames_to_detect_scenecut) { + // Accumulate total number of stats available till next key frame + num_stats_used_for_kf_boost++; + + // Accumulate kf group error. + if (kf_group_err != NULL) + *kf_group_err += + calculate_modified_err(frame_info, 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->rc.enable_scenecut_detection && cpi->oxcf.auto_key && + twopass->stats_in < twopass->stats_buf_ctx->stats_in_end) { + double loop_decay_rate; + + // Check for a scene cut. + if (test_candidate_kf(twopass, &last_frame, this_frame, twopass->stats_in, + frames_since_key, oxcf->rc_mode)) { + scenecut_detected = 1; + break; + } + + // How fast is the prediction quality decaying? + loop_decay_rate = + get_prediction_decay_rate(frame_info, 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(twopass, rc->min_gf_interval, i, + cpi->oxcf.key_freq - i, loop_decay_rate, + decay_accumulator)) { + scenecut_detected = 1; + break; + } + + // Step on to the next frame. + ++frames_to_key; + ++frames_since_key; + + // If we don't have a real key frame within the next two + // key_freq intervals then break out of the loop. + if (frames_to_key >= 2 * cpi->oxcf.key_freq) break; + } else { + ++frames_to_key; + ++frames_since_key; + } + ++i; + } + + if (kf_group_err != NULL) + rc->num_stats_used_for_kf_boost = num_stats_used_for_kf_boost; + + if (cpi->lap_enabled && !scenecut_detected) + frames_to_key = num_frames_to_next_key; + + return frames_to_key; +} + static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; @@ -1402,7 +2167,6 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { const AV1EncoderConfig *const oxcf = &cpi->oxcf; const FIRSTPASS_STATS first_frame = *this_frame; FIRSTPASS_STATS next_frame; - FIRSTPASS_STATS last_frame; av1_zero(next_frame); rc->frames_since_key = 0; @@ -1419,27 +2183,30 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { rc->frames_to_key = 1; - if (cpi->oxcf.pass == 0) { + if (has_no_stats_stage(cpi)) { + int num_frames_to_app_forced_key = detect_app_forced_key(cpi); rc->this_key_frame_forced = current_frame->frame_number != 0 && rc->frames_to_key == 0; - rc->frames_to_key = cpi->oxcf.key_freq; + if (num_frames_to_app_forced_key != -1) + rc->frames_to_key = num_frames_to_app_forced_key; + else + rc->frames_to_key = AOMMAX(1, cpi->oxcf.key_freq); + correct_frames_to_key(cpi); rc->kf_boost = DEFAULT_KF_BOOST; rc->source_alt_ref_active = 0; gf_group->update_type[0] = KF_UPDATE; return; } - int i, j; + int i; const FIRSTPASS_STATS *const start_position = twopass->stats_in; int kf_bits = 0; - double decay_accumulator = 1.0; double zero_motion_accumulator = 1.0; double boost_score = 0.0; double kf_raw_err = 0.0; double kf_mod_err = 0.0; double kf_group_err = 0.0; - double recent_loop_decay[FRAMES_TO_CHECK_DECAY]; double sr_accumulator = 0.0; - + int frames_to_key; // Is this a forced key frame by interval. rc->this_key_frame_forced = rc->next_key_frame_forced; @@ -1449,59 +2216,15 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { kf_raw_err = this_frame->intra_error; kf_mod_err = calculate_modified_err(frame_info, 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; + frames_to_key = + define_kf_interval(cpi, this_frame, &kf_group_err, oxcf->key_freq); - // 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(frame_info, twopass, oxcf, this_frame); + if (frames_to_key != -1) + rc->frames_to_key = AOMMIN(oxcf->key_freq, frames_to_key); + else + rc->frames_to_key = oxcf->key_freq; - // 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, oxcf->rc_mode)) - break; - - // How fast is the prediction quality decaying? - loop_decay_rate = - get_prediction_decay_rate(frame_info, 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 (cpi->lap_enabled) correct_frames_to_key(cpi); // 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. @@ -1521,10 +2244,11 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { for (i = 0; i < rc->frames_to_key; ++i) { kf_group_err += calculate_modified_err(frame_info, twopass, oxcf, &tmp_frame); - input_stats(twopass, &tmp_frame); + if (EOF == input_stats(twopass, &tmp_frame)) break; } rc->next_key_frame_forced = 1; - } else if (twopass->stats_in == twopass->stats_in_end || + } else if ((twopass->stats_in == twopass->stats_buf_ctx->stats_in_end && + is_stat_consumption_stage_twopass(cpi)) || rc->frames_to_key >= cpi->oxcf.key_freq) { rc->next_key_frame_forced = 1; } else { @@ -1532,7 +2256,7 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { } // Special case for the last key frame of the file. - if (twopass->stats_in >= twopass->stats_in_end) { + if (twopass->stats_in >= twopass->stats_buf_ctx->stats_in_end) { // Accumulate kf group error. kf_group_err += calculate_modified_err(frame_info, twopass, oxcf, this_frame); @@ -1586,7 +2310,7 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { // Not all frames in the group are necessarily used in calculating boost. if ((sr_accumulator < (kf_raw_err * 1.50)) && - (i <= (rc->max_gf_interval * 4))) { + (i <= rc->max_gf_interval * 2)) { double frame_boost; double zm_factor; @@ -1607,10 +2331,14 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { // 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); + start_position, twopass->stats_buf_ctx->stats_in_end, rc->frames_to_key); rc->kf_boost = (int)boost_score; + if (cpi->lap_enabled) { + rc->kf_boost = get_projected_kf_boost(cpi); + } + // 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) && @@ -1620,6 +2348,9 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { // 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); +#ifdef STRICT_RC + rc->kf_boost = AOMMIN(rc->kf_boost, MAX_KF_BOOST); +#endif } // Work out how many bits to allocate for the key frame itself. @@ -1627,19 +2358,9 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { 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); - kf_bits = adjust_boost_bits_for_target_level(cpi, kf_bits, + kf_bits = adjust_boost_bits_for_target_level(cpi, rc, kf_bits, twopass->kf_group_bits, 0); - // 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. @@ -1656,7 +2377,7 @@ static void find_next_key_frame(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame) { } static int is_skippable_frame(const AV1_COMP *cpi) { - if (cpi->oxcf.pass == 0) return 0; + if (has_no_stats_stage(cpi)) return 0; // 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 @@ -1664,8 +2385,8 @@ static int is_skippable_frame(const AV1_COMP *cpi) { 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 - 2 > twopass->stats_buf_ctx->stats_in_start && + twopass->stats_in < twopass->stats_buf_ctx->stats_in_end && (twopass->stats_in - 1)->pcnt_inter - (twopass->stats_in - 1)->pcnt_motion == 1 && @@ -1688,21 +2409,33 @@ static void process_first_pass_stats(AV1_COMP *cpi, RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; - if (cpi->oxcf.rc_mode != AOM_Q && current_frame->frame_number == 0) { - const int frames_left = - (int)(twopass->total_stats.count - current_frame->frame_number); + if (cpi->oxcf.rc_mode != AOM_Q && current_frame->frame_number == 0 && + cpi->twopass.stats_buf_ctx->total_stats && + cpi->twopass.stats_buf_ctx->total_left_stats) { + if (cpi->lap_enabled) { + /* + * Accumulate total_stats using available limited number of stats, + * and assign it to total_left_stats. + */ + *cpi->twopass.stats_buf_ctx->total_left_stats = + *cpi->twopass.stats_buf_ctx->total_stats; + } + const int frames_left = (int)(twopass->stats_buf_ctx->total_stats->count - + current_frame->frame_number); // 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_length = + twopass->stats_buf_ctx->total_left_stats->count; const double section_error = - twopass->total_left_stats.coded_error / section_length; + twopass->stats_buf_ctx->total_left_stats->coded_error / section_length; const double section_intra_skip = - twopass->total_left_stats.intra_skip_pct / section_length; + twopass->stats_buf_ctx->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); + (twopass->stats_buf_ctx->total_left_stats->inactive_zone_rows * 2) / + ((double)cm->mi_params.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); @@ -1716,12 +2449,18 @@ static void process_first_pass_stats(AV1_COMP *cpi, rc->avg_frame_qindex[KEY_FRAME] = rc->last_q[KEY_FRAME]; } - if (EOF == input_stats(twopass, this_frame)) return; + int err = 0; + if (cpi->lap_enabled) { + err = input_stats_lap(twopass, this_frame); + } else { + err = input_stats(twopass, this_frame); + } + if (err == EOF) return; { const int num_mbs = (cpi->oxcf.resize_mode != RESIZE_NONE) ? cpi->initial_mbs - : cpi->common.MBs; + : cm->mi_params.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); @@ -1730,7 +2469,8 @@ static void process_first_pass_stats(AV1_COMP *cpi, } // Update the total stats remaining structure. - subtract_stats(&twopass->total_left_stats, this_frame); + if (twopass->stats_buf_ctx->total_left_stats) + subtract_stats(twopass->stats_buf_ctx->total_left_stats, this_frame); // Set the frame content type flag. if (this_frame->intra_skip_pct >= FC_ANIMATION_THRESH) @@ -1745,7 +2485,7 @@ static void setup_target_rate(AV1_COMP *cpi) { int target_rate = gf_group->bit_allocation[gf_group->index]; - if (cpi->oxcf.pass == 0) { + if (has_no_stats_stage(cpi)) { av1_rc_set_frame_target(cpi, target_rate, cpi->common.width, cpi->common.height); } @@ -1755,12 +2495,20 @@ static void setup_target_rate(AV1_COMP *cpi) { void av1_get_second_pass_params(AV1_COMP *cpi, EncodeFrameParams *const frame_params, + const EncodeFrameInput *const frame_input, unsigned int frame_flags) { RATE_CONTROL *const rc = &cpi->rc; TWO_PASS *const twopass = &cpi->twopass; GF_GROUP *const gf_group = &cpi->gf_group; + AV1_COMMON *cm = &cpi->common; - if (cpi->oxcf.pass == 2 && !twopass->stats_in) return; + if (frame_is_intra_only(cm)) { + FeatureFlags *const features = &cm->features; + av1_set_screen_content_options(cpi, features); + cpi->is_screen_content_type = features->allow_screen_content_tools; + } + + if (is_stat_consumption_stage(cpi) && !twopass->stats_in) return; if (rc->frames_till_gf_update_due > 0 && !(frame_flags & FRAMEFLAGS_KEY)) { assert(gf_group->index < gf_group->size); @@ -1780,7 +2528,7 @@ void av1_get_second_pass_params(AV1_COMP *cpi, // 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) { + if (cpi->sf.part_sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { cpi->partition_search_skippable_frame = is_skippable_frame(cpi); } @@ -1794,7 +2542,7 @@ void av1_get_second_pass_params(AV1_COMP *cpi, FIRSTPASS_STATS this_frame; av1_zero(this_frame); // call above fn - if (cpi->oxcf.pass == 2) { + if (is_stat_consumption_stage(cpi)) { process_first_pass_stats(cpi, &this_frame); } else { rc->active_worst_quality = cpi->oxcf.cq_level; @@ -1810,13 +2558,84 @@ void av1_get_second_pass_params(AV1_COMP *cpi, this_frame = this_frame_copy; } else { frame_params->frame_type = INTER_FRAME; + const int altref_enabled = is_altref_enabled(cpi); + const int sframe_dist = cpi->oxcf.sframe_dist; + const int sframe_mode = cpi->oxcf.sframe_mode; + const int sframe_enabled = cpi->oxcf.sframe_enabled; + const int update_type = gf_group->update_type[gf_group->index]; + CurrentFrame *const current_frame = &cpi->common.current_frame; + if (sframe_enabled) { + if (altref_enabled) { + if (sframe_mode == 1) { + // sframe_mode == 1: insert sframe if it matches altref frame. + if (current_frame->frame_number % sframe_dist == 0 && + current_frame->frame_number != 0 && update_type == ARF_UPDATE) { + frame_params->frame_type = S_FRAME; + } + } else { + // sframe_mode != 1: if sframe will be inserted at the next available + // altref frame + if (current_frame->frame_number % sframe_dist == 0 && + current_frame->frame_number != 0) { + rc->sframe_due = 1; + } + if (rc->sframe_due && update_type == ARF_UPDATE) { + frame_params->frame_type = S_FRAME; + rc->sframe_due = 0; + } + } + } else { + if (current_frame->frame_number % sframe_dist == 0 && + current_frame->frame_number != 0) { + frame_params->frame_type = S_FRAME; + } + } + } } // Define a new GF/ARF group. (Should always enter here for key frames). if (rc->frames_till_gf_update_due == 0) { assert(cpi->common.current_frame.frame_number == 0 || gf_group->index == gf_group->size); - define_gf_group(cpi, &this_frame, frame_params); + const FIRSTPASS_STATS *const start_position = twopass->stats_in; + int num_frames_to_detect_scenecut, frames_to_key; + if (cpi->lap_enabled && cpi->rc.enable_scenecut_detection) + num_frames_to_detect_scenecut = MAX_GF_LENGTH_LAP + 1; + else + num_frames_to_detect_scenecut = 0; + frames_to_key = define_kf_interval(cpi, &this_frame, NULL, + num_frames_to_detect_scenecut); + reset_fpf_position(twopass, start_position); + if (frames_to_key != -1) + rc->frames_to_key = AOMMIN(rc->frames_to_key, frames_to_key); + + int max_gop_length = (cpi->oxcf.lag_in_frames >= 32 && + is_stat_consumption_stage_twopass(cpi)) + ? MAX_GF_INTERVAL + : MAX_GF_LENGTH_LAP; + if (rc->intervals_till_gf_calculate_due == 0) { + calculate_gf_length(cpi, max_gop_length, MAX_NUM_GF_INTERVALS); + } + + if (max_gop_length > 16) { + if (rc->gf_intervals[rc->cur_gf_index] - 1 > 16) { + // The calculate_gf_length function is previously used with + // max_gop_length = 32 with look-ahead gf intervals. + define_gf_group(cpi, &this_frame, frame_params, max_gop_length, 0); + if (!av1_tpl_setup_stats(cpi, 1, frame_params, frame_input)) { + // Tpl decides that a shorter gf interval is better. + // TODO(jingning): Remove redundant computations here. + max_gop_length = 16; + calculate_gf_length(cpi, max_gop_length, 1); + } + } else { + // Even based on 32 we still decide to use a short gf interval. + // Better to re-decide based on 16 then + max_gop_length = 16; + calculate_gf_length(cpi, max_gop_length, 1); + } + } + define_gf_group(cpi, &this_frame, frame_params, max_gop_length, 1); rc->frames_till_gf_update_due = rc->baseline_gf_interval; cpi->num_gf_group_show_frames = 0; assert(gf_group->index == 0); @@ -1839,7 +2658,7 @@ void av1_get_second_pass_params(AV1_COMP *cpi, // 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) { + if (cpi->sf.part_sf.allow_partition_search_skip && cpi->oxcf.pass == 2) { cpi->partition_search_skippable_frame = is_skippable_frame(cpi); } @@ -1853,15 +2672,12 @@ void av1_init_second_pass(AV1_COMP *cpi) { double frame_rate; FIRSTPASS_STATS *stats; - av1_twopass_zero_stats(&twopass->total_stats); - av1_twopass_zero_stats(&twopass->total_left_stats); + if (!twopass->stats_buf_ctx->stats_in_end) return; - if (!twopass->stats_in_end) return; + stats = twopass->stats_buf_ctx->total_stats; - stats = &twopass->total_stats; - - *stats = *twopass->stats_in_end; - twopass->total_left_stats = *stats; + *stats = *twopass->stats_buf_ctx->stats_in_end; + *twopass->stats_buf_ctx->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 @@ -1887,7 +2703,7 @@ void av1_init_second_pass(AV1_COMP *cpi) { (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) { + while (s < twopass->stats_buf_ctx->stats_in_end) { modified_error_total += calculate_modified_err(frame_info, twopass, oxcf, s); ++s; @@ -1913,6 +2729,37 @@ void av1_init_second_pass(AV1_COMP *cpi) { twopass->rolling_arf_group_actual_bits = 1; } +void av1_init_single_pass_lap(AV1_COMP *cpi) { + TWO_PASS *const twopass = &cpi->twopass; + + if (!twopass->stats_buf_ctx->stats_in_end) return; + + // This variable monitors how far behind the second ref update is lagging. + twopass->sr_update_lag = 1; + + twopass->bits_left = 0; + twopass->modified_error_min = 0.0; + twopass->modified_error_max = 0.0; + twopass->modified_error_left = 0.0; + + // 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; + + // Initialize bits per macro_block estimate correction factor. + twopass->bpm_factor = 1.0; + // Initialize actual and target bits counters for ARF groups so that + // at the start we have a neutral bpm adjustment. + twopass->rolling_arf_group_target_bits = 1; + twopass->rolling_arf_group_actual_bits = 1; +} + #define MINQ_ADJ_LIMIT 48 #define MINQ_ADJ_LIMIT_CQ 20 #define HIGH_UNDERSHOOT_RATIO 2 @@ -1942,23 +2789,40 @@ void av1_twopass_postencode_update(AV1_COMP *cpi) { rc->rate_error_estimate = 0; } + // Update the active best quality pyramid. + if (!rc->is_src_frame_alt_ref) { + const int pyramid_level = cpi->gf_group.layer_depth[cpi->gf_group.index]; + int i; + for (i = pyramid_level; i <= MAX_ARF_LAYERS; ++i) { + rc->active_best_quality[i] = cpi->common.quant_params.base_qindex; + // if (pyramid_level >= 2) { + // rc->active_best_quality[pyramid_level] = + // AOMMAX(rc->active_best_quality[pyramid_level], + // cpi->common.base_qindex); + // } + } + } + #if 0 { AV1_COMMON *cm = &cpi->common; FILE *fpfile; fpfile = fopen("details.stt", "a"); - fprintf(fpfile, "%10d %10d %10d %10"PRId64" %10"PRId64" %10d %10d %10d %10.4lf %10.4lf %10.4lf %10.4lf\n", - cm->current_frame.frame_number, - rc->base_frame_target, rc->projected_frame_size, - rc->total_actual_bits, rc->vbr_bits_off_target, - rc->rate_error_estimate, + fprintf(fpfile, + "%10d %10d %10d %10" PRId64 " %10" PRId64 + " %10d %10d %10d %10.4lf %10.4lf %10.4lf %10.4lf\n", + cm->current_frame.frame_number, rc->base_frame_target, + rc->projected_frame_size, rc->total_actual_bits, + rc->vbr_bits_off_target, rc->rate_error_estimate, twopass->rolling_arf_group_target_bits, twopass->rolling_arf_group_actual_bits, (double)twopass->rolling_arf_group_actual_bits / (double)twopass->rolling_arf_group_target_bits, twopass->bpm_factor, - av1_convert_qindex_to_q(cm->base_qindex, cm->seq_params.bit_depth), - av1_convert_qindex_to_q(rc->active_worst_quality, cm->seq_params.bit_depth)); + av1_convert_qindex_to_q(quant_params->base_qindex, + cm->seq_params.bit_depth), + av1_convert_qindex_to_q(rc->active_worst_quality, + cm->seq_params.bit_depth)); fclose(fpfile); } #endif diff --git a/media/libaom/src/av1/encoder/pass2_strategy.h b/media/libaom/src/av1/encoder/pass2_strategy.h index bf37746a1f..437fb8f79d 100644 --- a/media/libaom/src/av1/encoder/pass2_strategy.h +++ b/media/libaom/src/av1/encoder/pass2_strategy.h @@ -18,15 +18,57 @@ extern "C" { struct AV1_COMP; struct EncodeFrameParams; +// structure of accumulated stats and features in a gf group +typedef struct { + double gf_group_err; + double gf_group_raw_error; + double gf_group_skip_pct; + double gf_group_inactive_zone_rows; + + double mv_ratio_accumulator; + double decay_accumulator; + double zero_motion_accumulator; + double loop_decay_rate; + double last_loop_decay_rate; + double this_frame_mv_in_out; + double mv_in_out_accumulator; + double abs_mv_in_out_accumulator; + + double avg_sr_coded_error; + double avg_tr_coded_error; + double avg_pcnt_second_ref; + double avg_pcnt_third_ref; + double avg_pcnt_third_ref_nolast; + double avg_new_mv_count; + double avg_wavelet_energy; + double avg_raw_err_stdev; + int non_zero_stdev_count; + + unsigned int allow_alt_ref; +} GF_GROUP_STATS; + +typedef struct { + double frame_err; + double frame_coded_error; + double frame_sr_coded_error; + double frame_tr_coded_error; +} GF_FRAME_STATS; void av1_init_second_pass(struct AV1_COMP *cpi); +void av1_init_single_pass_lap(AV1_COMP *cpi); + void av1_get_second_pass_params(struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params, + const EncodeFrameInput *const frame_input, unsigned int frame_flags); void av1_twopass_postencode_update(struct AV1_COMP *cpi); +void av1_gop_bit_allocation(const AV1_COMP *cpi, RATE_CONTROL *const rc, + GF_GROUP *gf_group, int is_key_frame, int use_arf, + int64_t gf_group_bits); + #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/pickcdef.c b/media/libaom/src/av1/encoder/pickcdef.c index d3ae348083..a1092fd595 100644 --- a/media/libaom/src/av1/encoder/pickcdef.c +++ b/media/libaom/src/av1/encoder/pickcdef.c @@ -16,24 +16,45 @@ #include "aom/aom_integer.h" #include "aom_ports/system_state.h" +#include "av1/common/av1_common_int.h" #include "av1/common/cdef.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconinter.h" #include "av1/encoder/encoder.h" -#define REDUCED_PRI_STRENGTHS 8 -#define REDUCED_TOTAL_STRENGTHS (REDUCED_PRI_STRENGTHS * CDEF_SEC_STRENGTHS) +#define REDUCED_PRI_STRENGTHS_LVL1 8 +#define REDUCED_PRI_STRENGTHS_LVL2 5 + +#define REDUCED_TOTAL_STRENGTHS_LVL1 \ + (REDUCED_PRI_STRENGTHS_LVL1 * CDEF_SEC_STRENGTHS) +#define REDUCED_TOTAL_STRENGTHS_LVL2 \ + (REDUCED_PRI_STRENGTHS_LVL2 * CDEF_SEC_STRENGTHS) #define TOTAL_STRENGTHS (CDEF_PRI_STRENGTHS * CDEF_SEC_STRENGTHS) -static const int priconv[REDUCED_PRI_STRENGTHS] = { 0, 1, 2, 3, 5, 7, 10, 13 }; +static const int priconv_lvl1[REDUCED_TOTAL_STRENGTHS_LVL1] = { 0, 1, 2, 3, + 5, 7, 10, 13 }; +static const int priconv_lvl2[REDUCED_TOTAL_STRENGTHS_LVL2] = { 0, 2, 4, 8, + 14 }; +static const int nb_cdef_strengths[CDEF_PICK_METHODS] = { + TOTAL_STRENGTHS, REDUCED_TOTAL_STRENGTHS_LVL1, REDUCED_TOTAL_STRENGTHS_LVL2, + TOTAL_STRENGTHS +}; + +// Get primary strength value for the given index and search method +static INLINE int get_pri_strength(CDEF_PICK_METHOD pick_method, int pri_idx) { + switch (pick_method) { + case CDEF_FAST_SEARCH_LVL1: return priconv_lvl1[pri_idx]; + case CDEF_FAST_SEARCH_LVL2: return priconv_lvl2[pri_idx]; + default: assert(0 && "Invalid CDEF primary index"); return -1; + } +} /* Search for the best strength to add as an option, knowing we already selected nb_strengths options. */ static uint64_t search_one(int *lev, int nb_strengths, uint64_t mse[][TOTAL_STRENGTHS], int sb_count, - int fast) { + CDEF_PICK_METHOD pick_method) { uint64_t tot_mse[TOTAL_STRENGTHS]; - const int total_strengths = fast ? REDUCED_TOTAL_STRENGTHS : TOTAL_STRENGTHS; + const int total_strengths = nb_cdef_strengths[pick_method]; int i, j; uint64_t best_tot_mse = (uint64_t)1 << 63; int best_id = 0; @@ -68,13 +89,13 @@ static uint64_t search_one(int *lev, int nb_strengths, already selected nb_strengths options. */ static uint64_t search_one_dual(int *lev0, int *lev1, int nb_strengths, uint64_t (**mse)[TOTAL_STRENGTHS], int sb_count, - int fast) { + CDEF_PICK_METHOD pick_method) { uint64_t tot_mse[TOTAL_STRENGTHS][TOTAL_STRENGTHS]; int i, j; uint64_t best_tot_mse = (uint64_t)1 << 63; int best_id0 = 0; int best_id1 = 0; - const int total_strengths = fast ? REDUCED_TOTAL_STRENGTHS : TOTAL_STRENGTHS; + const int total_strengths = nb_cdef_strengths[pick_method]; memset(tot_mse, 0, sizeof(tot_mse)); for (i = 0; i < sb_count; i++) { int gi; @@ -117,13 +138,16 @@ static uint64_t search_one_dual(int *lev0, int *lev1, int nb_strengths, /* Search for the set of strengths that minimizes mse. */ static uint64_t joint_strength_search(int *best_lev, int nb_strengths, uint64_t mse[][TOTAL_STRENGTHS], - int sb_count, int fast) { + int sb_count, + CDEF_PICK_METHOD pick_method) { uint64_t best_tot_mse; + int fast = (pick_method == CDEF_FAST_SEARCH_LVL1 || + pick_method == CDEF_FAST_SEARCH_LVL2); int i; best_tot_mse = (uint64_t)1 << 63; /* Greedy search: add one strength options at a time. */ for (i = 0; i < nb_strengths; i++) { - best_tot_mse = search_one(best_lev, i, mse, sb_count, fast); + best_tot_mse = search_one(best_lev, i, mse, sb_count, pick_method); } /* Trying to refine the greedy search by reconsidering each already-selected option. */ @@ -132,7 +156,7 @@ static uint64_t joint_strength_search(int *best_lev, int nb_strengths, int j; for (j = 0; j < nb_strengths - 1; j++) best_lev[j] = best_lev[j + 1]; best_tot_mse = - search_one(best_lev, nb_strengths - 1, mse, sb_count, fast); + search_one(best_lev, nb_strengths - 1, mse, sb_count, pick_method); } } return best_tot_mse; @@ -142,14 +166,15 @@ static uint64_t joint_strength_search(int *best_lev, int nb_strengths, static uint64_t joint_strength_search_dual(int *best_lev0, int *best_lev1, int nb_strengths, uint64_t (**mse)[TOTAL_STRENGTHS], - int sb_count, int fast) { + int sb_count, + CDEF_PICK_METHOD pick_method) { uint64_t best_tot_mse; int i; best_tot_mse = (uint64_t)1 << 63; /* Greedy search: add one strength options at a time. */ for (i = 0; i < nb_strengths; i++) { best_tot_mse = - search_one_dual(best_lev0, best_lev1, i, mse, sb_count, fast); + search_one_dual(best_lev0, best_lev1, i, mse, sb_count, pick_method); } /* Trying to refine the greedy search by reconsidering each already-selected option. */ @@ -160,56 +185,47 @@ static uint64_t joint_strength_search_dual(int *best_lev0, int *best_lev1, best_lev1[j] = best_lev1[j + 1]; } best_tot_mse = search_one_dual(best_lev0, best_lev1, nb_strengths - 1, mse, - sb_count, fast); + sb_count, pick_method); } return best_tot_mse; } -static void copy_sb16_16(uint16_t *dst, int dstride, const uint16_t *src, - int src_voffset, int src_hoffset, int sstride, - int vsize, int hsize) { +typedef void (*copy_fn_t)(uint16_t *dst, int dstride, const void *src, + int src_voffset, int src_hoffset, int sstride, + int vsize, int hsize); +typedef uint64_t (*compute_cdef_dist_t)(void *dst, int dstride, uint16_t *src, + cdef_list *dlist, int cdef_count, + BLOCK_SIZE bsize, int coeff_shift, + int row, int col); + +static void copy_sb16_16_highbd(uint16_t *dst, int dstride, const void *src, + int src_voffset, int src_hoffset, int sstride, + int vsize, int hsize) { int r; - const uint16_t *base = &src[src_voffset * sstride + src_hoffset]; + const uint16_t *src16 = CONVERT_TO_SHORTPTR((uint8_t *)src); + const uint16_t *base = &src16[src_voffset * sstride + src_hoffset]; for (r = 0; r < vsize; r++) memcpy(dst + r * dstride, base + r * sstride, hsize * sizeof(*base)); } -#if CONFIG_DIST_8X8 -static INLINE uint64_t dist_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src, - int sstride, int coeff_shift) { - uint64_t svar = 0; - uint64_t dvar = 0; - uint64_t sum_s = 0; - uint64_t sum_d = 0; - uint64_t sum_s2 = 0; - uint64_t sum_d2 = 0; - uint64_t sum_sd = 0; - int i, j; - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - sum_s += src[i * sstride + j]; - sum_d += dst[i * dstride + j]; - sum_s2 += src[i * sstride + j] * src[i * sstride + j]; - sum_d2 += dst[i * dstride + j] * dst[i * dstride + j]; - sum_sd += src[i * sstride + j] * dst[i * dstride + j]; - } - } - /* Compute the variance -- the calculation cannot go negative. */ - svar = sum_s2 - ((sum_s * sum_s + 32) >> 6); - dvar = sum_d2 - ((sum_d * sum_d + 32) >> 6); - return (uint64_t)floor( - .5 + (sum_d2 + sum_s2 - 2 * sum_sd) * .5 * - (svar + dvar + (400 << 2 * coeff_shift)) / - (sqrt((20000 << 4 * coeff_shift) + svar * (double)dvar))); +static void copy_sb16_16(uint16_t *dst, int dstride, const void *src, + int src_voffset, int src_hoffset, int sstride, + int vsize, int hsize) { + int r, c; + const uint8_t *src8 = (uint8_t *)src; + const uint8_t *base = &src8[src_voffset * sstride + src_hoffset]; + for (r = 0; r < vsize; r++) + for (c = 0; c < hsize; c++) + dst[r * dstride + c] = (uint16_t)base[r * sstride + c]; } -#endif // CONFIG_DIST_8X8 -static INLINE uint64_t mse_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src, - int sstride) { +static INLINE uint64_t mse_wxh_16bit_highbd(uint16_t *dst, int dstride, + uint16_t *src, int sstride, int w, + int h) { uint64_t sum = 0; int i, j; - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { int e = dst[i * dstride + j] - src[i * sstride + j]; sum += e * e; } @@ -217,79 +233,82 @@ static INLINE uint64_t mse_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src, return sum; } -static INLINE uint64_t mse_4x4_16bit(uint16_t *dst, int dstride, uint16_t *src, - int sstride) { +static INLINE uint64_t mse_wxh_16bit(uint8_t *dst, int dstride, uint16_t *src, + int sstride, int w, int h) { uint64_t sum = 0; int i, j; - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - int e = dst[i * dstride + j] - src[i * sstride + j]; + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + int e = (uint16_t)dst[i * dstride + j] - src[i * sstride + j]; sum += e * e; } } return sum; } +static INLINE void init_src_params(int *src_stride, int *width, int *height, + int *width_log2, int *height_log2, + BLOCK_SIZE bsize) { + *src_stride = block_size_wide[bsize]; + *width = block_size_wide[bsize]; + *height = block_size_high[bsize]; + *width_log2 = MI_SIZE_LOG2 + mi_size_wide_log2[bsize]; + *height_log2 = MI_SIZE_LOG2 + mi_size_wide_log2[bsize]; +} + /* Compute MSE only on the blocks we filtered. */ -static uint64_t compute_cdef_dist(uint16_t *dst, int dstride, uint16_t *src, - cdef_list *dlist, int cdef_count, - BLOCK_SIZE bsize, int coeff_shift, int pli) { +static uint64_t compute_cdef_dist_highbd(void *dst, int dstride, uint16_t *src, + cdef_list *dlist, int cdef_count, + BLOCK_SIZE bsize, int coeff_shift, + int row, int col) { + assert(bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 || + bsize == BLOCK_8X8); uint64_t sum = 0; int bi, bx, by; - if (bsize == BLOCK_8X8) { - for (bi = 0; bi < cdef_count; bi++) { - by = dlist[bi].by; - bx = dlist[bi].bx; - if (pli == 0) { -#if CONFIG_DIST_8X8 - sum += dist_8x8_16bit(&dst[(by << 3) * dstride + (bx << 3)], dstride, - &src[bi << (3 + 3)], 8, coeff_shift); -#else - - sum += mse_8x8_16bit(&dst[(by << 3) * dstride + (bx << 3)], dstride, - &src[bi << (3 + 3)], 8); -#endif // CONFIG_DIST_8X8 - - } else { - sum += mse_8x8_16bit(&dst[(by << 3) * dstride + (bx << 3)], dstride, - &src[bi << (3 + 3)], 8); - } - } - } else if (bsize == BLOCK_4X8) { - for (bi = 0; bi < cdef_count; bi++) { - by = dlist[bi].by; - bx = dlist[bi].bx; - sum += mse_4x4_16bit(&dst[(by << 3) * dstride + (bx << 2)], dstride, - &src[bi << (3 + 2)], 4); - sum += mse_4x4_16bit(&dst[((by << 3) + 4) * dstride + (bx << 2)], dstride, - &src[(bi << (3 + 2)) + 4 * 4], 4); - } - } else if (bsize == BLOCK_8X4) { - for (bi = 0; bi < cdef_count; bi++) { - by = dlist[bi].by; - bx = dlist[bi].bx; - sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 3)], dstride, - &src[bi << (2 + 3)], 8); - sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 3) + 4], dstride, - &src[(bi << (2 + 3)) + 4], 8); - } - } else { - assert(bsize == BLOCK_4X4); - for (bi = 0; bi < cdef_count; bi++) { - by = dlist[bi].by; - bx = dlist[bi].bx; - sum += mse_4x4_16bit(&dst[(by << 2) * dstride + (bx << 2)], dstride, - &src[bi << (2 + 2)], 4); - } + uint16_t *dst16 = CONVERT_TO_SHORTPTR((uint8_t *)dst); + uint16_t *dst_buff = &dst16[row * dstride + col]; + int src_stride, width, height, width_log2, height_log2; + init_src_params(&src_stride, &width, &height, &width_log2, &height_log2, + bsize); + for (bi = 0; bi < cdef_count; bi++) { + by = dlist[bi].by; + bx = dlist[bi].bx; + sum += mse_wxh_16bit_highbd( + &dst_buff[(by << height_log2) * dstride + (bx << width_log2)], dstride, + &src[bi << (height_log2 + width_log2)], src_stride, width, height); } return sum >> 2 * coeff_shift; } -static int sb_all_skip(const AV1_COMMON *const cm, int mi_row, int mi_col) { - const int maxr = AOMMIN(cm->mi_rows - mi_row, MI_SIZE_64X64); - const int maxc = AOMMIN(cm->mi_cols - mi_col, MI_SIZE_64X64); - const int stride = cm->mi_stride; - MB_MODE_INFO **mbmi = cm->mi_grid_base + mi_row * stride + mi_col; +static uint64_t compute_cdef_dist(void *dst, int dstride, uint16_t *src, + cdef_list *dlist, int cdef_count, + BLOCK_SIZE bsize, int coeff_shift, int row, + int col) { + assert(bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 || + bsize == BLOCK_8X8); + uint64_t sum = 0; + int bi, bx, by; + uint8_t *dst8 = (uint8_t *)dst; + uint8_t *dst_buff = &dst8[row * dstride + col]; + int src_stride, width, height, width_log2, height_log2; + init_src_params(&src_stride, &width, &height, &width_log2, &height_log2, + bsize); + for (bi = 0; bi < cdef_count; bi++) { + by = dlist[bi].by; + bx = dlist[bi].bx; + sum += mse_wxh_16bit( + &dst_buff[(by << height_log2) * dstride + (bx << width_log2)], dstride, + &src[bi << (height_log2 + width_log2)], src_stride, width, height); + } + return sum >> 2 * coeff_shift; +} + +static int sb_all_skip(const CommonModeInfoParams *const mi_params, int mi_row, + int mi_col) { + const int maxr = AOMMIN(mi_params->mi_rows - mi_row, MI_SIZE_64X64); + const int maxc = AOMMIN(mi_params->mi_cols - mi_col, MI_SIZE_64X64); + const int stride = mi_params->mi_stride; + MB_MODE_INFO **mbmi = mi_params->mi_grid_base + mi_row * stride + mi_col; for (int r = 0; r < maxr; ++r, mbmi += stride) { for (int c = 0; c < maxc; ++c) { if (!mbmi[c]->skip) return 0; @@ -300,11 +319,12 @@ static int sb_all_skip(const AV1_COMMON *const cm, int mi_row, int mi_col) { static void pick_cdef_from_qp(AV1_COMMON *const cm) { const int bd = cm->seq_params.bit_depth; - const int q = av1_ac_quant_QTX(cm->base_qindex, 0, bd) >> (bd - 8); + const int q = + av1_ac_quant_QTX(cm->quant_params.base_qindex, 0, bd) >> (bd - 8); CdefInfo *const cdef_info = &cm->cdef_info; cdef_info->cdef_bits = 0; cdef_info->nb_cdef_strengths = 1; - cdef_info->cdef_damping = 3 + (cm->base_qindex >> 6); + cdef_info->cdef_damping = 3 + (cm->quant_params.base_qindex >> 6); int predicted_y_f1 = 0; int predicted_y_f2 = 0; @@ -312,13 +332,13 @@ static void pick_cdef_from_qp(AV1_COMMON *const cm) { int predicted_uv_f2 = 0; aom_clear_system_state(); if (!frame_is_intra_only(cm)) { - predicted_y_f1 = clamp((int)roundf(-q * q * 0.0000023593946f + + predicted_y_f1 = clamp((int)roundf(q * q * -0.0000023593946f + q * 0.0068615186f + 0.02709886f), 0, 15); - predicted_y_f2 = clamp((int)roundf(-q * q * 0.00000057629734f + + predicted_y_f2 = clamp((int)roundf(q * q * -0.00000057629734f + q * 0.0013993345f + 0.03831067f), 0, 3); - predicted_uv_f1 = clamp((int)roundf(-q * q * 0.0000007095069f + + predicted_uv_f1 = clamp((int)roundf(q * q * -0.0000007095069f + q * 0.0034628846f + 0.00887099f), 0, 15); predicted_uv_f2 = clamp((int)roundf(q * q * 0.00000023874085f + @@ -328,11 +348,11 @@ static void pick_cdef_from_qp(AV1_COMMON *const cm) { predicted_y_f1 = clamp( (int)roundf(q * q * 0.0000033731974f + q * 0.008070594f + 0.0187634f), 0, 15); - predicted_y_f2 = clamp((int)roundf(-q * q * -0.0000029167343f + - q * 0.0027798624f + 0.0079405f), - 0, 3); + predicted_y_f2 = clamp( + (int)roundf(q * q * 0.0000029167343f + q * 0.0027798624f + 0.0079405f), + 0, 3); predicted_uv_f1 = clamp( - (int)roundf(-q * q * 0.0000130790995f + q * 0.012892405f - 0.00748388f), + (int)roundf(q * q * -0.0000130790995f + q * 0.012892405f - 0.00748388f), 0, 15); predicted_uv_f2 = clamp((int)roundf(q * q * 0.0000032651783f + q * 0.00035520183f + 0.00228092f), @@ -343,14 +363,15 @@ static void pick_cdef_from_qp(AV1_COMMON *const cm) { cdef_info->cdef_uv_strengths[0] = predicted_uv_f1 * CDEF_SEC_STRENGTHS + predicted_uv_f2; - const int nvfb = (cm->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; - const int nhfb = (cm->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; - MB_MODE_INFO **mbmi = cm->mi_grid_base; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const int nvfb = (mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + const int nhfb = (mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + MB_MODE_INFO **mbmi = mi_params->mi_grid_base; for (int r = 0; r < nvfb; ++r) { for (int c = 0; c < nhfb; ++c) { mbmi[MI_SIZE_64X64 * c]->cdef_strength = 0; } - mbmi += MI_SIZE_64X64 * cm->mi_stride; + mbmi += MI_SIZE_64X64 * mi_params->mi_stride; } } @@ -362,17 +383,17 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, return; } - uint16_t *src[3]; - uint16_t *ref_coeff[3]; - static cdef_list dlist[MI_SIZE_128X128 * MI_SIZE_128X128]; + cdef_list dlist[MI_SIZE_128X128 * MI_SIZE_128X128]; int dir[CDEF_NBLOCKS][CDEF_NBLOCKS] = { { 0 } }; int var[CDEF_NBLOCKS][CDEF_NBLOCKS] = { { 0 } }; - const int nvfb = (cm->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; - const int nhfb = (cm->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const int nvfb = (mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; + const int nhfb = (mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; int *sb_index = aom_malloc(nvfb * nhfb * sizeof(*sb_index)); - const int damping = 3 + (cm->base_qindex >> 6); - const int fast = pick_method == CDEF_FAST_SEARCH; - const int total_strengths = fast ? REDUCED_TOTAL_STRENGTHS : TOTAL_STRENGTHS; + const int damping = 3 + (cm->quant_params.base_qindex >> 6); + const int fast = (pick_method == CDEF_FAST_SEARCH_LVL1 || + pick_method == CDEF_FAST_SEARCH_LVL2); + const int total_strengths = nb_cdef_strengths[pick_method]; DECLARE_ALIGNED(32, uint16_t, tmp_dst[1 << (MAX_SB_SIZE_LOG2 * 2)]); const int num_planes = av1_num_planes(cm); av1_setup_dst_planes(xd->plane, cm->seq_params.sb_size, frame, 0, 0, 0, @@ -381,61 +402,32 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, mse[0] = aom_malloc(sizeof(**mse) * nvfb * nhfb); mse[1] = aom_malloc(sizeof(**mse) * nvfb * nhfb); - int stride[3]; int bsize[3]; int mi_wide_l2[3]; int mi_high_l2[3]; int xdec[3]; int ydec[3]; + uint8_t *ref_buffer[3] = { ref->y_buffer, ref->u_buffer, ref->v_buffer }; + int ref_stride[3] = { ref->y_stride, ref->uv_stride, ref->uv_stride }; + for (int pli = 0; pli < num_planes; pli++) { - uint8_t *ref_buffer; - int ref_stride; - switch (pli) { - case 0: - ref_buffer = ref->y_buffer; - ref_stride = ref->y_stride; - break; - case 1: - ref_buffer = ref->u_buffer; - ref_stride = ref->uv_stride; - break; - case 2: - ref_buffer = ref->v_buffer; - ref_stride = ref->uv_stride; - break; - } - src[pli] = aom_memalign( - 32, sizeof(*src) * cm->mi_rows * cm->mi_cols * MI_SIZE * MI_SIZE); - ref_coeff[pli] = aom_memalign( - 32, sizeof(*ref_coeff) * cm->mi_rows * cm->mi_cols * MI_SIZE * MI_SIZE); xdec[pli] = xd->plane[pli].subsampling_x; ydec[pli] = xd->plane[pli].subsampling_y; bsize[pli] = ydec[pli] ? (xdec[pli] ? BLOCK_4X4 : BLOCK_8X4) : (xdec[pli] ? BLOCK_4X8 : BLOCK_8X8); - stride[pli] = cm->mi_cols << MI_SIZE_LOG2; mi_wide_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_x; mi_high_l2[pli] = MI_SIZE_LOG2 - xd->plane[pli].subsampling_y; + } - const int frame_height = - (cm->mi_rows * MI_SIZE) >> xd->plane[pli].subsampling_y; - const int frame_width = - (cm->mi_cols * MI_SIZE) >> xd->plane[pli].subsampling_x; - const int plane_sride = stride[pli]; - const int dst_stride = xd->plane[pli].dst.stride; - for (int r = 0; r < frame_height; ++r) { - for (int c = 0; c < frame_width; ++c) { - if (cm->seq_params.use_highbitdepth) { - src[pli][r * plane_sride + c] = - CONVERT_TO_SHORTPTR(xd->plane[pli].dst.buf)[r * dst_stride + c]; - ref_coeff[pli][r * plane_sride + c] = - CONVERT_TO_SHORTPTR(ref_buffer)[r * ref_stride + c]; - } else { - src[pli][r * plane_sride + c] = - xd->plane[pli].dst.buf[r * dst_stride + c]; - ref_coeff[pli][r * plane_sride + c] = ref_buffer[r * ref_stride + c]; - } - } - } + copy_fn_t copy_fn; + compute_cdef_dist_t compute_cdef_dist_fn; + + if (cm->seq_params.use_highbitdepth) { + copy_fn = copy_sb16_16_highbd; + compute_cdef_dist_fn = compute_cdef_dist_highbd; + } else { + copy_fn = copy_sb16_16; + compute_cdef_dist_fn = compute_cdef_dist; } DECLARE_ALIGNED(32, uint16_t, inbuf[CDEF_INBUF_SIZE]); @@ -445,19 +437,20 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, for (int fbr = 0; fbr < nvfb; ++fbr) { for (int fbc = 0; fbc < nhfb; ++fbc) { // No filtering if the entire filter block is skipped - if (sb_all_skip(cm, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64)) continue; + if (sb_all_skip(mi_params, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64)) + continue; const MB_MODE_INFO *const mbmi = - cm->mi_grid_base[MI_SIZE_64X64 * fbr * cm->mi_stride + - MI_SIZE_64X64 * fbc]; + mi_params->mi_grid_base[MI_SIZE_64X64 * fbr * mi_params->mi_stride + + MI_SIZE_64X64 * fbc]; if (((fbc & 1) && (mbmi->sb_type == BLOCK_128X128 || mbmi->sb_type == BLOCK_128X64)) || ((fbr & 1) && (mbmi->sb_type == BLOCK_128X128 || mbmi->sb_type == BLOCK_64X128))) continue; - int nhb = AOMMIN(MI_SIZE_64X64, cm->mi_cols - MI_SIZE_64X64 * fbc); - int nvb = AOMMIN(MI_SIZE_64X64, cm->mi_rows - MI_SIZE_64X64 * fbr); + int nhb = AOMMIN(MI_SIZE_64X64, mi_params->mi_cols - MI_SIZE_64X64 * fbc); + int nvb = AOMMIN(MI_SIZE_64X64, mi_params->mi_rows - MI_SIZE_64X64 * fbr); int hb_step = 1; int vb_step = 1; BLOCK_SIZE bs; @@ -465,11 +458,13 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, mbmi->sb_type == BLOCK_64X128) { bs = mbmi->sb_type; if (bs == BLOCK_128X128 || bs == BLOCK_128X64) { - nhb = AOMMIN(MI_SIZE_128X128, cm->mi_cols - MI_SIZE_64X64 * fbc); + nhb = + AOMMIN(MI_SIZE_128X128, mi_params->mi_cols - MI_SIZE_64X64 * fbc); hb_step = 2; } if (bs == BLOCK_128X128 || bs == BLOCK_64X128) { - nvb = AOMMIN(MI_SIZE_128X128, cm->mi_rows - MI_SIZE_64X64 * fbr); + nvb = + AOMMIN(MI_SIZE_128X128, mi_params->mi_rows - MI_SIZE_64X64 * fbr); vb_step = 2; } } else { @@ -477,16 +472,16 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, } const int cdef_count = av1_cdef_compute_sb_list( - cm, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64, dlist, bs); + mi_params, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64, dlist, bs); const int yoff = CDEF_VBORDER * (fbr != 0); const int xoff = CDEF_HBORDER * (fbc != 0); int dirinit = 0; for (int pli = 0; pli < num_planes; pli++) { for (int i = 0; i < CDEF_INBUF_SIZE; i++) inbuf[i] = CDEF_VERY_LARGE; - /* We avoid filtering the pixels for which some of the pixels to average - are outside the frame. We could change the filter instead, but it - would add special cases for any future vectorization. */ + /* We avoid filtering the pixels for which some of the pixels to + average are outside the frame. We could change the filter instead, + but it would add special cases for any future vectorization. */ const int ysize = (nvb << mi_high_l2[pli]) + CDEF_VBORDER * (fbr + vb_step < nvfb) + yoff; const int xsize = (nhb << mi_wide_l2[pli]) + @@ -495,18 +490,18 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, const int col = fbc * MI_SIZE_64X64 << mi_wide_l2[pli]; for (int gi = 0; gi < total_strengths; gi++) { int pri_strength = gi / CDEF_SEC_STRENGTHS; - if (fast) pri_strength = priconv[pri_strength]; + if (fast) pri_strength = get_pri_strength(pick_method, pri_strength); const int sec_strength = gi % CDEF_SEC_STRENGTHS; - copy_sb16_16(&in[(-yoff * CDEF_BSTRIDE - xoff)], CDEF_BSTRIDE, - src[pli], row - yoff, col - xoff, stride[pli], ysize, - xsize); + copy_fn(&in[(-yoff * CDEF_BSTRIDE - xoff)], CDEF_BSTRIDE, + xd->plane[pli].dst.buf, row - yoff, col - xoff, + xd->plane[pli].dst.stride, ysize, xsize); av1_cdef_filter_fb( NULL, tmp_dst, CDEF_BSTRIDE, in, xdec[pli], ydec[pli], dir, &dirinit, var, pli, dlist, cdef_count, pri_strength, sec_strength + (sec_strength == 3), damping, coeff_shift); - const uint64_t curr_mse = compute_cdef_dist( - ref_coeff[pli] + row * stride[pli] + col, stride[pli], tmp_dst, - dlist, cdef_count, bsize[pli], coeff_shift, pli); + const uint64_t curr_mse = compute_cdef_dist_fn( + ref_buffer[pli], ref_stride[pli], tmp_dst, dlist, cdef_count, + bsize[pli], coeff_shift, row, col); if (pli < 2) mse[pli][sb_count][gi] = curr_mse; else @@ -514,7 +509,7 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, } } sb_index[sb_count++] = - MI_SIZE_64X64 * fbr * cm->mi_stride + MI_SIZE_64X64 * fbc; + MI_SIZE_64X64 * fbr * mi_params->mi_stride + MI_SIZE_64X64 * fbc; } } @@ -529,10 +524,10 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, uint64_t tot_mse; if (num_planes > 1) { tot_mse = joint_strength_search_dual(best_lev0, best_lev1, nb_strengths, - mse, sb_count, fast); + mse, sb_count, pick_method); } else { tot_mse = joint_strength_search(best_lev0, nb_strengths, mse[0], sb_count, - fast); + pick_method); } const int total_bits = sb_count * i + nb_strengths * CDEF_STRENGTH_BITS * @@ -565,19 +560,22 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, best_mse = curr; } } - cm->mi_grid_base[sb_index[i]]->cdef_strength = best_gi; + mi_params->mi_grid_base[sb_index[i]]->cdef_strength = best_gi; } if (fast) { for (int j = 0; j < cdef_info->nb_cdef_strengths; j++) { const int luma_strength = cdef_info->cdef_strengths[j]; const int chroma_strength = cdef_info->cdef_uv_strengths[j]; - cdef_info->cdef_strengths[j] = - priconv[luma_strength / CDEF_SEC_STRENGTHS] * CDEF_SEC_STRENGTHS + - (luma_strength % CDEF_SEC_STRENGTHS); - cdef_info->cdef_uv_strengths[j] = - priconv[chroma_strength / CDEF_SEC_STRENGTHS] * CDEF_SEC_STRENGTHS + - (chroma_strength % CDEF_SEC_STRENGTHS); + int pri_strength; + pri_strength = + get_pri_strength(pick_method, luma_strength / CDEF_SEC_STRENGTHS); + cdef_info->cdef_strengths[j] = pri_strength * CDEF_SEC_STRENGTHS + + (luma_strength % CDEF_SEC_STRENGTHS); + pri_strength = + get_pri_strength(pick_method, chroma_strength / CDEF_SEC_STRENGTHS); + cdef_info->cdef_uv_strengths[j] = pri_strength * CDEF_SEC_STRENGTHS + + (chroma_strength % CDEF_SEC_STRENGTHS); } } @@ -585,9 +583,5 @@ void av1_cdef_search(YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref, aom_free(mse[0]); aom_free(mse[1]); - for (int pli = 0; pli < num_planes; pli++) { - aom_free(src[pli]); - aom_free(ref_coeff[pli]); - } aom_free(sb_index); } diff --git a/media/libaom/src/av1/encoder/picklpf.c b/media/libaom/src/av1/encoder/picklpf.c index 52acd5ce5a..17c9965519 100644 --- a/media/libaom/src/av1/encoder/picklpf.c +++ b/media/libaom/src/av1/encoder/picklpf.c @@ -19,8 +19,8 @@ #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/av1_loopfilter.h" -#include "av1/common/onyxc_int.h" #include "av1/common/quant_common.h" #include "av1/encoder/av1_quantize.h" @@ -38,7 +38,7 @@ static void yv12_copy_plane(const YV12_BUFFER_CONFIG *src_bc, } int av1_get_max_filter_level(const AV1_COMP *cpi) { - if (cpi->oxcf.pass == 2) { + if (is_stat_consumption_stage_twopass(cpi)) { return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4 : MAX_LOOP_FILTER; } else { @@ -142,11 +142,12 @@ static int search_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, // Bias against raising loop filter in favor of lowering it. int64_t bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; - if ((cpi->oxcf.pass == 2) && (cpi->twopass.section_intra_rating < 20)) + if ((is_stat_consumption_stage_twopass(cpi)) && + (cpi->twopass.section_intra_rating < 20)) bias = (bias * cpi->twopass.section_intra_rating) / 20; // yx, bias less for large block size - if (cm->tx_mode != ONLY_4X4) bias >>= 1; + if (cm->features.tx_mode != ONLY_4X4) bias >>= 1; if (filt_direction <= 0 && filt_low != filt_mid) { // Get Low filter error score @@ -212,8 +213,8 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, } else if (method >= LPF_PICK_FROM_Q) { const int min_filter_level = 0; const int max_filter_level = av1_get_max_filter_level(cpi); - const int q = - av1_ac_quant_QTX(cm->base_qindex, 0, cm->seq_params.bit_depth); + const int q = av1_ac_quant_QTX(cm->quant_params.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; @@ -263,12 +264,14 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi, lf->filter_level[0] = lf->filter_level[1] = search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, last_frame_filter_level, NULL, 0, 2); - lf->filter_level[0] = - search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, - last_frame_filter_level, NULL, 0, 0); - lf->filter_level[1] = - search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, - last_frame_filter_level, NULL, 0, 1); + if (method != LPF_PICK_FROM_FULL_IMAGE_NON_DUAL) { + lf->filter_level[0] = + search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, + last_frame_filter_level, NULL, 0, 0); + lf->filter_level[1] = + search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE, + last_frame_filter_level, NULL, 0, 1); + } if (num_planes > 1) { lf->filter_level_u = diff --git a/media/libaom/src/av1/encoder/pickrst.c b/media/libaom/src/av1/encoder/pickrst.c index 0b26641b75..ccbe1cc3ea 100644 --- a/media/libaom/src/av1/encoder/pickrst.c +++ b/media/libaom/src/av1/encoder/pickrst.c @@ -23,7 +23,7 @@ #include "aom_mem/aom_mem.h" #include "aom_ports/mem.h" #include "aom_ports/system_state.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/quant_common.h" #include "av1/common/restoration.h" @@ -63,20 +63,29 @@ typedef int64_t (*sse_part_extractor_type)(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, int hstart, int width, int vstart, int height); +typedef uint64_t (*var_part_extractor_type)(const YV12_BUFFER_CONFIG *a, + int hstart, int width, int vstart, + int height); #if CONFIG_AV1_HIGHBITDEPTH #define NUM_EXTRACTORS (3 * (1 + 1)) -static const sse_part_extractor_type sse_part_extractors[NUM_EXTRACTORS] = { - aom_get_y_sse_part, aom_get_u_sse_part, - aom_get_v_sse_part, aom_highbd_get_y_sse_part, - aom_highbd_get_u_sse_part, aom_highbd_get_v_sse_part, -}; #else #define NUM_EXTRACTORS 3 -static const sse_part_extractor_type sse_part_extractors[NUM_EXTRACTORS] = { - aom_get_y_sse_part, aom_get_u_sse_part, aom_get_v_sse_part -}; #endif +static const sse_part_extractor_type sse_part_extractors[NUM_EXTRACTORS] = { + aom_get_y_sse_part, aom_get_u_sse_part, + aom_get_v_sse_part, +#if CONFIG_AV1_HIGHBITDEPTH + aom_highbd_get_y_sse_part, aom_highbd_get_u_sse_part, + aom_highbd_get_v_sse_part, +#endif +}; +static const var_part_extractor_type var_part_extractors[NUM_EXTRACTORS] = { + aom_get_y_var, aom_get_u_var, aom_get_v_var, +#if CONFIG_AV1_HIGHBITDEPTH + aom_highbd_get_y_var, aom_highbd_get_u_var, aom_highbd_get_v_var, +#endif +}; static int64_t sse_restoration_unit(const RestorationTileLimits *limits, const YV12_BUFFER_CONFIG *src, @@ -87,6 +96,14 @@ static int64_t sse_restoration_unit(const RestorationTileLimits *limits, limits->v_start, limits->v_end - limits->v_start); } +static uint64_t var_restoration_unit(const RestorationTileLimits *limits, + const YV12_BUFFER_CONFIG *src, int plane, + int highbd) { + return var_part_extractors[3 * highbd + plane]( + src, limits->h_start, limits->h_end - limits->h_start, limits->v_start, + limits->v_end - limits->v_start); +} + typedef struct { // The best coefficients for Wiener or Sgrproj restoration WienerInfo wiener; @@ -98,6 +115,10 @@ typedef struct { // The rtype to use for this unit given a frame rtype as // index. Indices: WIENER, SGRPROJ, SWITCHABLE. RestorationType best_rtype[RESTORE_TYPES - 1]; + + // This flag will be set based on the speed feature + // 'prune_sgr_based_on_wiener'. 0 implies no pruning and 1 implies pruning. + uint8_t skip_sgr_eval; } RestUnitSearchInfo; typedef struct { @@ -624,7 +645,7 @@ static AOM_INLINE void av1_calc_proj_params_high_bd_c( dat_stride, flt0, flt0_stride, H, C); } else if (params->r[1] > 0) { calc_proj_params_r1_high_bd_c(src8, width, height, src_stride, dat8, - dat_stride, flt0, flt0_stride, H, C); + dat_stride, flt1, flt1_stride, H, C); } } @@ -857,6 +878,16 @@ static AOM_INLINE void search_sgrproj(const RestorationTileLimits *limits, const int highbd = cm->seq_params.use_highbitdepth; const int bit_depth = cm->seq_params.bit_depth; + const int64_t bits_none = x->sgrproj_restore_cost[0]; + // Prune evaluation of RESTORE_SGRPROJ if 'skip_sgr_eval' is set + if (rusi->skip_sgr_eval) { + rsc->bits += bits_none; + rsc->sse += rusi->sse[RESTORE_NONE]; + rusi->best_rtype[RESTORE_SGRPROJ - 1] = RESTORE_NONE; + rusi->sse[RESTORE_SGRPROJ] = INT64_MAX; + return; + } + uint8_t *dgd_start = rsc->dgd_buffer + limits->v_start * rsc->dgd_stride + limits->h_start; const uint8_t *src_start = @@ -872,7 +903,7 @@ static AOM_INLINE void search_sgrproj(const RestorationTileLimits *limits, dgd_start, limits->h_end - limits->h_start, limits->v_end - limits->v_start, rsc->dgd_stride, src_start, rsc->src_stride, highbd, bit_depth, procunit_width, procunit_height, - tmpbuf, rsc->sf->enable_sgr_ep_pruning); + tmpbuf, rsc->sf->lpf_sf.enable_sgr_ep_pruning); RestorationUnitInfo rui; rui.restoration_type = RESTORE_SGRPROJ; @@ -880,7 +911,6 @@ static AOM_INLINE void search_sgrproj(const RestorationTileLimits *limits, rusi->sse[RESTORE_SGRPROJ] = try_restoration_unit(rsc, limits, tile, &rui); - const int64_t bits_none = x->sgrproj_restore_cost[0]; const int64_t bits_sgr = x->sgrproj_restore_cost[1] + (count_sgrproj_bits(&rusi->sgrproj, &rsc->sgrproj) << AV1_PROB_COST_SHIFT); @@ -890,7 +920,8 @@ static AOM_INLINE void search_sgrproj(const RestorationTileLimits *limits, double cost_sgr = RDCOST_DBL(x->rdmult, bits_sgr >> 4, rusi->sse[RESTORE_SGRPROJ]); if (rusi->sgrproj.ep < 10) - cost_sgr *= (1 + DUAL_SGR_PENALTY_MULT * rsc->sf->dual_sgr_penalty_level); + cost_sgr *= + (1 + DUAL_SGR_PENALTY_MULT * rsc->sf->lpf_sf.dual_sgr_penalty_level); RestorationType rtype = (cost_sgr < cost_none) ? RESTORE_SGRPROJ : RESTORE_NONE; @@ -1426,11 +1457,41 @@ static AOM_INLINE void search_wiener(const RestorationTileLimits *limits, RestSearchCtxt *rsc = (RestSearchCtxt *)priv; RestUnitSearchInfo *rusi = &rsc->rusi[rest_unit_idx]; + const MACROBLOCK *const x = rsc->x; + const int64_t bits_none = x->wiener_restore_cost[0]; + + // Skip Wiener search for low variance contents + if (rsc->sf->lpf_sf.prune_wiener_based_on_src_var) { + const int scale[3] = { 0, 1, 2 }; + // Obtain the normalized Qscale + const int qs = av1_dc_quant_QTX(rsc->cm->quant_params.base_qindex, 0, + rsc->cm->seq_params.bit_depth) >> + 3; + // Derive threshold as sqr(normalized Qscale) * scale / 16, + const uint64_t thresh = + (qs * qs * scale[rsc->sf->lpf_sf.prune_wiener_based_on_src_var]) >> 4; + const int highbd = rsc->cm->seq_params.use_highbitdepth; + const uint64_t src_var = + var_restoration_unit(limits, rsc->src, rsc->plane, highbd); + // Do not perform Wiener search if source variance is lower than threshold + // or if the reconstruction error is zero + int prune_wiener = (src_var < thresh) || (rusi->sse[RESTORE_NONE] == 0); + if (prune_wiener) { + rsc->bits += bits_none; + rsc->sse += rusi->sse[RESTORE_NONE]; + rusi->best_rtype[RESTORE_WIENER - 1] = RESTORE_NONE; + rusi->sse[RESTORE_WIENER] = INT64_MAX; + if (rsc->sf->lpf_sf.prune_sgr_based_on_wiener == 2) + rusi->skip_sgr_eval = 1; + return; + } + } + const int wiener_win = (rsc->plane == AOM_PLANE_Y) ? WIENER_WIN : WIENER_WIN_CHROMA; int reduced_wiener_win = wiener_win; - if (rsc->sf->reduce_wiener_window_size) { + if (rsc->sf->lpf_sf.reduce_wiener_window_size) { reduced_wiener_win = (rsc->plane == AOM_PLANE_Y) ? WIENER_WIN_REDUCED : WIENER_WIN_CHROMA; } @@ -1456,14 +1517,13 @@ static AOM_INLINE void search_wiener(const RestorationTileLimits *limits, limits->h_start, limits->h_end, limits->v_start, limits->v_end, rsc->dgd_stride, rsc->src_stride, M, H); #endif - const MACROBLOCK *const x = rsc->x; - const int64_t bits_none = x->wiener_restore_cost[0]; if (!wiener_decompose_sep_sym(reduced_wiener_win, M, H, vfilter, hfilter)) { rsc->bits += bits_none; rsc->sse += rusi->sse[RESTORE_NONE]; rusi->best_rtype[RESTORE_WIENER - 1] = RESTORE_NONE; rusi->sse[RESTORE_WIENER] = INT64_MAX; + if (rsc->sf->lpf_sf.prune_sgr_based_on_wiener == 2) rusi->skip_sgr_eval = 1; return; } @@ -1482,6 +1542,7 @@ static AOM_INLINE void search_wiener(const RestorationTileLimits *limits, rsc->sse += rusi->sse[RESTORE_NONE]; rusi->best_rtype[RESTORE_WIENER - 1] = RESTORE_NONE; rusi->sse[RESTORE_WIENER] = INT64_MAX; + if (rsc->sf->lpf_sf.prune_sgr_based_on_wiener == 2) rusi->skip_sgr_eval = 1; return; } @@ -1512,6 +1573,14 @@ static AOM_INLINE void search_wiener(const RestorationTileLimits *limits, (cost_wiener < cost_none) ? RESTORE_WIENER : RESTORE_NONE; rusi->best_rtype[RESTORE_WIENER - 1] = rtype; + // Set 'skip_sgr_eval' based on rdcost ratio of RESTORE_WIENER and + // RESTORE_NONE or based on best_rtype + if (rsc->sf->lpf_sf.prune_sgr_based_on_wiener == 1) { + rusi->skip_sgr_eval = cost_wiener > (1.01 * cost_none); + } else if (rsc->sf->lpf_sf.prune_sgr_based_on_wiener == 2) { + rusi->skip_sgr_eval = rusi->best_rtype[RESTORE_WIENER - 1] == RESTORE_NONE; + } + rsc->sse += rusi->sse[rtype]; rsc->bits += (cost_wiener < cost_none) ? bits_wiener : bits_none; if (cost_wiener < cost_none) rsc->wiener = rusi->wiener; @@ -1583,7 +1652,8 @@ static AOM_INLINE void search_switchable(const RestorationTileLimits *limits, const int64_t bits = x->switchable_restore_cost[r] + coeff_bits; double cost = RDCOST_DBL(x->rdmult, bits >> 4, sse); if (r == RESTORE_SGRPROJ && rusi->sgrproj.ep < 10) - cost *= (1 + DUAL_SGR_PENALTY_MULT * rsc->sf->dual_sgr_penalty_level); + cost *= + (1 + DUAL_SGR_PENALTY_MULT * rsc->sf->lpf_sf.dual_sgr_penalty_level); if (r == 0 || cost < best_cost) { best_cost = cost; best_bits = bits; @@ -1631,7 +1701,7 @@ static int rest_tiles_in_plane(const AV1_COMMON *cm, int plane) { void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; const int num_planes = av1_num_planes(cm); - assert(!cm->all_lossless); + assert(!cm->features.all_lossless); int ntiles[2]; for (int is_uv = 0; is_uv < 2; ++is_uv) @@ -1664,7 +1734,7 @@ 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; - if (!cpi->sf.disable_loop_restoration_chroma || !plane) { + if (!cpi->sf.lpf_sf.disable_loop_restoration_chroma || !plane) { av1_extend_frame(rsc.dgd_buffer, rsc.plane_width, rsc.plane_height, rsc.dgd_stride, RESTORATION_BORDER, RESTORATION_BORDER, highbd); diff --git a/media/libaom/src/av1/encoder/ransac.c b/media/libaom/src/av1/encoder/ransac.c index 685d93bea0..07e1a5f5f8 100644 --- a/media/libaom/src/av1/encoder/ransac.c +++ b/media/libaom/src/av1/encoder/ransac.c @@ -530,8 +530,8 @@ static int ransac(const int *matched_points, int npoints, params_by_motion[i].num_inliers = motions[i].num_inliers; memcpy(params_by_motion[i].inliers, motions[i].inlier_indices, sizeof(*motions[i].inlier_indices) * npoints); + num_inliers_by_motion[i] = motions[i].num_inliers; } - num_inliers_by_motion[i] = motions[i].num_inliers; } finish_ransac: diff --git a/media/libaom/src/av1/encoder/rate_distortion_model_params.h b/media/libaom/src/av1/encoder/rate_distortion_model_params.h deleted file mode 100644 index 7cd0962c57..0000000000 --- a/media/libaom/src/av1/encoder/rate_distortion_model_params.h +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Copyright (c) 2018, 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_RATE_DISTORTION_MODEL_PARAMS_H_ -#define AOM_AV1_ENCODER_RATE_DISTORTION_MODEL_PARAMS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "av1/encoder/ml.h" - -// 22 float features + -// 2 categorical features with 4 possible values, converted to one-hot vectors. -// So, total 22 + 2 * 4 = 30 features. -#define NUM_FEATURES 30 -#define NUM_HIDDEN_LAYERS 1 -#define NUM_HIDDEN_NODES 96 -#define NUM_OUTPUTS 1 - -//------------------------------------------------------------------------------ -// RDCost model - -static const float - av1_rdcost_model_nn_weights_layer0[NUM_FEATURES * NUM_HIDDEN_NODES] = { - -0.0699f, 0.2790f, 0.1915f, 0.2669f, 0.4637f, 0.4095f, - 0.2129f, 0.0634f, 0.2306f, -0.2232f, -0.5711f, -0.6493f, - -0.7406f, -0.8440f, 0.4105f, 0.1392f, 0.5218f, -0.1618f, - -0.1719f, 0.3409f, 0.1111f, -0.3609f, -0.2929f, 0.3869f, - -0.5373f, 0.0700f, 0.2572f, 0.2483f, -0.0314f, 0.5228f, - 0.0169f, -0.1357f, 0.0419f, -0.1722f, 0.1303f, 0.1198f, - -0.0013f, 0.1309f, 0.0293f, -0.1941f, 0.0668f, -0.0643f, - -0.0381f, 0.1249f, -0.0731f, -0.1649f, 0.0964f, 0.0270f, - 0.1354f, 0.0538f, -0.2064f, -0.2067f, -0.0569f, 0.0449f, - 0.1680f, -0.0732f, -0.0785f, 0.1884f, -0.2137f, -0.0189f, - 0.2976f, 0.2818f, -0.0222f, 0.2658f, 0.0488f, 0.2778f, - -0.1110f, 0.2069f, -0.0072f, -0.0095f, -0.1105f, -0.1365f, - -0.4245f, -0.4751f, -0.0736f, 0.2333f, 0.0653f, -0.0249f, - 0.0055f, -0.0838f, -0.0489f, -0.2597f, 0.2621f, -0.0251f, - -0.0545f, 0.0816f, -0.0816f, 0.3396f, -0.1047f, 0.3678f, - 0.1487f, -0.0270f, 0.2574f, 0.1018f, 0.2560f, -0.0598f, - -0.0446f, -0.1792f, 0.5336f, -0.1590f, -0.9820f, -0.6514f, - -0.6304f, -0.8359f, -0.0699f, 0.0295f, -0.0057f, -0.3088f, - -0.1466f, 0.2220f, -0.1980f, -0.3400f, -0.1228f, 0.2667f, - -0.4816f, 0.0155f, -0.0194f, 0.2051f, 0.0513f, 0.1575f, - -121.4240f, -126.6840f, -124.1106f, -127.6184f, -85.0333f, -26.6396f, - 2.7020f, 102.0452f, -85.5128f, 0.0076f, 122.2206f, 107.5265f, - 108.3773f, 93.4847f, 20.3705f, -89.6993f, -176.9070f, -41.7543f, - -123.0293f, -91.6437f, -205.7099f, -62.5346f, -83.2987f, 21.3830f, - 56.6341f, -120.8647f, -127.7562f, -121.6688f, -127.4225f, -74.8045f, - -15.9247f, -14.6468f, -14.7788f, -15.4498f, -18.5514f, -11.1579f, - -5.8164f, -3.4318f, 0.8100f, 0.0642f, 203.5111f, 189.6872f, - 190.4776f, 176.4784f, -4.9427f, -12.5324f, -7.6861f, 21.9182f, - -6.7864f, -7.1906f, -8.1292f, 21.4780f, -7.8016f, -5.2653f, - 61.8526f, -15.5105f, -14.6900f, -14.1459f, -15.4350f, -19.1379f, - -0.7876f, -1.8558f, -4.6035f, -6.8405f, -0.2904f, 2.3202f, - 1.8127f, -2.9397f, -0.8187f, -0.6098f, 22.6173f, 10.3668f, - 12.9363f, 2.4541f, 6.6700f, 0.3804f, -3.3117f, 8.5464f, - -25.8348f, 1.8698f, -9.5753f, 8.5558f, -16.3576f, 7.2217f, - 35.3115f, -1.1447f, -2.6530f, -4.7027f, -5.7024f, -0.9513f, - 0.8393f, 0.7085f, 0.7879f, 0.3728f, 3.0574f, 1.1360f, - 26.0531f, 4.1084f, -1.7340f, 0.1683f, -450.7927f, -444.5818f, - -442.5239f, -438.1168f, 2.4924f, -0.0147f, -0.0797f, -47.5322f, - -1.7638f, -0.8608f, -0.6500f, -44.4326f, -0.9027f, 2.5560f, - -267.6517f, 0.2642f, 0.9457f, 0.7944f, 0.3609f, 3.2742f, - -74.3400f, -81.6894f, -76.2162f, -69.2979f, -90.2476f, -39.7389f, - 2.2545f, 36.5095f, -60.1129f, -1.0383f, 87.0348f, 83.9940f, - 83.7199f, 80.8609f, 14.9075f, -78.7405f, -74.3549f, -4.2382f, - -23.9739f, -91.8469f, -67.2654f, -21.5293f, -9.9857f, 11.8391f, - 35.8223f, -74.2551f, -81.0729f, -73.8347f, -70.3798f, -86.8052f, - 0.1701f, -0.1136f, 0.0060f, -0.0496f, -0.1727f, 0.0195f, - -0.1040f, 0.1027f, 0.0467f, -0.2538f, -0.1322f, 0.0860f, - 0.0093f, -0.2801f, -0.0958f, 0.0497f, -0.0582f, -0.0311f, - 0.1840f, 0.0752f, 0.0282f, 0.0297f, 0.0607f, 0.0650f, - 0.0893f, 0.1297f, 0.0373f, 0.0040f, -0.0973f, 0.0248f, - -0.1419f, 0.0322f, -0.0712f, 0.0860f, -0.0426f, -0.1989f, - 0.1393f, -0.1183f, 0.0735f, -0.1895f, 0.1447f, -0.0056f, - -0.1833f, 0.0884f, 0.0949f, 0.0476f, 0.0551f, 0.2125f, - -0.1537f, -0.0141f, -0.2182f, 0.1567f, 0.0457f, -0.1485f, - -0.1177f, 0.0391f, 0.1982f, -0.1288f, 0.1165f, -0.2019f, - 0.4550f, 0.5179f, 0.4311f, 0.1861f, 0.6199f, 0.4542f, - 0.2034f, 0.1128f, 1.3489f, -0.2525f, -2.1139f, -2.2444f, - -2.3679f, -2.3378f, 0.5682f, 0.1348f, 0.3032f, -1.5835f, - 0.2883f, 0.1693f, 0.0439f, -1.4556f, 0.3818f, 0.4875f, - -1.8899f, 0.2510f, 0.6450f, 0.6082f, 0.5962f, 0.8131f, - 12.0281f, 13.3899f, 13.6249f, 15.8068f, -1.5453f, 6.7456f, - -6.0877f, 26.2596f, 6.2223f, -0.5922f, 134.1428f, 128.8985f, - 128.7538f, 123.0920f, 1.3207f, 18.3069f, 15.7436f, 46.5230f, - 24.7455f, 15.0688f, 19.9965f, 34.7236f, 19.7171f, 1.2018f, - 49.7274f, 11.8957f, 13.1578f, 14.0451f, 15.3544f, -3.5601f, - 1.0048f, 0.9479f, 1.1832f, 2.0635f, -2.9808f, 2.0803f, - -7.5815f, 8.4733f, -4.2008f, 0.1217f, 226.5257f, 210.7018f, - 211.6235f, 195.2605f, 0.8283f, 1.0977f, 1.4858f, 41.1242f, - 1.5822f, 0.8742f, 2.0440f, 33.6213f, 1.6177f, 0.9661f, - 65.0014f, 1.4197f, 1.0109f, 1.3153f, 1.5470f, -3.2833f, - 2.0858f, 2.0012f, 2.1088f, 2.5593f, -0.9422f, 1.8554f, - -6.5378f, 0.6780f, 2.3186f, 0.0506f, 218.3285f, 203.4055f, - 204.0362f, 188.7854f, 0.3701f, 2.5257f, 3.5172f, 28.8144f, - 2.1511f, 3.4676f, 2.6337f, 28.5113f, 2.4254f, -0.0548f, - 59.4511f, 2.0757f, 2.1551f, 2.2271f, 2.5300f, -1.4173f, - 91.9240f, 88.2142f, 83.6155f, 82.2482f, -9.2566f, 10.9654f, - -2.6974f, 62.6750f, -3.6298f, -0.1245f, 69.6721f, 67.1340f, - 66.9162f, 64.1994f, -83.6778f, 76.8107f, 69.7832f, 64.9261f, - 68.4901f, 76.3615f, 70.8108f, 63.5435f, 69.1973f, -83.6034f, - 24.8275f, 90.1923f, 87.6831f, 82.9783f, 81.8558f, -7.1010f, - 95.1656f, 88.3853f, 80.5835f, 79.5990f, -3.0720f, 8.1290f, - -0.6151f, 63.6425f, -4.5833f, -0.0063f, 70.1861f, 66.6250f, - 66.6148f, 63.0886f, -89.2863f, 74.7684f, 64.8897f, 60.4134f, - 62.5241f, 78.7076f, 61.7234f, 60.1688f, 61.9509f, -89.4098f, - 30.3361f, 92.9144f, 88.5954f, 79.6336f, 79.2453f, -0.4101f, - 0.6287f, 0.8050f, 0.4417f, 0.5419f, 0.5972f, 1.3037f, - 0.4316f, -0.0013f, -0.3673f, -0.4952f, 6.1773f, 5.7825f, - 6.1705f, 5.3848f, 1.7607f, -0.0152f, -0.2924f, 0.8199f, - 1.3326f, 0.7197f, -0.6332f, 1.1127f, 1.0472f, 1.8468f, - 3.4419f, 0.8233f, 0.7175f, 0.8514f, 0.6372f, 0.9472f, - -0.0813f, -0.0197f, -0.0096f, -0.2015f, 0.1133f, -0.0305f, - 0.0578f, 0.1375f, -0.0750f, -0.1702f, 0.1246f, -0.1782f, - 0.2017f, 0.0425f, -0.0602f, 0.1837f, 0.1044f, -0.1273f, - -0.1431f, 0.0672f, -0.1807f, -0.1045f, -0.1355f, -0.0497f, - -0.0561f, -0.0633f, 0.1907f, -0.0777f, 0.1203f, 0.0754f, - 0.4079f, 0.2001f, 0.0558f, 0.0622f, 0.2951f, 0.6541f, - -0.0068f, 0.1070f, 0.4469f, -0.1266f, -1.3035f, -1.3324f, - -1.3612f, -0.9966f, 0.7986f, 0.3192f, -0.5028f, -0.3844f, - -0.4079f, 0.6690f, -0.5109f, -0.2719f, -0.4958f, 1.0310f, - -0.8044f, 0.1447f, 0.4221f, 0.3194f, 0.3063f, 0.5520f, - 0.4667f, -5.7238f, -0.5602f, 12.6339f, -15.1865f, -14.9035f, - -3.0726f, 9.5347f, -24.6225f, -2.7086f, 89.8557f, 95.0657f, - 93.8693f, 99.1085f, -35.9483f, -18.0363f, -1.6298f, 25.3484f, - 39.3975f, -15.3199f, 5.7664f, 17.2367f, 25.2788f, -36.5648f, - 29.1426f, 0.3857f, -5.2117f, 0.0533f, 12.1707f, -11.1735f, - 0.2673f, 0.0090f, 0.1574f, 0.0904f, 0.0281f, 0.1144f, - 0.1123f, -0.0061f, 0.0954f, -0.0094f, -0.4387f, -0.5006f, - -0.2560f, -0.2326f, -0.1769f, 0.0465f, 0.1273f, -0.1627f, - 0.2987f, -0.3041f, 0.1131f, -0.3620f, 0.0932f, -0.0649f, - -0.4597f, 0.2535f, -0.0994f, 0.1390f, 0.1279f, 0.4207f, - -39.1159f, -42.6382f, -38.4225f, -31.2301f, -28.2382f, -28.1176f, - -9.5822f, 1.1886f, -1.2964f, -0.7908f, 154.9819f, 147.1914f, - 147.0482f, 138.7535f, -21.7014f, -35.7117f, -28.8802f, -3.8968f, - -21.5007f, -28.2213f, -28.4878f, -3.7558f, -26.8317f, -22.8491f, - 50.9464f, -37.0918f, -42.8811f, -39.3079f, -32.1904f, -26.6354f, - -72.5346f, -75.5751f, -72.6896f, -71.3671f, -35.3279f, -21.6077f, - -5.8259f, 38.7516f, -6.8012f, 0.0172f, 170.0685f, 157.4452f, - 158.2334f, 145.0102f, 10.0653f, -45.1775f, -56.4571f, -5.1165f, - -75.8980f, -46.8672f, -55.3642f, -6.5631f, -81.0258f, 10.1348f, - 55.9786f, -70.8124f, -75.7040f, -73.9831f, -70.8786f, -34.9723f, - 88.6239f, 86.5330f, 80.9333f, 79.6833f, -10.0096f, 10.6312f, - -4.2350f, 62.6230f, -3.2991f, -0.0843f, 75.8659f, 72.7886f, - 72.5301f, 68.8265f, -81.8276f, 70.3025f, 62.9511f, 62.5706f, - 69.1842f, 69.3637f, 65.4820f, 65.4357f, 71.5347f, -82.1064f, - 24.1925f, 86.2418f, 85.4985f, 80.4091f, 79.5378f, -9.3877f, - -7.6594f, -4.9581f, -10.6385f, -20.2307f, -44.2261f, -13.7557f, - -4.5344f, 18.1793f, -10.5522f, -1.5878f, 110.3187f, 102.4945f, - 102.3305f, 94.1324f, -25.2665f, 9.8172f, -4.4791f, 69.4972f, - -6.7571f, 5.8378f, -11.6101f, 70.7066f, -4.9327f, -24.0513f, - 41.4598f, -7.0600f, -7.0940f, -10.2478f, -18.9616f, -46.7505f, - 90.9365f, 86.0260f, 73.2934f, 69.3406f, 3.3863f, 3.8524f, - 0.6536f, 63.2150f, -10.6304f, 0.0291f, 73.0071f, 69.7660f, - 69.0457f, 65.5611f, -92.3379f, 74.2756f, 54.5025f, 84.3183f, - 53.7481f, 73.5624f, 55.3827f, 82.3242f, 53.5432f, -92.5355f, - 25.3457f, 89.1858f, 84.4763f, 72.9840f, 69.1889f, 4.6719f, - -0.0129f, 0.1995f, 0.2069f, 0.0358f, 0.1209f, -0.1185f, - -0.1217f, -0.1456f, 0.0125f, -0.1354f, 0.0510f, -0.0572f, - 0.1397f, 0.1453f, -0.0086f, 0.0107f, 0.0232f, 0.1508f, - 0.0884f, -0.0967f, -0.1786f, 0.1361f, -0.1399f, -0.2021f, - -0.0242f, -0.2169f, 0.0133f, 0.0116f, -0.1489f, -0.0093f, - -0.0796f, 0.1507f, 0.0906f, 0.0228f, -0.0166f, -0.1875f, - 0.0471f, 0.1184f, -0.0007f, -0.2732f, -0.1386f, -0.2057f, - -0.0213f, -0.1699f, 0.0996f, 0.1562f, 0.1850f, -0.0362f, - -0.2059f, 0.0258f, -0.0135f, -0.1276f, 0.0034f, 0.2023f, - 0.0857f, -0.0085f, -0.1955f, -0.1666f, -0.0920f, 0.0971f, - -0.0292f, -0.0512f, -0.0753f, -0.0739f, -0.0873f, -0.1200f, - 0.0220f, -0.1359f, 0.2013f, -0.0445f, 0.1143f, -0.1484f, - -0.1556f, -0.0003f, 0.1711f, -0.0724f, -0.0531f, 0.1126f, - 0.0476f, -0.0057f, 0.0088f, 0.0792f, -0.0438f, -0.1118f, - -0.0244f, 0.0712f, 0.0930f, -0.0203f, 0.1662f, -0.0695f, - -12.3872f, -18.7022f, -13.4237f, -1.4731f, -18.6843f, -14.1515f, - -7.5057f, 40.2090f, -2.7774f, -1.8433f, 123.6006f, 119.0557f, - 118.2758f, 113.6423f, -32.6216f, -19.5865f, -16.2897f, 17.2068f, - 6.3559f, -17.8742f, 0.7098f, 11.5970f, -10.1104f, -33.1830f, - 39.5617f, -10.5499f, -17.8137f, -14.7185f, -2.6172f, -14.6004f, - 0.3893f, 0.4443f, 0.5305f, 0.3049f, 0.8316f, 0.8679f, - 0.2265f, 0.2393f, 1.1970f, -0.2891f, -1.8666f, -1.8266f, - -1.6984f, -1.8787f, 0.8706f, 0.4208f, 0.5076f, -0.8436f, - -0.1623f, 0.8008f, 0.1512f, -1.0839f, -0.3002f, 0.9263f, - -1.3031f, 0.5964f, 0.3413f, 0.5551f, 0.2618f, 0.7018f, - -0.1320f, -0.1944f, -0.0209f, -0.0877f, 0.0721f, -0.0840f, - 0.0589f, 0.1019f, 0.1927f, -0.2011f, -0.1117f, 0.1575f, - 0.1080f, -0.0516f, 0.2154f, -0.1231f, 0.0426f, -0.0522f, - -0.1824f, -0.1923f, -0.1206f, -0.1724f, -0.0798f, 0.0401f, - -0.2170f, 0.0293f, -0.0853f, 0.1517f, 0.2128f, -0.1934f, - 0.0406f, 0.0517f, 0.0822f, -0.0150f, 0.0943f, -0.0989f, - -0.1802f, -0.1453f, -0.1967f, -0.1797f, 0.1545f, -0.1217f, - 0.1755f, -0.1604f, -0.0515f, 0.0509f, 0.0310f, -0.1220f, - -0.1770f, -0.0157f, 0.1989f, -0.0069f, 0.1766f, 0.1267f, - -0.0517f, -0.0396f, 0.0346f, 0.1946f, 0.1162f, -0.1345f, - -106.6179f, -110.5917f, -107.5476f, -108.0601f, -61.1687f, -22.4247f, - 2.6632f, 109.5208f, -66.1177f, 0.0062f, 159.9339f, 144.7755f, - 145.5032f, 128.9872f, 18.9180f, -75.3569f, -105.0866f, -52.0704f, - -119.1299f, -74.7543f, -109.9468f, -59.0682f, -104.5754f, 19.2878f, - 67.2573f, -104.8061f, -111.8610f, -106.6751f, -107.3537f, -56.4758f, - -0.6967f, -0.8495f, -0.9586f, -1.0461f, 1.4522f, -0.2762f, - 28.2828f, 2.9157f, -2.1062f, 0.1566f, -467.2388f, -461.0685f, - -459.0092f, -453.8370f, 1.5422f, -0.8186f, -0.4884f, -53.0399f, - -2.0255f, -1.1348f, -1.1039f, -50.2489f, -1.4821f, 1.8021f, - -258.0319f, -1.0865f, -0.5542f, -1.0443f, -1.2732f, 1.8413f, - 0.2377f, 0.1937f, -0.0116f, 0.0935f, -0.0599f, 0.0118f, - -0.0875f, 0.0455f, -0.1301f, -0.1081f, -0.2622f, -0.1960f, - 0.0393f, -0.1490f, 0.1852f, -0.0964f, -0.0741f, 0.0419f, - 0.1162f, -0.0274f, 0.1200f, -0.0333f, -0.1337f, 0.2141f, - 0.0664f, 0.1044f, -0.1744f, 0.1060f, -0.1468f, 0.0679f, - 0.0218f, 0.0494f, 0.1064f, 0.1363f, 0.0013f, 0.1331f, - -0.2095f, 0.2088f, -0.0399f, -0.1811f, 0.0678f, -0.1974f, - 0.1855f, -0.0968f, -0.2008f, 0.0162f, -0.0096f, -0.1493f, - 0.2170f, -0.1248f, -0.2055f, 0.1276f, -0.0269f, -0.1697f, - -0.0662f, 0.1073f, -0.0029f, -0.1051f, -0.1573f, 0.2106f, - -0.2020f, -0.1565f, 0.0335f, -0.1818f, -0.1665f, 0.2169f, - 0.1974f, -0.1470f, -0.1738f, -0.2038f, 0.0558f, -0.0441f, - 0.0065f, -0.1485f, -0.1366f, -0.2131f, 0.1042f, 0.0349f, - -0.1804f, -0.1361f, -0.0116f, -0.1012f, -0.0860f, 0.0606f, - -0.2077f, 0.1826f, -0.1014f, -0.0721f, -0.1517f, 0.1022f, - -0.1110f, -0.0186f, 0.1505f, 0.1797f, 0.0911f, 0.0340f, - 0.1702f, -0.1404f, -0.0566f, -0.2744f, -0.1943f, -0.1871f, - 0.0046f, 0.0306f, -0.0436f, 0.1625f, -0.1302f, 0.0175f, - 0.1570f, -0.1425f, 0.0779f, 0.1398f, 0.0929f, 0.0897f, - 0.0458f, -0.0936f, 0.1321f, -0.1355f, 0.0974f, 0.0457f, - -73.3516f, -75.0655f, -72.1062f, -72.4624f, -34.8640f, -14.3727f, - -4.4720f, 66.4982f, -18.8358f, 0.0397f, 174.2172f, 160.4959f, - 161.1034f, 147.3250f, 9.5507f, -45.0180f, -73.1609f, -1.5230f, - -74.8677f, -43.8559f, -68.7622f, -4.8971f, -82.1922f, 9.6490f, - 64.7115f, -71.8566f, -75.3879f, -72.5479f, -71.7161f, -34.8056f, - 0.1442f, 0.1558f, 0.1267f, -0.1261f, -0.0506f, -0.0823f, - -0.1807f, -0.0889f, -0.2098f, -0.1295f, -0.2046f, -0.1749f, - -0.1197f, -0.1380f, 0.0799f, -0.0889f, -0.1209f, 0.1919f, - 0.1947f, -0.2086f, -0.1042f, -0.0468f, 0.0232f, 0.1052f, - -0.0535f, 0.1398f, 0.1713f, -0.1522f, 0.1453f, 0.0286f, - -64.8503f, -67.6746f, -63.6497f, -60.4614f, -35.6091f, -20.1605f, - -3.6082f, 84.2801f, -37.8552f, -2.2371f, 132.4947f, 123.5057f, - 123.5776f, 113.9060f, -14.8772f, -40.7130f, -79.1391f, -10.7024f, - -65.7831f, -43.6078f, -79.6847f, -13.0743f, -69.2533f, -16.0171f, - 50.4868f, -64.3678f, -68.7061f, -64.0823f, -59.3413f, -28.9405f, - 77.1601f, 75.4899f, 69.8696f, 67.8764f, -22.7548f, 5.9814f, - -3.2826f, 57.9754f, -5.9500f, -0.0014f, 77.2251f, 74.0737f, - 73.7004f, 70.5072f, -80.9661f, 69.3065f, 55.8337f, 76.8831f, - 57.9902f, 63.4765f, 56.4748f, 70.0282f, 61.0874f, -81.3960f, - 26.2594f, 76.0367f, 74.9115f, 69.2361f, 66.9262f, -20.1637f, - 0.1886f, -0.1108f, 0.1262f, 0.0189f, 0.1382f, 0.0859f, - -0.1874f, -0.1986f, -0.0171f, -0.1400f, -0.2944f, -0.0750f, - -0.0395f, -0.2092f, -0.0878f, 0.1216f, -0.0870f, -0.1613f, - 0.2495f, 0.0754f, 0.0244f, -0.1205f, -0.0196f, -0.1729f, - 0.1170f, 0.1585f, 0.1482f, -0.1705f, -0.1337f, 0.0199f, - 13.0897f, 9.1111f, 6.7413f, 6.3907f, -28.1187f, 0.4556f, - -5.3116f, 30.7293f, -16.3644f, -0.0365f, 118.9118f, 111.6125f, - 111.3227f, 103.4680f, -30.1883f, 8.9328f, -4.1876f, 79.3936f, - -9.0522f, 12.7861f, -1.2736f, 78.0446f, -5.9485f, -30.5716f, - 27.8951f, 13.9613f, 6.7173f, 5.2345f, 8.3271f, -27.3705f, - 1.0488f, 1.0864f, 1.0710f, 1.7332f, -3.0561f, 1.1622f, - -7.6688f, 3.0491f, -1.3865f, 0.0769f, 222.5451f, 207.8170f, - 208.1767f, 193.1396f, 0.4447f, 2.1654f, 1.8929f, 35.1469f, - 1.1783f, 2.6199f, 1.1611f, 26.2989f, 3.4446f, 0.1551f, - 65.6529f, 1.2229f, 0.9851f, 1.0241f, 1.4373f, -3.3421f, - 0.1388f, 0.0756f, 0.2047f, 0.1140f, 0.0945f, 0.2038f, - 0.1038f, -0.2068f, -0.0626f, -0.1937f, 0.1347f, -0.0464f, - -0.0866f, 0.0250f, 0.0264f, -0.1556f, -0.1625f, 0.1028f, - -0.1255f, -0.0854f, 0.1033f, 0.0008f, -0.2133f, -0.0317f, - 0.1725f, -0.1054f, -0.1900f, 0.0383f, 0.0440f, -0.1900f, - -30.0811f, -30.9929f, -29.3194f, -26.8347f, -20.5957f, -4.1595f, - -1.9066f, 42.4707f, -9.0435f, 0.0064f, 175.7328f, 163.1350f, - 163.5085f, 151.1648f, 4.4620f, -20.6011f, -19.3402f, 1.5468f, - -32.0920f, -25.4581f, -12.3706f, -2.1636f, -32.4569f, 3.9365f, - 61.0117f, -28.4195f, -31.0837f, -30.2749f, -27.5522f, -22.8688f, - -0.3000f, 0.0092f, -0.3675f, -0.4113f, 0.0033f, 0.1138f, - 0.2182f, -0.5803f, 0.7507f, -0.2529f, -1.7724f, -1.4702f, - -1.5805f, -1.4294f, 0.1435f, -0.0168f, 0.2356f, -0.4373f, - -0.4500f, -0.4803f, -0.0041f, -0.3878f, 0.1321f, 0.2761f, - -1.1975f, -0.3509f, -0.0465f, -0.4050f, -0.1110f, 0.2233f, - 0.0950f, 0.0974f, -0.1600f, -0.1753f, -0.0328f, 0.0741f, - -0.0706f, 0.1839f, -0.0833f, -0.1367f, -0.1094f, -0.1739f, - -0.1069f, 0.0370f, -0.1404f, 0.1631f, -0.1570f, 0.2117f, - -0.1891f, 0.0395f, 0.1081f, 0.1760f, 0.0997f, 0.0853f, - -0.1018f, 0.1306f, -0.0924f, -0.2078f, 0.0801f, -0.0949f, - 0.5803f, 0.5578f, 0.4089f, 0.1912f, 0.6774f, 0.3145f, - 0.3992f, -0.1316f, 1.3142f, -0.2457f, -2.3536f, -2.4939f, - -2.3165f, -2.4879f, 0.2321f, 0.1901f, 0.1789f, -1.5215f, - 0.2645f, 0.2231f, 0.2411f, -1.2361f, 0.2971f, 0.1421f, - -1.6715f, 0.3158f, 0.2476f, 0.3596f, 0.3029f, 0.9297f, - -88.8401f, -89.5209f, -86.1926f, -87.4196f, -39.6504f, -17.9684f, - -4.2702f, 80.2017f, -29.1676f, -0.4190f, 150.2820f, 138.4751f, - 139.1087f, 126.6569f, 13.7188f, -57.0739f, -80.3383f, -18.8351f, - -87.4103f, -56.0072f, -82.7707f, -23.1871f, -93.6787f, 13.9287f, - 59.6213f, -87.4843f, -90.4227f, -86.2635f, -86.6841f, -37.9086f, - 0.1184f, -0.2169f, -0.1915f, 0.0543f, 0.1253f, -0.1370f, - 0.0836f, -0.1198f, 0.1544f, -0.2004f, -0.1118f, -0.0786f, - 0.1517f, -0.1000f, -0.1055f, 0.0936f, -0.1579f, 0.1098f, - -0.0234f, -0.0499f, 0.0951f, -0.1711f, 0.0186f, -0.2008f, - 0.1777f, 0.1386f, -0.1495f, -0.0684f, -0.2149f, -0.1198f, - -0.6205f, -0.7209f, -0.5487f, -0.9080f, 1.3400f, 0.0085f, - 28.2837f, 3.2217f, -1.8463f, 0.1620f, -464.3599f, -458.4327f, - -455.9967f, -451.0393f, 1.6619f, -0.6944f, -0.3167f, -52.3630f, - -1.6971f, -0.7340f, -0.8923f, -49.2771f, -1.1177f, 1.8810f, - -258.9386f, -1.0765f, -0.7279f, -0.5208f, -0.8839f, 1.8175f, - -78.8510f, -80.5740f, -77.8843f, -77.9798f, -36.5560f, -16.0818f, - -5.5362f, 66.4228f, -16.8150f, 0.0036f, 181.8365f, 167.7181f, - 168.2344f, 153.9725f, 11.2659f, -47.5786f, -92.6978f, 6.7573f, - -68.7704f, -48.3850f, -95.3637f, 8.8888f, -76.9497f, 11.2243f, - 60.9020f, -77.6515f, -80.7610f, -78.4537f, -77.4659f, -36.2872f, - -0.0936f, 0.1966f, -0.2121f, 0.0193f, 0.0489f, -0.1445f, - 0.0060f, 0.0358f, -0.0783f, -0.0985f, -0.2072f, -0.0802f, - -0.0185f, 0.1868f, -0.0631f, 0.1260f, -0.0675f, 0.2167f, - -0.2174f, -0.1085f, 0.1483f, -0.1655f, -0.1040f, 0.1605f, - -0.1673f, -0.0148f, -0.1856f, -0.1454f, 0.1603f, -0.1620f, - -0.9205f, -1.2716f, -3.6561f, -5.0834f, -0.7934f, 1.8710f, - 2.2999f, -2.9516f, -1.7631f, -0.3804f, 41.2998f, 26.2358f, - 28.9763f, 15.7315f, 5.2164f, 3.2963f, -5.4457f, 18.6310f, - -25.0076f, 5.4368f, -12.0085f, 17.1462f, -14.6992f, 5.6365f, - 48.6207f, -1.0921f, -1.8723f, -3.5354f, -5.1774f, -1.0200f, - -0.1065f, -0.2021f, 0.0332f, 0.1692f, -0.1239f, 0.1325f, - -0.0660f, -0.0567f, 0.2107f, -0.2084f, -0.0263f, 0.1411f, - 0.0178f, 0.0451f, 0.2024f, -0.1756f, -0.0771f, -0.1690f, - -0.2097f, -0.2130f, 0.0714f, 0.0172f, -0.0310f, 0.0649f, - -0.1550f, 0.0701f, 0.0306f, -0.1750f, -0.1988f, -0.2060f, - 0.0005f, -0.1325f, -0.1823f, -0.0900f, -0.1291f, -0.1817f, - 0.0144f, 0.0951f, -0.1954f, -0.0171f, -0.1985f, 0.0875f, - 0.0901f, -0.0857f, 0.1681f, 0.0465f, 0.1023f, 0.0985f, - -0.2152f, -0.1723f, -0.0825f, 0.0203f, -0.1206f, -0.1431f, - -0.1552f, 0.1344f, 0.0398f, 0.0169f, 0.2180f, -0.1530f, - 2.7964f, 2.7312f, 2.8831f, 3.4729f, -3.1366f, 2.4043f, - -7.2004f, 1.4128f, 2.8648f, 0.0578f, 225.5640f, 210.3712f, - 210.6907f, 195.0339f, 0.3140f, 1.8060f, 2.7355f, 33.6917f, - 3.3542f, 3.3682f, 1.7371f, 31.2424f, 3.4094f, -0.1192f, - 63.0864f, 3.0562f, 2.8633f, 2.6777f, 3.5495f, -4.2616f, - -1.4034f, 0.3930f, -4.6756f, -9.9870f, -27.8511f, 5.6071f, - -1.0862f, 34.4907f, -10.4831f, -0.0281f, 117.2617f, 104.9590f, - 106.1515f, 93.9707f, -16.8801f, 5.3036f, -21.7458f, 98.5306f, - -20.7596f, 6.4733f, -17.6440f, 98.3097f, -31.9540f, -17.0600f, - 27.4543f, -0.6140f, -1.6182f, -4.9167f, -8.9017f, -26.2485f, - -0.1952f, -0.0462f, -0.1958f, 0.1679f, -0.1592f, -0.1634f, - -0.0507f, -0.0542f, 0.0038f, -0.0343f, 0.0567f, -0.1983f, - 0.0250f, -0.0762f, 0.0902f, -0.0343f, 0.1240f, 0.1161f, - 0.1237f, 0.1870f, 0.0346f, 0.0340f, 0.0625f, -0.0355f, - 0.0278f, -0.1043f, 0.1755f, 0.0253f, 0.1750f, -0.2070f, - -5.5531f, -5.3122f, -4.9348f, -4.4782f, -7.5686f, -1.5478f, - -5.4341f, 0.5087f, -2.1382f, 0.0798f, 208.3677f, 194.0083f, - 194.4168f, 179.3082f, 1.4443f, -1.5038f, -1.4021f, 25.9363f, - -4.0635f, -2.6785f, -1.6640f, 22.2589f, -1.4910f, 1.4715f, - 59.1972f, -4.9638f, -5.1920f, -4.9193f, -5.2649f, -8.0556f, - 20.1226f, 12.0195f, 9.7385f, 10.7058f, -27.4201f, 8.4869f, - -5.0826f, 32.9212f, -2.0674f, -0.0290f, 120.5002f, 112.3222f, - 112.3287f, 104.1107f, -20.6293f, 14.8534f, -0.8748f, 103.1141f, - -1.1368f, 15.3716f, 2.7653f, 91.7285f, -0.5991f, -20.7338f, - 35.9363f, 20.5104f, 11.1988f, 9.0368f, 10.6355f, -26.5309f, - -0.2058f, -0.2176f, 0.1331f, -0.1415f, -0.0825f, -0.0470f, - -0.0615f, 0.1274f, 0.0076f, -0.0575f, -0.2065f, 0.0866f, - 0.2166f, -0.1942f, -0.1952f, 0.1323f, -0.1016f, 0.1803f, - -0.0424f, 0.1555f, 0.1118f, 0.1559f, 0.0337f, -0.0341f, - -0.0430f, 0.1988f, -0.0553f, -0.0255f, 0.1817f, 0.0608f, - 0.1431f, 0.0686f, -0.0245f, -0.2107f, 0.2001f, -0.0964f, - -0.0090f, 0.1151f, -0.0365f, -0.1986f, 0.1740f, -0.2098f, - 0.0013f, 0.1369f, 0.1910f, 0.1801f, -0.2019f, 0.0348f, - -0.1175f, 0.0627f, -0.1929f, -0.0099f, 0.1349f, 0.1804f, - -0.1071f, -0.1651f, -0.1146f, -0.0259f, 0.1626f, -0.0271f, - 0.1393f, 0.1304f, -0.0200f, 0.0924f, -0.0839f, -0.0031f, - -0.1311f, 0.0350f, -0.1330f, -0.0911f, 0.1949f, -0.0209f, - -0.1883f, 0.0269f, 0.2040f, 0.1552f, 0.1532f, 0.1157f, - -0.1102f, -0.1220f, -0.0808f, -0.1050f, 0.1716f, 0.0846f, - -0.0180f, -0.1037f, 0.2063f, 0.1237f, 0.1253f, -0.0496f, - -0.0183f, 0.0491f, 0.1703f, -0.0824f, -0.0702f, -0.1100f, - -0.0965f, 0.0130f, -0.1222f, -0.1081f, 0.0329f, 0.2115f, - -0.1438f, 0.0799f, -0.1602f, -0.0330f, 0.0501f, 0.1072f, - -0.0744f, -0.1783f, -0.0240f, 0.0777f, -0.1944f, 0.0438f, - -0.0033f, -0.1873f, 0.0984f, -0.0318f, 0.0773f, 0.1489f, - 0.3966f, 0.4711f, 0.3972f, 0.0623f, 0.5970f, 0.1018f, - 0.1375f, -0.1881f, 0.8921f, -0.1854f, -2.1138f, -2.1178f, - -1.8295f, -2.1703f, 0.5784f, -0.1937f, -0.0728f, -0.9953f, - 0.2442f, -0.4074f, -0.1591f, -1.1660f, 0.4832f, 0.2203f, - -1.4957f, 0.1544f, 0.1810f, 0.2275f, 0.4075f, 0.8153f, - 0.0715f, 0.0222f, 0.0463f, -0.0201f, 0.0396f, 0.5951f, - -0.2779f, -0.0306f, 0.7532f, -0.1596f, -4.1080f, -3.7925f, - -3.8522f, -3.2468f, 0.7728f, 0.0188f, -0.1448f, 0.4084f, - -0.4666f, -0.1036f, -1.1469f, 0.4243f, 0.2778f, 0.9023f, - -3.0216f, 0.0384f, -0.3348f, -0.0314f, -0.2788f, 0.0479f, - 139.0773f, 131.6164f, 115.0392f, 111.1817f, 41.7596f, 9.5379f, - 1.8542f, 46.9890f, -12.8221f, 0.0241f, 52.9779f, 51.5268f, - 50.8060f, 48.7028f, -132.9665f, 118.3478f, 101.1239f, 81.4608f, - 75.4251f, 121.0643f, 97.8947f, 86.8911f, 74.5576f, -133.7606f, - 29.2657f, 135.8916f, 131.3661f, 114.1687f, 111.0784f, 31.3790f, - -0.0807f, -0.0657f, -0.0027f, 0.0410f, 0.0765f, 0.1194f, - 0.0953f, -0.0060f, 0.1531f, -0.2339f, 0.1488f, -0.0615f, - -0.0579f, 0.0761f, 0.1250f, -0.0469f, 0.1480f, 0.0683f, - -0.0049f, 0.1558f, 0.2168f, -0.0736f, 0.1135f, -0.1244f, - 0.0725f, -0.1297f, -0.0215f, -0.0412f, -0.1632f, -0.0200f, - -0.1346f, -0.1954f, 0.0053f, 0.0151f, 0.1379f, -0.1497f, - -0.0102f, -0.0336f, 0.0900f, -0.1706f, -0.0932f, -0.2084f, - 0.1242f, -0.2027f, 0.0849f, -0.2139f, -0.2015f, 0.0944f, - -0.0984f, 0.2082f, 0.1625f, -0.0227f, -0.1676f, 0.1021f, - 0.1516f, 0.0245f, 0.0955f, -0.1488f, -0.0057f, 0.1783f, - -0.8568f, -0.8175f, -0.6282f, -1.3107f, 1.5712f, 0.1044f, - 28.2289f, 3.0885f, -1.9829f, 0.1600f, -465.9583f, -459.5893f, - -457.5055f, -452.7600f, 1.7229f, -0.6620f, -0.1065f, -52.8017f, - -2.0293f, -0.8224f, -1.0389f, -49.9049f, -1.2250f, 1.7647f, - -259.2465f, -1.0978f, -0.5169f, -0.8721f, -0.8197f, 1.9158f, - 16.2234f, 15.8523f, 13.8343f, 9.8509f, -21.4326f, 15.7650f, - -6.4451f, 34.8575f, 1.1387f, -0.0223f, 117.7213f, 109.8494f, - 109.7624f, 101.8532f, -20.3275f, 16.0812f, 4.9165f, 92.4919f, - 4.1615f, 13.8451f, 9.2112f, 97.1580f, -8.7037f, -20.4420f, - 27.1105f, 17.4922f, 13.9998f, 12.3888f, 11.4705f, -20.9568f, - 0.5457f, 0.5322f, 0.2823f, 0.3581f, 0.5359f, 0.1576f, - 0.1969f, -0.0136f, -0.2748f, -0.3168f, -0.3918f, -0.2167f, - -0.1797f, -0.1869f, 0.2986f, -0.2116f, -0.4226f, -0.2022f, - 0.9452f, 0.5474f, -0.1218f, 0.2067f, -0.1600f, 0.1937f, - 0.0808f, 0.4877f, 0.5106f, 0.2626f, 0.5076f, 0.6228f, - 0.5124f, 0.4044f, 0.4023f, 0.1222f, 2.5446f, 0.9623f, - 24.9875f, 4.7442f, -2.0551f, 0.1642f, -449.9478f, -444.1841f, - -442.0153f, -437.1498f, 2.3209f, -0.6986f, -0.3456f, -47.4074f, - -1.2374f, -1.0939f, -0.9112f, -41.1851f, -0.5064f, 2.4209f, - -263.4446f, -0.0433f, 0.3460f, 0.1475f, 0.3770f, 2.9154f, - 0.2032f, 0.1527f, 0.2161f, -0.1981f, 0.1893f, -0.2003f, - 0.1734f, 0.1713f, 0.1207f, -0.2073f, -0.1018f, 0.0770f, - 0.0728f, 0.1665f, 0.0689f, 0.1884f, -0.1399f, -0.1326f, - -0.0518f, -0.1948f, 0.1576f, -0.1835f, 0.1436f, 0.0497f, - 0.0883f, -0.1253f, -0.0417f, -0.0507f, -0.1555f, 0.2076f, - -2.4080f, 6.1616f, -0.8564f, -13.6773f, -32.7238f, -16.3144f, - -1.9828f, 20.5110f, -17.0191f, -1.7154f, 103.6642f, 95.3675f, - 95.5662f, 86.9504f, -35.5340f, 19.6681f, -2.4900f, 65.0847f, - -15.8119f, 13.7256f, -4.6753f, 63.4713f, -6.5992f, -34.2369f, - 41.3959f, -1.5528f, 3.8106f, -0.7762f, -12.3204f, -35.1734f, - -83.9509f, -87.4861f, -83.5925f, -81.5047f, -54.1256f, -45.7506f, - -13.5325f, -6.0331f, -8.5062f, 0.0261f, 189.9450f, 177.7870f, - 178.6945f, 164.9762f, 9.8521f, -68.0619f, -68.6145f, 6.5056f, - -55.9651f, -66.9540f, -65.3349f, -2.1954f, -57.2408f, 8.6577f, - 60.6966f, -82.1056f, -88.5245f, -83.3057f, -80.7283f, -50.5285f, - -0.1397f, 0.1862f, -0.0691f, -0.0906f, 0.1560f, 0.1377f, - -0.0066f, -0.0213f, 0.0708f, -0.0386f, -0.0015f, -0.0020f, - -0.2122f, 0.0747f, 0.0795f, 0.0229f, 0.1923f, -0.1661f, - 0.0895f, 0.1176f, 0.1398f, -0.0443f, 0.0934f, 0.0638f, - -0.1924f, 0.0602f, 0.0404f, 0.1597f, 0.1387f, -0.0601f, - -28.3967f, -21.8483f, -25.5175f, -29.9252f, 2.0161f, -3.0092f, - 7.7435f, 28.2367f, -35.0188f, -0.1578f, 105.0164f, 93.4495f, - 94.9134f, 81.0315f, 4.3602f, 8.1303f, -37.7665f, -16.6986f, - -40.8902f, 8.2542f, -33.3215f, -2.0457f, -69.0245f, 4.1016f, - 47.2770f, -25.8268f, -23.6034f, -26.4339f, -27.8305f, 8.4468f, - 13.8742f, 8.3874f, 4.2044f, 1.4619f, -40.2909f, -0.6358f, - -0.7982f, 36.1931f, -17.3147f, -0.3348f, 106.8135f, 96.5298f, - 97.8829f, 86.9994f, -25.8170f, 15.0652f, -0.9181f, 85.8544f, - 2.5475f, 9.8009f, -3.5931f, 89.2017f, -3.7252f, -25.2986f, - 22.5505f, 14.0434f, 7.0708f, 4.6646f, 1.5807f, -39.4024f, - -0.1436f, 0.0256f, 0.0274f, -0.2126f, 0.0401f, 0.0745f, - -0.0379f, -0.0357f, 0.0777f, -0.0709f, -0.1093f, -0.2047f, - -0.0713f, -0.0478f, -0.0908f, 0.1963f, 0.1282f, 0.0977f, - 0.1304f, 0.2058f, 0.0700f, 0.0518f, 0.0239f, 0.0686f, - -0.1909f, 0.0828f, -0.1243f, -0.1920f, 0.1908f, -0.0808f, - 90.8028f, 89.2894f, 84.5339f, 83.3491f, -13.3838f, 12.0240f, - -3.9443f, 63.0867f, -2.5321f, -0.0099f, 68.9140f, 66.3206f, - 66.0278f, 63.1498f, -83.7261f, 74.3448f, 73.4998f, 64.8477f, - 69.7701f, 74.5878f, 71.0331f, 63.2116f, 74.3162f, -83.9282f, - 20.8163f, 89.6818f, 88.6452f, 83.7338f, 82.9360f, -13.2357f, - 0.1299f, -0.1765f, -0.0168f, -0.1372f, -0.1183f, 0.0472f, - 0.1312f, 0.0267f, 0.0194f, -0.1593f, 0.0059f, 0.1775f, - 0.0668f, -0.1239f, -0.1982f, -0.1415f, -0.1659f, -0.1148f, - 0.0136f, 0.0913f, -0.1254f, -0.0357f, 0.0892f, 0.0835f, - -0.0554f, 0.1969f, -0.0888f, -0.0623f, -0.0236f, -0.1492f, - 0.4196f, 0.3218f, 0.2287f, 0.5095f, 0.7210f, 0.2279f, - 0.4523f, -0.1832f, 1.3095f, -0.2041f, -2.1443f, -2.1947f, - -1.9292f, -2.1142f, 0.5840f, 0.1018f, 0.1011f, -1.6565f, - 0.4325f, 0.0424f, 0.2836f, -1.7183f, 0.2595f, 0.2686f, - -1.8784f, 0.3891f, 0.3050f, 0.6195f, 0.2896f, 0.5905f, - -5.3024f, -3.2518f, -12.5192f, -29.1732f, 1.6538f, -1.8315f, - 9.9788f, 10.5155f, 6.3234f, -0.3460f, 76.9925f, 51.3785f, - 55.7120f, 29.0432f, 5.5901f, 25.6578f, -3.9565f, 13.0509f, - -106.0371f, 23.2124f, -18.2004f, 8.4618f, -69.3585f, 5.5651f, - 80.0565f, -6.4941f, -5.3742f, -14.4209f, -24.1565f, 6.6801f, - -22.0585f, -20.9909f, -26.7939f, -29.6890f, -14.5085f, 2.1866f, - -4.2608f, 17.3977f, -30.8824f, -0.4017f, 135.6957f, 126.9320f, - 127.0044f, 118.1835f, -1.8768f, -0.8629f, -32.0882f, 44.7862f, - -23.9174f, 1.6485f, -27.9940f, 51.9078f, -48.5279f, -1.7550f, - 49.9230f, -19.9785f, -22.4647f, -27.6911f, -27.3197f, -10.6545f, - -0.1922f, -0.1999f, -0.1396f, 0.1065f, 0.0085f, -0.1940f, - 0.0351f, 0.1285f, -0.0292f, -0.1296f, 0.1543f, -0.2082f, - -0.1758f, 0.0719f, 0.0764f, 0.1394f, -0.0255f, -0.0370f, - 0.1615f, -0.0568f, 0.1920f, -0.1631f, 0.0199f, 0.1884f, - 0.0693f, 0.1074f, -0.0273f, 0.1540f, 0.0098f, 0.2111f, - 0.1805f, -0.0555f, 0.1159f, 0.0469f, 0.1789f, -0.1711f, - -0.1304f, 0.1912f, -0.0737f, -0.1408f, 0.1804f, -0.2023f, - -0.0467f, -0.1019f, -0.0136f, 0.0691f, 0.1454f, -0.0213f, - 0.0929f, -0.0958f, 0.1299f, 0.1137f, 0.1175f, 0.1042f, - -0.2081f, -0.0737f, 0.0582f, 0.1640f, 0.2120f, -0.0646f, - -0.0326f, 0.1976f, 0.1182f, -0.1365f, -0.1784f, 0.2113f, - 0.0469f, 0.0763f, -0.0197f, -0.1902f, 0.1259f, 0.1598f, - -0.0180f, -0.1339f, -0.1675f, -0.1884f, -0.1973f, 0.1529f, - 0.1160f, 0.2154f, -0.1446f, -0.1395f, 0.0355f, 0.1513f, - -0.2086f, -0.1135f, -0.1502f, -0.0018f, 0.0486f, -0.0110f, - -0.0843f, -0.0716f, -0.1367f, 0.0753f, 0.0114f, 0.0475f, - -0.0632f, 0.2045f, -0.0512f, -0.0906f, -0.1071f, -0.1957f, - 0.1361f, 0.1821f, -0.1684f, -0.1383f, 0.1059f, 0.1579f, - -0.0064f, -0.1205f, -0.0718f, -0.1323f, -0.0174f, -0.1092f, - -0.1915f, 0.1978f, -0.1245f, 0.1297f, -0.1542f, 0.1556f, - -0.1752f, 0.0718f, -0.1020f, -0.1970f, 0.0518f, -0.0888f, - 0.0541f, -0.1922f, -0.1467f, -0.0653f, -0.1940f, -0.0800f, - -0.1096f, -0.0796f, -0.1310f, 0.0191f, -0.1077f, -0.0973f, - 0.1566f, 0.0074f, 0.0500f, -0.0415f, -0.2116f, 0.0227f, - 0.0895f, 0.1528f, 0.1404f, 0.0467f, 0.0462f, -0.0973f, - -0.1669f, 0.0551f, 0.1167f, -0.1470f, -0.0542f, -0.1006f, - 0.2104f, 0.1039f, -0.0211f, -0.1726f, -0.0694f, -0.0270f, - 0.0277f, -0.0715f, -0.2055f, -0.1502f, -0.1718f, -0.0043f, - 0.0174f, 0.1019f, -0.0233f, -0.1518f, -0.1331f, -0.0001f, - -0.1483f, -0.2115f, 0.0666f, 0.0014f, 0.1601f, -0.0690f, - }; - -static const float av1_rdcost_model_nn_biases_layer0[NUM_HIDDEN_NODES] = { - 0.156824f, 0.f, 0.130013f, 0.084482f, -129.058197f, -15.090252f, - -3.859116f, 0.736356f, -81.361557f, -0.001922f, -0.000713f, 0.440181f, - 14.982646f, 1.282223f, 2.23122f, 94.26635f, 93.920929f, 0.614672f, - 0.f, 0.315858f, 4.746014f, 0.116901f, -35.661354f, -75.148285f, - 92.006989f, -14.112332f, 86.673157f, -0.000307f, -0.000544f, 0.f, - -7.851313f, 0.505186f, 0.f, 0.f, -111.681091f, -0.937782f, - 0.035789f, 0.f, 0.f, -0.00102f, -75.180527f, 0.f, - -63.821148f, 79.592392f, 0.085068f, 11.184906f, 1.25406f, 0.f, - -29.779242f, -0.181732f, 0.f, 0.425554f, -90.78405f, 0.f, - -0.828326f, -81.132179f, 0.f, -2.757063f, 0.f, 0.f, - 2.967951f, -4.440599f, 0.f, -5.105355f, 14.734543f, 0.f, - 0.f, 0.f, 0.f, 0.295342f, -0.026907f, 133.375412f, - -0.000855f, 0.f, -0.875029f, 15.665165f, 0.437296f, 0.321257f, - -0.001932f, -4.235782f, -87.187782f, 0.f, -28.84696f, 7.055514f, - 0.f, 95.548302f, -0.000425f, 0.38969f, -13.88008f, -27.347931f, - 0.f, 0.f, 0.f, -0.000026f, 0.f, 0.f, -}; - -static const float - av1_rdcost_model_nn_weights_layer1[NUM_HIDDEN_NODES * NUM_OUTPUTS] = { - -0.101706f, -0.14411f, -0.139118f, -0.132945f, 118.811302f, - 3.137232f, -32.969776f, -4.150725f, 26.263071f, 0.092841f, - 0.174125f, -0.028195f, 15.712872f, 17.722702f, 5.666006f, - -121.143929f, -131.933731f, -3.000318f, -0.032063f, -0.380065f, - -1.660653f, -0.164802f, 7.177527f, 87.759155f, -119.564224f, - -98.051651f, -110.581116f, -0.069982f, 0.023906f, 0.183792f, - 40.606274f, -0.080804f, -0.053744f, -0.187848f, 157.44313f, - -4.820149f, 0.089499f, 0.070232f, -0.043038f, 0.072996f, - 93.347313f, 0.225259f, 103.223228f, -110.682541f, 0.14314f, - -89.827538f, 6.505952f, -0.076949f, 73.816132f, -0.063416f, - -0.23736f, -0.066059f, 116.049599f, 0.120871f, -4.708246f, - 107.501671f, -0.206708f, -32.688675f, 0.047608f, -0.105907f, - 6.505825f, -75.461891f, -0.160341f, 6.532121f, -84.868111f, - -0.065622f, 0.044756f, 0.008672f, 0.017155f, 0.046108f, - -0.218818f, -126.507957f, 0.028271f, 0.180625f, -4.707376f, - -121.524307f, -0.03853f, -4.103166f, -0.018947f, -95.768463f, - 15.941695f, 0.147154f, -102.863029f, -72.521698f, -0.037133f, - -138.1492f, 0.210016f, -0.084692f, -68.693665f, -52.523472f, - -0.133385f, -0.17438f, 0.008654f, -0.035642f, -0.145202f, - 0.211135f, - }; - -static const float av1_rdcost_model_nn_biases_layer1[NUM_OUTPUTS] = { - 0.251909f -}; - -static const NN_CONFIG av1_rdcost_model_nnconfig = { - NUM_FEATURES, - NUM_OUTPUTS, - NUM_HIDDEN_LAYERS, - { - NUM_HIDDEN_NODES, - }, - { - av1_rdcost_model_nn_weights_layer0, - av1_rdcost_model_nn_weights_layer1, - }, - { - av1_rdcost_model_nn_biases_layer0, - av1_rdcost_model_nn_biases_layer1, - }, -}; - -//------------------------------------------------------------------------------ - -#undef NUM_FEATURES -#undef NUM_HIDDEN_LAYERS -#undef NUM_HIDDEN_NODES -#undef NUM_OUTPUTS - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // AOM_AV1_ENCODER_RATE_DISTORTION_MODEL_PARAMS_H_ diff --git a/media/libaom/src/av1/encoder/ratectrl.c b/media/libaom/src/av1/encoder/ratectrl.c index cd56c1fece..433163f2e7 100644 --- a/media/libaom/src/av1/encoder/ratectrl.c +++ b/media/libaom/src/av1/encoder/ratectrl.c @@ -86,7 +86,11 @@ static int rtc_minq_12[QINDEX_RANGE]; static int gf_high = 2400; static int gf_low = 300; +#ifdef STRICT_RC +static int kf_high = 3200; +#else static int kf_high = 5000; +#endif static int kf_low = 400; // How many times less pixels there are to encode given the current scaling. @@ -155,13 +159,12 @@ double av1_convert_qindex_to_q(int qindex, aom_bit_depth_t bit_depth) { int av1_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex, double correction_factor, aom_bit_depth_t bit_depth) { const double q = av1_convert_qindex_to_q(qindex, bit_depth); - int enumerator = frame_type == KEY_FRAME ? 2000000 : 1800000; + int enumerator = frame_type == KEY_FRAME ? 2000000 : 1500000; assert(correction_factor <= MAX_BPB_FACTOR && correction_factor >= MIN_BPB_FACTOR); // q based adjustment to baseline enumerator - enumerator += (int)(enumerator * q) >> 12; return (int)(enumerator * correction_factor / q); } @@ -370,6 +373,42 @@ int av1_rc_drop_frame(AV1_COMP *cpi) { } } +static int adjust_q_cbr(const AV1_COMP *cpi, int q, int active_worst_quality) { + const RATE_CONTROL *const rc = &cpi->rc; + const AV1_COMMON *const cm = &cpi->common; + const int max_delta = 16; + const int change_avg_frame_bandwidth = + abs(rc->avg_frame_bandwidth - rc->prev_avg_frame_bandwidth) > + 0.1 * (rc->avg_frame_bandwidth); + // If resolution changes or avg_frame_bandwidth significantly changed, + // then set this flag to indicate change in target bits per macroblock. + const int change_target_bits_mb = + cm->prev_frame && + (cm->width != cm->prev_frame->width || + cm->height != cm->prev_frame->height || change_avg_frame_bandwidth); + // Apply some control/clamp to QP under certain conditions. + if (cm->current_frame.frame_type != KEY_FRAME && !cpi->use_svc && + rc->frames_since_key > 1 && !change_target_bits_mb && + (!cpi->oxcf.gf_cbr_boost_pct || + !(cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame))) { + // Make sure q is between oscillating Qs to prevent resonance. + if (rc->rc_1_frame * rc->rc_2_frame == -1 && + rc->q_1_frame != rc->q_2_frame) { + q = clamp(q, AOMMIN(rc->q_1_frame, rc->q_2_frame), + AOMMAX(rc->q_1_frame, rc->q_2_frame)); + } + // Limit the decrease in Q from previous frame. + if (rc->q_1_frame - q > max_delta) q = rc->q_1_frame - max_delta; + } + // For single spatial layer: if resolution has increased push q closer + // to the active_worst to avoid excess overshoot. + if (cpi->svc.number_spatial_layers <= 1 && cm->prev_frame && + (cm->width * cm->height > + 1.5 * cm->prev_frame->width * cm->prev_frame->height)) + q = (q + active_worst_quality) >> 1; + return AOMMAX(AOMMIN(q, cpi->rc.worst_quality), cpi->rc.best_quality); +} + static const RATE_FACTOR_LEVEL rate_factor_levels[FRAME_UPDATE_TYPES] = { KF_STD, // KF_UPDATE INTER_NORMAL, // LF_UPDATE @@ -393,7 +432,7 @@ 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) { + } else if (is_stat_consumption_stage(cpi)) { const RATE_FACTOR_LEVEL rf_lvl = get_rate_factor_level(&cpi->gf_group); rcf = rc->rate_correction_factors[rf_lvl]; } else { @@ -419,7 +458,7 @@ 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) { + } else if (is_stat_consumption_stage(cpi)) { const RATE_FACTOR_LEVEL rf_lvl = get_rate_factor_level(&cpi->gf_group); rc->rate_correction_factors[rf_lvl] = factor; } else { @@ -457,7 +496,7 @@ void av1_rc_update_rate_correction_factors(AV1_COMP *cpi, int width, av1_cyclic_refresh_estimate_bits_at_q(cpi, rate_correction_factor); } else { projected_size_based_on_q = av1_estimate_bits_at_q( - cpi->common.current_frame.frame_type, cm->base_qindex, MBs, + cm->current_frame.frame_type, cm->quant_params.base_qindex, MBs, rate_correction_factor, cm->seq_params.bit_depth); } // Work out a size correction factor. @@ -475,7 +514,7 @@ void av1_rc_update_rate_correction_factors(AV1_COMP *cpi, int width, } cpi->rc.q_2_frame = cpi->rc.q_1_frame; - cpi->rc.q_1_frame = cm->base_qindex; + cpi->rc.q_1_frame = cm->quant_params.base_qindex; cpi->rc.rc_2_frame = cpi->rc.rc_1_frame; if (correction_factor > 110) cpi->rc.rc_1_frame = -1; @@ -524,8 +563,8 @@ 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; + const int use_cyclic_refresh = cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + cpi->cyclic_refresh->apply_cyclic_refresh; // Find 'qindex' based on 'desired_bits_per_mb'. assert(best_qindex <= worst_qindex); @@ -582,15 +621,9 @@ int av1_rc_regulate_q(const AV1_COMP *cpi, int target_bits_per_frame, int q = find_closest_qindex_by_rate(target_bits_per_mb, cpi, correction_factor, active_best_quality, active_worst_quality); + if (cpi->oxcf.rc_mode == AOM_CBR && has_no_stats_stage(cpi)) + return adjust_q_cbr(cpi, q, active_worst_quality); - // In CBR mode, this makes sure q is between oscillating Qs to prevent - // resonance. - if (cpi->oxcf.rc_mode == AOM_CBR && !cpi->use_svc && - (cpi->rc.rc_1_frame * cpi->rc.rc_2_frame == -1) && - cpi->rc.q_1_frame != cpi->rc.q_2_frame) { - q = clamp(q, AOMMIN(cpi->rc.q_1_frame, cpi->rc.q_2_frame), - AOMMAX(cpi->rc.q_1_frame, cpi->rc.q_2_frame)); - } return q; } @@ -757,6 +790,7 @@ static int rc_pick_q_and_bounds_one_pass_cbr(const AV1_COMP *cpi, int width, av1_compute_qdelta(rc, q_val, q_val * q_adj_factor, bit_depth); } } else if (!rc->is_src_frame_alt_ref && !cpi->use_svc && + cpi->oxcf.gf_cbr_boost_pct && (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) { // Use the lower of active_worst_quality and recent // average Q as basis for GF/ARF best Q limit unless last frame was @@ -831,15 +865,15 @@ static int gf_group_pyramid_level(const GF_GROUP *gf_group, int gf_index) { static int get_active_cq_level(const RATE_CONTROL *rc, const AV1EncoderConfig *const oxcf, - int intra_only, int superres_denom) { + int intra_only, SUPERRES_MODE superres_mode, + int superres_denom) { static const double cq_adjust_threshold = 0.1; int active_cq_level = oxcf->cq_level; (void)intra_only; if (oxcf->rc_mode == AOM_CQ || oxcf->rc_mode == AOM_Q) { // printf("Superres %d %d %d = %d\n", superres_denom, intra_only, // rc->frames_to_key, !(intra_only && rc->frames_to_key <= 1)); - if ((oxcf->superres_mode == SUPERRES_QTHRESH || - oxcf->superres_mode == SUPERRES_AUTO) && + if ((superres_mode == SUPERRES_QTHRESH || superres_mode == SUPERRES_AUTO) && superres_denom != SCALE_NUMERATOR) { int mult = SUPERRES_QADJ_PER_DENOM_KEYFRAME_SOLO; if (intra_only && rc->frames_to_key <= 1) { @@ -862,6 +896,44 @@ static int get_active_cq_level(const RATE_CONTROL *rc, return active_cq_level; } +static int get_q_using_fixed_offsets(const AV1EncoderConfig *const oxcf, + const RATE_CONTROL *const rc, + const GF_GROUP *const gf_group, + int gf_index, int cq_level, + int bit_depth) { + assert(oxcf->use_fixed_qp_offsets); + assert(oxcf->rc_mode == AOM_Q); + const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_index]; + + int offset_idx = -1; + if (update_type == KF_UPDATE) { + if (rc->frames_to_key == 1) { + // Image / intra-only coding: ignore offsets. + return cq_level; + } + offset_idx = 0; + } else if (update_type == ARF_UPDATE || update_type == GF_UPDATE) { + offset_idx = 1; + } else if (update_type == INTNL_ARF_UPDATE) { + offset_idx = + AOMMIN(gf_group->layer_depth[gf_index], FIXED_QP_OFFSET_COUNT - 1); + } else { // Leaf level / overlay frame. + assert(update_type == LF_UPDATE || update_type == OVERLAY_UPDATE || + update_type == INTNL_OVERLAY_UPDATE); + return cq_level; // Directly Return worst quality allowed. + } + assert(offset_idx >= 0 && offset_idx < FIXED_QP_OFFSET_COUNT); + assert(oxcf->fixed_qp_offsets[offset_idx] >= 0); + + // Get qindex offset, by first converting to 'q' and then back. + const double q_val_orig = av1_convert_qindex_to_q(cq_level, bit_depth); + const double q_val_target = + AOMMAX(q_val_orig - oxcf->fixed_qp_offsets[offset_idx], 0.0); + const int delta_qindex = + av1_compute_qdelta(rc, q_val_orig, q_val_target, bit_depth); + return AOMMAX(cq_level + delta_qindex, 0); +} + static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width, int height, int *bottom_index, int *top_index) { @@ -869,13 +941,20 @@ static int rc_pick_q_and_bounds_one_pass_vbr(const AV1_COMP *cpi, int width, const RATE_CONTROL *const rc = &cpi->rc; const CurrentFrame *const current_frame = &cm->current_frame; const AV1EncoderConfig *const oxcf = &cpi->oxcf; - const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), - cm->superres_scale_denominator); + const int cq_level = + get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, + cm->superres_scale_denominator); + const int bit_depth = cm->seq_params.bit_depth; + + if (oxcf->use_fixed_qp_offsets) { + return get_q_using_fixed_offsets(oxcf, rc, &cpi->gf_group, + cpi->gf_group.index, cq_level, bit_depth); + } + int active_best_quality; int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi); int q; int *inter_minq; - const int bit_depth = cm->seq_params.bit_depth; ASSIGN_MINQ_TABLE(bit_depth, inter_minq); if (frame_is_intra_only(cm)) { @@ -1026,7 +1105,7 @@ int av1_frame_type_qdelta(const AV1_COMP *cpi, int q) { rate_factor = rate_factor_deltas[rf_lvl]; if (rf_lvl == GF_ARF_LOW) { - rate_factor -= (cpi->gf_group.layer_depth[cpi->gf_group.index] - 2) * 0.2; + rate_factor -= (cpi->gf_group.layer_depth[cpi->gf_group.index] - 2) * 0.1; rate_factor = AOMMAX(rate_factor, 1.0); } return av1_compute_qdelta_by_rate(&cpi->rc, frame_type, q, rate_factor, @@ -1058,8 +1137,8 @@ static int rc_pick_q_and_bounds_one_pass_cq(const AV1_COMP *cpi, int width, #define STATIC_MOTION_THRESH 95 static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, int height, int *active_best, - int *active_worst, int *arf_q, - int cq_level, int is_fwd_kf) { + int *active_worst, int cq_level, + int is_fwd_kf) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const AV1EncoderConfig *const oxcf = &cpi->oxcf; @@ -1082,8 +1161,6 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, 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 @@ -1092,7 +1169,7 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, int delta_qindex; int qindex; - if (oxcf->pass == 2 && + if (is_stat_consumption_stage_twopass(cpi) && cpi->twopass.last_kfgroup_zeromotion_pct >= STATIC_MOTION_THRESH) { qindex = AOMMIN(rc->last_kf_qindex, rc->last_boosted_qindex); active_best_quality = qindex; @@ -1117,7 +1194,7 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, active_best_quality = get_kf_active_quality(rc, active_worst_quality, bit_depth); - if (oxcf->pass == 2 && + if (is_stat_consumption_stage_twopass(cpi) && cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH) { active_best_quality /= 3; } @@ -1128,7 +1205,7 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, } // Make a further adjustment based on the kf zero motion measure. - if (oxcf->pass == 2) + if (is_stat_consumption_stage_twopass(cpi)) q_adj_factor += 0.05 - (0.001 * (double)cpi->twopass.kf_zeromotion_pct); // Convert the adjustment factor to a qindex delta @@ -1140,8 +1217,8 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, // Tweak active_best_quality for AOM_Q mode when superres is on, as this // will be used directly as 'q' later. if (oxcf->rc_mode == AOM_Q && - (oxcf->superres_mode == SUPERRES_QTHRESH || - oxcf->superres_mode == SUPERRES_AUTO) && + (cpi->superres_mode == SUPERRES_QTHRESH || + cpi->superres_mode == SUPERRES_AUTO) && cm->superres_scale_denominator != SCALE_NUMERATOR) { active_best_quality = AOMMAX(active_best_quality - @@ -1154,19 +1231,15 @@ static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, *active_worst = active_worst_quality; } -// Does some final adjustments to the q value and bounds. This does not apply to -// AOM_Q mode unless it is an INTRA_ONLY_FRAME. -static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height, - int *active_worst, int *active_best, - int *q_out, int is_intrl_arf_boost) { +static void adjust_active_best_and_worst_quality(const AV1_COMP *cpi, + const int is_intrl_arf_boost, + int *active_worst, + int *active_best) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; - const AV1EncoderConfig *oxcf = &cpi->oxcf; const int bit_depth = cpi->common.seq_params.bit_depth; int active_best_quality = *active_best; int active_worst_quality = *active_worst; - int q; - // Extension to max or min Q if undershoot or overshoot is outside // the permitted range. if (cpi->oxcf.rc_mode != AOM_Q) { @@ -1185,6 +1258,7 @@ static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height, } aom_clear_system_state(); +#ifndef STRICT_RC // 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)) { @@ -1192,6 +1266,7 @@ static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height, active_worst_quality = AOMMAX(active_worst_quality + qdelta, active_best_quality); } +#endif // Modify active_best_quality for downscaled normal frames. if (av1_frame_scaled(cm) && !frame_is_kf_gf_arf(cpi)) { @@ -1206,7 +1281,18 @@ static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height, active_worst_quality = clamp(active_worst_quality, active_best_quality, rc->worst_quality); - if (oxcf->rc_mode == AOM_Q || + *active_best = active_best_quality; + *active_worst = active_worst_quality; +} + +static int get_q(const AV1_COMP *cpi, const int width, const int height, + const int active_worst_quality, + const int active_best_quality) { + const AV1_COMMON *const cm = &cpi->common; + const RATE_CONTROL *const rc = &cpi->rc; + int q; + + if (cpi->oxcf.rc_mode == AOM_Q || (frame_is_intra_only(cm) && !rc->this_key_frame_forced && cpi->twopass.kf_zeromotion_pct >= STATIC_KF_GROUP_THRESH && rc->frames_to_key > 1)) { @@ -1220,40 +1306,108 @@ static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height, q = AOMMIN(rc->last_boosted_qindex, (active_best_quality + active_worst_quality) / 2); } + q = clamp(q, active_best_quality, active_worst_quality); } else { q = av1_rc_regulate_q(cpi, rc->this_frame_target, active_best_quality, active_worst_quality, width, height); if (q > active_worst_quality) { // Special case when we are targeting the max allowed rate. - if (rc->this_frame_target >= rc->max_frame_bandwidth) - active_worst_quality = q; - else + if (rc->this_frame_target < rc->max_frame_bandwidth) { q = active_worst_quality; + } } + q = AOMMAX(q, active_best_quality); } - q = clamp(q, active_best_quality, active_worst_quality); + return q; +} - *active_best = active_best_quality; - *active_worst = active_worst_quality; - *q_out = q; +// Returns |active_best_quality| for an inter frame. +// The |active_best_quality| depends on different rate control modes: +// VBR, Q, CQ, CBR. +// The returning active_best_quality could further be adjusted in +// adjust_active_best_and_worst_quality(). +static int get_active_best_quality(const AV1_COMP *const cpi, + const int active_worst_quality, + const int cq_level, const int gf_index) { + const AV1_COMMON *const cm = &cpi->common; + const int bit_depth = cm->seq_params.bit_depth; + const RATE_CONTROL *const rc = &cpi->rc; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + const GF_GROUP *gf_group = &cpi->gf_group; + const int rc_mode = oxcf->rc_mode; + int *inter_minq; + ASSIGN_MINQ_TABLE(bit_depth, inter_minq); + int active_best_quality = 0; + const int is_intrl_arf_boost = + gf_group->update_type[gf_index] == INTNL_ARF_UPDATE; + const int is_leaf_frame = !(cpi->refresh_golden_frame || + cpi->refresh_alt_ref_frame || is_intrl_arf_boost); + const int is_overlay_frame = rc->is_src_frame_alt_ref; + + if (is_leaf_frame || is_overlay_frame) { + if (rc_mode == AOM_Q) return cq_level; + + active_best_quality = inter_minq[active_worst_quality]; + // For the constrained quality mode we don't want + // q to fall below the cq level. + if ((rc_mode == AOM_CQ) && (active_best_quality < cq_level)) { + active_best_quality = cq_level; + } + return active_best_quality; + } + + // TODO(chengchen): can we remove this condition? + if (rc_mode == AOM_Q && !cpi->refresh_alt_ref_frame && !is_intrl_arf_boost) { + return cq_level; + } + + // Determine active_best_quality for frames that are not leaf or overlay. + int q = active_worst_quality; + // Use the lower of active_worst_quality and recent + // average Q as basis for GF/ARF best Q limit unless last frame was + // a key frame. + if (rc->frames_since_key > 1 && + rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) { + q = rc->avg_frame_qindex[INTER_FRAME]; + } + if (rc_mode == AOM_CQ && q < cq_level) q = cq_level; + active_best_quality = get_gf_active_quality(rc, q, bit_depth); + // Constrained quality use slightly lower active best. + if (rc_mode == AOM_CQ) active_best_quality = active_best_quality * 15 / 16; + 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); + if (!is_intrl_arf_boost) return active_best_quality; + + if (rc_mode == AOM_Q || rc_mode == AOM_CQ) active_best_quality = rc->arf_q; + int this_height = gf_group_pyramid_level(gf_group, gf_index); + while (this_height > 1) { + active_best_quality = (active_best_quality + active_worst_quality + 1) / 2; + --this_height; + } + return active_best_quality; } static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, int height, int gf_index, - int *bottom_index, int *top_index, - int *arf_q) { + int *bottom_index, int *top_index) { const AV1_COMMON *const cm = &cpi->common; const RATE_CONTROL *const rc = &cpi->rc; const AV1EncoderConfig *const oxcf = &cpi->oxcf; const GF_GROUP *gf_group = &cpi->gf_group; - const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), - cm->superres_scale_denominator); + const int cq_level = + get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode, + cm->superres_scale_denominator); + const int bit_depth = cm->seq_params.bit_depth; + + if (oxcf->use_fixed_qp_offsets) { + return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_group->index, + cq_level, bit_depth); + } + int active_best_quality = 0; int active_worst_quality = rc->active_worst_quality; int q; - int *inter_minq; - const int bit_depth = cm->seq_params.bit_depth; - ASSIGN_MINQ_TABLE(bit_depth, inter_minq); const int is_intrl_arf_boost = gf_group->update_type[gf_index] == INTNL_ARF_UPDATE; @@ -1262,101 +1416,50 @@ static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width, const int is_fwd_kf = cm->current_frame.frame_type == KEY_FRAME && cm->show_frame == 0; get_intra_q_and_bounds_two_pass(cpi, width, height, &active_best_quality, - &active_worst_quality, arf_q, cq_level, - is_fwd_kf); - } else if (!rc->is_src_frame_alt_ref && - (cpi->refresh_golden_frame || is_intrl_arf_boost || - cpi->refresh_alt_ref_frame)) { - // Use the lower of active_worst_quality and recent - // average Q as basis for GF/ARF best Q limit unless last frame was - // a key frame. - if (rc->frames_since_key > 1 && - rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) { - q = rc->avg_frame_qindex[INTER_FRAME]; - } else { - q = active_worst_quality; - } - // For constrained quality dont allow Q less than the cq level - if (oxcf->rc_mode == AOM_CQ) { - if (q < cq_level) q = cq_level; - - active_best_quality = get_gf_active_quality(rc, q, bit_depth); - - // Constrained quality use slightly lower active best. - active_best_quality = active_best_quality * 15 / 16; - - if (gf_group->update_type[gf_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); - *arf_q = active_best_quality; - } 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(gf_group, gf_index); - while (this_height > 1) { - active_best_quality = - (active_best_quality + active_worst_quality + 1) / 2; - --this_height; - } - } - } else if (oxcf->rc_mode == AOM_Q) { - if (!cpi->refresh_alt_ref_frame && !is_intrl_arf_boost) { - active_best_quality = cq_level; - } else { - if (gf_group->update_type[gf_index] == ARF_UPDATE) { - active_best_quality = get_gf_active_quality(rc, q, bit_depth); - 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; - int this_height = gf_group_pyramid_level(gf_group, gf_index); - while (this_height > 1) { - active_best_quality = - (active_best_quality + active_worst_quality + 1) / 2; - --this_height; - } - } - } - } else { - active_best_quality = get_gf_active_quality(rc, q, bit_depth); - 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); - if (is_intrl_arf_boost) { - int this_height = gf_group_pyramid_level(gf_group, gf_index); - while (this_height > 1) { - active_best_quality = - (active_best_quality + active_worst_quality + 1) / 2; - --this_height; - } - } - } + &active_worst_quality, cq_level, is_fwd_kf); +#ifdef STRICT_RC + active_best_quality = 0; +#endif } else { - if (oxcf->rc_mode == AOM_Q) { - active_best_quality = cq_level; - } else { - active_best_quality = inter_minq[active_worst_quality]; +#ifdef STRICT_RC + // Active best quality limited by previous layer. + const int pyramid_level = gf_group_pyramid_level(gf_group, gf_index); + active_best_quality = + rc->active_best_quality[pyramid_level - 1] + + AOMMAX((rc->active_best_quality[pyramid_level - 1] / 10), 5); +#else + active_best_quality = + get_active_best_quality(cpi, active_worst_quality, cq_level, gf_index); +#endif - // For the constrained quality mode we don't want - // q to fall below the cq level. - if ((oxcf->rc_mode == AOM_CQ) && (active_best_quality < cq_level)) { - active_best_quality = cq_level; - } + // For alt_ref and GF frames (including internal arf frames) adjust the + // worst allowed quality as well. This insures that even on hard + // sections we dont clamp the Q at the same value for arf frames and + // leaf (non arf) frames. This is important to the TPL model which assumes + // Q drops with each arf level. + if (!(rc->is_src_frame_alt_ref) && + (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame || + is_intrl_arf_boost)) { + active_worst_quality = + (active_best_quality + (3 * active_worst_quality) + 2) / 4; } } - postprocess_q_and_bounds(cpi, width, height, &active_worst_quality, - &active_best_quality, &q, is_intrl_arf_boost); + adjust_active_best_and_worst_quality( + cpi, is_intrl_arf_boost, &active_worst_quality, &active_best_quality); + q = get_q(cpi, width, height, active_worst_quality, active_best_quality); + // Special case when we are targeting the max allowed rate. + if (rc->this_frame_target >= rc->max_frame_bandwidth && + q > active_worst_quality) { + active_worst_quality = q; + } + +#ifdef STRICT_RC + *top_index = rc->worst_quality; +#else *top_index = active_worst_quality; +#endif *bottom_index = active_best_quality; assert(*top_index <= rc->worst_quality && *top_index >= rc->best_quality); @@ -1376,7 +1479,7 @@ int av1_rc_pick_q_and_bounds(const AV1_COMP *cpi, RATE_CONTROL *rc, int width, const GF_GROUP *gf_group = &cpi->gf_group; if ((cpi->oxcf.rc_mode != AOM_Q || gf_group->update_type[gf_index] == ARF_UPDATE) && - cpi->oxcf.pass == 0) { + has_no_stats_stage(cpi)) { if (cpi->oxcf.rc_mode == AOM_CBR) q = rc_pick_q_and_bounds_one_pass_cbr(cpi, width, height, bottom_index, top_index); @@ -1389,10 +1492,8 @@ int av1_rc_pick_q_and_bounds(const AV1_COMP *cpi, RATE_CONTROL *rc, int width, q = rc_pick_q_and_bounds_one_pass_vbr(cpi, width, height, bottom_index, top_index); } else { - int arf_q = -1; // Initialize to invalid value, for sanity check later. - q = rc_pick_q_and_bounds_two_pass(cpi, width, height, gf_index, - bottom_index, top_index, &arf_q); + bottom_index, top_index); } if (gf_group->update_type[gf_index] == ARF_UPDATE) rc->arf_q = q; @@ -1408,10 +1509,11 @@ void av1_rc_compute_frame_size_bounds(const AV1_COMP *cpi, int frame_target, } else { // For very small rate targets where the fractional adjustment // may be tiny make sure there is at least a minimum range. - const int tolerance = (cpi->sf.recode_tolerance * frame_target) / 100; - *frame_under_shoot_limit = AOMMAX(frame_target - tolerance - 200, 0); + const int tolerance = + AOMMAX(100, (cpi->sf.hl_sf.recode_tolerance * frame_target) / 100); + *frame_under_shoot_limit = AOMMAX(frame_target - tolerance, 0); *frame_over_shoot_limit = - AOMMIN(frame_target + tolerance + 200, cpi->rc.max_frame_bandwidth); + AOMMIN(frame_target + tolerance, cpi->rc.max_frame_bandwidth); } } @@ -1470,7 +1572,7 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { const int is_intrnl_arf = gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE; - const int qindex = cm->base_qindex; + const int qindex = cm->quant_params.base_qindex; // Update rate control heuristics rc->projected_frame_size = (int)(bytes_used << 3); @@ -1516,6 +1618,7 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { if (current_frame->frame_type == KEY_FRAME) rc->last_kf_qindex = qindex; update_buffer_level(cpi, rc->projected_frame_size); + rc->prev_avg_frame_bandwidth = rc->avg_frame_bandwidth; // Rolling monitors of whether we are over or underspending used to help // regulate min and Max Q in two pass. @@ -1524,13 +1627,13 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { (int)(rc->this_frame_target / resize_rate_factor(cpi, cm->width, cm->height)); if (current_frame->frame_type != KEY_FRAME) { - rc->rolling_target_bits = ROUND_POWER_OF_TWO( + rc->rolling_target_bits = (int)ROUND_POWER_OF_TWO_64( rc->rolling_target_bits * 3 + rc->this_frame_target, 2); - rc->rolling_actual_bits = ROUND_POWER_OF_TWO( + rc->rolling_actual_bits = (int)ROUND_POWER_OF_TWO_64( rc->rolling_actual_bits * 3 + rc->projected_frame_size, 2); - rc->long_rolling_target_bits = ROUND_POWER_OF_TWO( + rc->long_rolling_target_bits = (int)ROUND_POWER_OF_TWO_64( rc->long_rolling_target_bits * 31 + rc->this_frame_target, 5); - rc->long_rolling_actual_bits = ROUND_POWER_OF_TWO( + rc->long_rolling_actual_bits = (int)ROUND_POWER_OF_TWO_64( rc->long_rolling_actual_bits * 31 + rc->projected_frame_size, 5); } @@ -1644,7 +1747,7 @@ void av1_rc_set_gf_interval_range(const AV1_COMP *const cpi, const AV1EncoderConfig *const oxcf = &cpi->oxcf; // Special case code for 1 pass fixed Q mode tests - if ((oxcf->pass == 0) && (oxcf->rc_mode == AOM_Q)) { + if ((has_no_stats_stage(cpi)) && (oxcf->rc_mode == AOM_Q)) { rc->max_gf_interval = FIXED_GF_INTERVAL; rc->min_gf_interval = FIXED_GF_INTERVAL; rc->static_scene_max_gf_interval = FIXED_GF_INTERVAL; @@ -1658,9 +1761,15 @@ void av1_rc_set_gf_interval_range(const AV1_COMP *const cpi, if (rc->max_gf_interval == 0) rc->max_gf_interval = av1_rc_get_default_max_gf_interval( 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; + /* + * Extended max interval for genuinely static scenes like slide shows. + * The no.of.stats available in the case of LAP is limited, + * hence setting to max_gf_interval. + */ + if (cpi->lap_enabled) + rc->static_scene_max_gf_interval = rc->max_gf_interval + 1; + else + rc->static_scene_max_gf_interval = MAX_STATIC_GF_GROUP_LENGTH; if (rc->max_gf_interval > rc->static_scene_max_gf_interval) rc->max_gf_interval = rc->static_scene_max_gf_interval; @@ -1704,28 +1813,21 @@ void av1_rc_update_framerate(AV1_COMP *cpi, int width, int height) { static void vbr_rate_correction(AV1_COMP *cpi, int *this_frame_target) { RATE_CONTROL *const rc = &cpi->rc; int64_t vbr_bits_off_target = rc->vbr_bits_off_target; - int max_delta; - double position_factor = 1.0; + const int stats_count = + cpi->twopass.stats_buf_ctx->total_stats != NULL + ? (int)cpi->twopass.stats_buf_ctx->total_stats->count + : 0; + const int frame_window = AOMMIN( + 16, (int)(stats_count - (int)cpi->common.current_frame.frame_number)); - // How far through the clip are we. - // This number is used to damp the per frame rate correction. - // Range 0 - 1.0 - if (cpi->twopass.total_stats.count != 0.) { - position_factor = sqrt((double)cpi->common.current_frame.frame_number / - cpi->twopass.total_stats.count); - } - max_delta = (int)(position_factor * - ((*this_frame_target * VBR_PCT_ADJUSTMENT_LIMIT) / 100)); + if (frame_window > 0) { + const int max_delta = + AOMMIN(abs((int)(vbr_bits_off_target / frame_window)), + (*this_frame_target * VBR_PCT_ADJUSTMENT_LIMIT) / 100); - // vbr_bits_off_target > 0 means we have extra bits to spend - if (vbr_bits_off_target > 0) { - *this_frame_target += (vbr_bits_off_target > max_delta) - ? max_delta - : (int)vbr_bits_off_target; - } else { - *this_frame_target -= (vbr_bits_off_target < -max_delta) - ? max_delta - : (int)-vbr_bits_off_target; + // vbr_bits_off_target > 0 means we have extra bits to spend + // vbr_bits_off_target < 0 we are currently overshooting + *this_frame_target += (vbr_bits_off_target >= 0) ? max_delta : -max_delta; } // Fast redistribution of bits arising from massive local undershoot. @@ -1757,20 +1859,22 @@ int av1_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; + int64_t target; #if USE_ALTREF_FOR_ONE_PASS 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) / + target = ((int64_t)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) / + target = ((int64_t)rc->avg_frame_bandwidth * rc->baseline_gf_interval) / (rc->baseline_gf_interval + af_ratio - 1); } + if (target > INT_MAX) target = INT_MAX; #else target = rc->avg_frame_bandwidth; #endif - return av1_rc_clamp_pframe_target_size(cpi, target, frame_update_type); + return av1_rc_clamp_pframe_target_size(cpi, (int)target, frame_update_type); } int av1_calc_iframe_target_size_one_pass_vbr(const AV1_COMP *const cpi) { @@ -1852,6 +1956,63 @@ int av1_calc_iframe_target_size_one_pass_cbr(const AV1_COMP *cpi) { return av1_rc_clamp_iframe_target_size(cpi, target); } +static void set_reference_structure_one_pass_rt(AV1_COMP *cpi, int gf_update) { + AV1_COMMON *const cm = &cpi->common; + ExternalFlags *const ext_flags = &cpi->ext_flags; + SVC *const svc = &cpi->svc; + // Specify the reference prediction structure, for 1 layer nonrd mode. + // Current structue is to use 3 references (LAST, GOLDEN, ALTREF), + // where ALT_REF always behind current by lag_alt frames, and GOLDEN is + // either updated on LAST with period baseline_gf_interval (fixed slot) + // or always behind current by lag_gld (gld_fixed_slot = 0, lag_gld <= 7). + const int gld_fixed_slot = 1; + const unsigned int lag_alt = 4; + int last_idx = 0; + int last_idx_refresh = 0; + int gld_idx = 0; + int alt_ref_idx = 0; + ext_flags->refresh_frame_flags_pending = 1; + svc->external_ref_frame_config = 1; + ext_flags->ref_frame_flags = 0; + ext_flags->refresh_last_frame = 1; + ext_flags->refresh_golden_frame = 0; + ext_flags->refresh_alt_ref_frame = 0; + for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) svc->ref_idx[i] = 7; + for (int i = 0; i < REF_FRAMES; ++i) svc->refresh[i] = 0; + // Always reference LAST, GOLDEN, ALTREF + ext_flags->ref_frame_flags ^= AOM_LAST_FLAG; + ext_flags->ref_frame_flags ^= AOM_GOLD_FLAG; + ext_flags->ref_frame_flags ^= AOM_ALT_FLAG; + const int sh = 7 - gld_fixed_slot; + // Moving index slot for last: 0 - (sh - 1). + if (cm->current_frame.frame_number > 1) + last_idx = ((cm->current_frame.frame_number - 1) % sh); + // Moving index for refresh of last: one ahead for next frame. + last_idx_refresh = (cm->current_frame.frame_number % sh); + gld_idx = 6; + if (!gld_fixed_slot) { + gld_idx = 7; + const unsigned int lag_gld = 7; // Must be <= 7. + // Moving index for gld_ref, lag behind current by gld_interval frames. + if (cm->current_frame.frame_number > lag_gld) + gld_idx = ((cm->current_frame.frame_number - lag_gld) % sh); + } + // Moving index for alt_ref, lag behind LAST by lag_alt frames. + if (cm->current_frame.frame_number > lag_alt) + alt_ref_idx = ((cm->current_frame.frame_number - lag_alt) % sh); + svc->ref_idx[0] = last_idx; // LAST + svc->ref_idx[1] = last_idx_refresh; // LAST2 (for refresh of last). + svc->ref_idx[3] = gld_idx; // GOLDEN + svc->ref_idx[6] = alt_ref_idx; // ALT_REF + // Refresh this slot, which will become LAST on next frame. + svc->refresh[last_idx_refresh] = 1; + // Update GOLDEN on period for fixed slot case. + if (gld_fixed_slot && gf_update) { + ext_flags->refresh_golden_frame = 1; + svc->refresh[gld_idx] = 1; + } +} + #define DEFAULT_KF_BOOST_RT 2300 #define DEFAULT_GF_BOOST_RT 2000 @@ -1861,7 +2022,17 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, RATE_CONTROL *const rc = &cpi->rc; AV1_COMMON *const cm = &cpi->common; GF_GROUP *const gf_group = &cpi->gf_group; + ResizePendingParams *const resize_pending_params = + &cpi->resize_pending_params; + int gf_update = 0; int target; + const int resize_pending = + (resize_pending_params->width && resize_pending_params->height && + (cm->width != resize_pending_params->width || + cm->height != resize_pending_params->height)); + // Turn this on to explicitly set the reference structure rather than + // relying on internal/default structure. + const int set_reference_structure = 1; if (cpi->use_svc) { av1_update_temporal_layer_framerate(cpi); av1_restore_layer_context(cpi); @@ -1883,8 +2054,10 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, frame_params->frame_type = INTER_FRAME; gf_group->update_type[gf_group->index] = LF_UPDATE; } - if (rc->frames_till_gf_update_due == 0 && cpi->svc.temporal_layer_id == 0 && - cpi->svc.spatial_layer_id == 0) { + // GF update based on frames_till_gf_update_due, also + // force upddate on resize pending frame. + if ((resize_pending || rc->frames_till_gf_update_due == 0) && + cpi->svc.temporal_layer_id == 0 && cpi->svc.spatial_layer_id == 0) { if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) av1_cyclic_refresh_set_golden_update(cpi); else @@ -1918,6 +2091,7 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, gf_group->size = rc->baseline_gf_interval; gf_group->update_type[0] = (frame_params->frame_type == KEY_FRAME) ? KF_UPDATE : GF_UPDATE; + gf_update = 1; } if (cpi->oxcf.rc_mode == AOM_CBR) { if (frame_params->frame_type == KEY_FRAME) { @@ -1936,4 +2110,8 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, } av1_rc_set_frame_target(cpi, target, cm->width, cm->height); rc->base_frame_target = target; + if (set_reference_structure && cpi->oxcf.speed >= 6 && + cm->number_spatial_layers == 1 && cm->number_temporal_layers == 1) + set_reference_structure_one_pass_rt(cpi, gf_update); + cm->current_frame.frame_type = frame_params->frame_type; } diff --git a/media/libaom/src/av1/encoder/ratectrl.h b/media/libaom/src/av1/encoder/ratectrl.h index 0c92af60bb..c463786635 100644 --- a/media/libaom/src/av1/encoder/ratectrl.h +++ b/media/libaom/src/av1/encoder/ratectrl.h @@ -17,8 +17,8 @@ #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" #ifdef __cplusplus extern "C" { @@ -45,8 +45,14 @@ extern "C" { #define MAX_PYRAMID_LVL 4 #define MIN_GF_INTERVAL 4 -#define MAX_GF_INTERVAL 16 +#define MAX_GF_INTERVAL 32 #define FIXED_GF_INTERVAL 8 // Used in some testing modes only +#define MAX_GF_LENGTH_LAP 16 + +#define MAX_NUM_GF_INTERVALS 15 + +#define MAX_ARF_LAYERS 6 +// #define STRICT_RC typedef struct { int resize_width; @@ -78,6 +84,10 @@ typedef struct { int base_frame_target; // A baseline frame target before adjustment // for previous under or over shoot. int this_frame_target; // Actual frame target after rc adjustment. + + // gop bit budget + int64_t gf_group_bits; + int projected_frame_size; int sb64_target_rate; int last_q[FRAME_TYPES]; // Separate values for Intra/Inter @@ -91,6 +101,14 @@ typedef struct { int frames_since_golden; int frames_till_gf_update_due; + + // number of determined gf group length left + int intervals_till_gf_calculate_due; + // stores gf group length intervals + int gf_intervals[MAX_NUM_GF_INTERVALS]; + // the current index in gf_intervals + int cur_gf_index; + int min_gf_interval; int max_gf_interval; int static_scene_max_gf_interval; @@ -108,6 +126,7 @@ typedef struct { 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. + int prev_avg_frame_bandwidth; int ni_av_qi; int ni_tot_qi; @@ -156,7 +175,17 @@ typedef struct { // Q index used for ALT frame int arf_q; int active_worst_quality; + int active_best_quality[MAX_ARF_LAYERS + 1]; int base_layer_qp; + + // Total number of stats used only for kf_boost calculation. + int num_stats_used_for_kf_boost; + // Total number of stats used only for gfu_boost calculation. + int num_stats_used_for_gfu_boost; + // Total number of stats required by gfu_boost calculation. + int num_stats_required_for_gfu_boost; + int next_is_fwd_key; + int enable_scenecut_detection; } RATE_CONTROL; struct AV1_COMP; diff --git a/media/libaom/src/av1/encoder/rd.c b/media/libaom/src/av1/encoder/rd.c index 6e91f66c3b..e48c771194 100644 --- a/media/libaom/src/av1/encoder/rd.c +++ b/media/libaom/src/av1/encoder/rd.c @@ -278,7 +278,7 @@ void av1_fill_mode_rates(AV1_COMMON *const cm, MACROBLOCK *x, av1_cost_tokens_from_cdf(x->compound_type_cost[i], fc->compound_type_cdf[i], NULL); for (i = 0; i < BLOCK_SIZES_ALL; ++i) { - if (get_interinter_wedge_bits(i)) { + if (av1_is_wedge_used(i)) { av1_cost_tokens_from_cdf(x->wedge_idx_cost[i], fc->wedge_idx_cdf[i], NULL); } @@ -312,14 +312,11 @@ void av1_fill_mode_rates(AV1_COMMON *const cm, MACROBLOCK *x, } // Values are now correlated to quantizer. -static int sad_per_bit16lut_8[QINDEX_RANGE]; -static int sad_per_bit4lut_8[QINDEX_RANGE]; -static int sad_per_bit16lut_10[QINDEX_RANGE]; -static int sad_per_bit4lut_10[QINDEX_RANGE]; -static int sad_per_bit16lut_12[QINDEX_RANGE]; -static int sad_per_bit4lut_12[QINDEX_RANGE]; +static int sad_per_bit_lut_8[QINDEX_RANGE]; +static int sad_per_bit_lut_10[QINDEX_RANGE]; +static int sad_per_bit_lut_12[QINDEX_RANGE]; -static void init_me_luts_bd(int *bit16lut, int *bit4lut, int range, +static void init_me_luts_bd(int *bit16lut, int range, aom_bit_depth_t bit_depth) { int i; // Initialize the sad lut tables using a formulaic calculation for now. @@ -328,17 +325,13 @@ static void init_me_luts_bd(int *bit16lut, int *bit4lut, int range, for (i = 0; i < range; i++) { const double q = av1_convert_qindex_to_q(i, bit_depth); bit16lut[i] = (int)(0.0418 * q + 2.4107); - bit4lut[i] = (int)(0.063 * q + 2.742); } } void av1_init_me_luts(void) { - init_me_luts_bd(sad_per_bit16lut_8, sad_per_bit4lut_8, QINDEX_RANGE, - AOM_BITS_8); - init_me_luts_bd(sad_per_bit16lut_10, sad_per_bit4lut_10, QINDEX_RANGE, - AOM_BITS_10); - init_me_luts_bd(sad_per_bit16lut_12, sad_per_bit4lut_12, QINDEX_RANGE, - AOM_BITS_12); + init_me_luts_bd(sad_per_bit_lut_8, QINDEX_RANGE, AOM_BITS_8); + init_me_luts_bd(sad_per_bit_lut_10, QINDEX_RANGE, AOM_BITS_10); + init_me_luts_bd(sad_per_bit_lut_12, QINDEX_RANGE, AOM_BITS_12); } static const int rd_boost_factor[16] = { 64, 32, 32, 32, 24, 16, 12, 12, @@ -364,7 +357,7 @@ int av1_compute_rd_mult_based_on_qindex(const AV1_COMP *cpi, int qindex) { int av1_compute_rd_mult(const AV1_COMP *cpi, int qindex) { int64_t rdmult = av1_compute_rd_mult_based_on_qindex(cpi, qindex); - if (cpi->oxcf.pass == 2 && + if (is_stat_consumption_stage(cpi) && (cpi->common.current_frame.frame_type != KEY_FRAME)) { const GF_GROUP *const gf_group = &cpi->gf_group; const FRAME_UPDATE_TYPE frame_type = gf_group->update_type[gf_group->index]; @@ -398,23 +391,23 @@ int av1_get_deltaq_offset(const AV1_COMP *cpi, int qindex, double beta) { int av1_get_adaptive_rdmult(const AV1_COMP *cpi, double beta) { assert(beta > 0.0); const AV1_COMMON *cm = &cpi->common; - int64_t q = - av1_dc_quant_QTX(cm->base_qindex, 0, cpi->common.seq_params.bit_depth); + int64_t q = av1_dc_quant_QTX(cm->quant_params.base_qindex, 0, + cm->seq_params.bit_depth); int64_t rdmult = 0; - switch (cpi->common.seq_params.bit_depth) { + switch (cm->seq_params.bit_depth) { case AOM_BITS_8: rdmult = (int)((88 * q * q / beta) / 24); break; case AOM_BITS_10: rdmult = ROUND_POWER_OF_TWO((int)((88 * q * q / beta) / 24), 4); break; default: - assert(cpi->common.seq_params.bit_depth == AOM_BITS_12); + assert(cm->seq_params.bit_depth == AOM_BITS_12); rdmult = ROUND_POWER_OF_TWO((int)((88 * q * q / beta) / 24), 8); break; } - if (cpi->oxcf.pass == 2 && - (cpi->common.current_frame.frame_type != KEY_FRAME)) { + if (is_stat_consumption_stage(cpi) && + (cm->current_frame.frame_type != KEY_FRAME)) { const GF_GROUP *const gf_group = &cpi->gf_group; const FRAME_UPDATE_TYPE frame_type = gf_group->update_type[gf_group->index]; const int boost_index = AOMMIN(15, (cpi->rc.gfu_boost / 100)); @@ -446,18 +439,9 @@ static int compute_rd_thresh_factor(int qindex, aom_bit_depth_t bit_depth) { void av1_initialize_me_consts(const AV1_COMP *cpi, MACROBLOCK *x, int qindex) { switch (cpi->common.seq_params.bit_depth) { - case AOM_BITS_8: - x->sadperbit16 = sad_per_bit16lut_8[qindex]; - x->sadperbit4 = sad_per_bit4lut_8[qindex]; - break; - case AOM_BITS_10: - x->sadperbit16 = sad_per_bit16lut_10[qindex]; - x->sadperbit4 = sad_per_bit4lut_10[qindex]; - break; - case AOM_BITS_12: - x->sadperbit16 = sad_per_bit16lut_12[qindex]; - x->sadperbit4 = sad_per_bit4lut_12[qindex]; - break; + case AOM_BITS_8: x->sadperbit = sad_per_bit_lut_8[qindex]; break; + case AOM_BITS_10: x->sadperbit = sad_per_bit_lut_10[qindex]; break; + case AOM_BITS_12: x->sadperbit = sad_per_bit_lut_12[qindex]; break; default: assert(0 && "bit_depth should be AOM_BITS_8, AOM_BITS_10 or AOM_BITS_12"); } @@ -467,10 +451,10 @@ static void set_block_thresholds(const AV1_COMMON *cm, RD_OPT *rd) { int i, bsize, segment_id; for (segment_id = 0; segment_id < MAX_SEGMENTS; ++segment_id) { - const int qindex = - clamp(av1_get_qindex(&cm->seg, segment_id, cm->base_qindex) + - cm->y_dc_delta_q, - 0, MAXQ); + const int qindex = clamp( + av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex) + + cm->quant_params.y_dc_delta_q, + 0, MAXQ); const int q = compute_rd_thresh_factor(qindex, cm->seq_params.bit_depth); for (bsize = 0; bsize < BLOCK_SIZES_ALL; ++bsize) { @@ -605,33 +589,37 @@ void av1_initialize_rd_consts(AV1_COMP *cpi) { aom_clear_system_state(); - rd->RDMULT = av1_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q); + rd->RDMULT = av1_compute_rd_mult( + cpi, cm->quant_params.base_qindex + cm->quant_params.y_dc_delta_q); set_error_per_bit(x, rd->RDMULT); set_block_thresholds(cm, rd); - if ((!cpi->sf.use_nonrd_pick_mode && + if ((!cpi->sf.rt_sf.use_nonrd_pick_mode && cpi->oxcf.mv_cost_upd_freq != COST_UPD_OFF) || frame_is_intra_only(cm) || (cm->current_frame.frame_number & 0x07) == 1) - av1_fill_mv_costs(cm->fc, cm->cur_frame_force_integer_mv, - cm->allow_high_precision_mv, x); + av1_fill_mv_costs(cm->fc, cm->features.cur_frame_force_integer_mv, + cm->features.allow_high_precision_mv, x); - if (frame_is_intra_only(cm) && cm->allow_screen_content_tools && - cpi->oxcf.pass != 1) { - int *dvcost[2] = { &cpi->dv_cost[0][MV_MAX], &cpi->dv_cost[1][MV_MAX] }; - av1_build_nmv_cost_table(cpi->dv_joint_cost, dvcost, &cm->fc->ndvc, + if (!cpi->sf.rt_sf.use_nonrd_pick_mode && frame_is_intra_only(cm) && + cm->features.allow_screen_content_tools && + !is_stat_generation_stage(cpi)) { + IntraBCMVCosts *const dv_costs = &cpi->dv_costs; + int *dvcost[2] = { &dv_costs->mv_component[0][MV_MAX], + &dv_costs->mv_component[1][MV_MAX] }; + av1_build_nmv_cost_table(dv_costs->joint_mv, dvcost, &cm->fc->ndvc, MV_SUBPEL_NONE); } - if (cpi->oxcf.pass != 1) { + if (!is_stat_generation_stage(cpi)) { for (int i = 0; i < TRANS_TYPES; ++i) // IDENTITY: 1 bit // TRANSLATION: 3 bits // ROTZOOM: 2 bits // AFFINE: 3 bits - cpi->gmtype_cost[i] = (1 + (i > 0 ? (i == ROTZOOM ? 1 : 2) : 0)) - << AV1_PROB_COST_SHIFT; + cpi->gm_info.type_cost[i] = (1 + (i > 0 ? (i == ROTZOOM ? 1 : 2) : 0)) + << AV1_PROB_COST_SHIFT; } } @@ -980,22 +968,20 @@ static void get_entropy_contexts_plane(BLOCK_SIZE plane_bsize, const struct macroblockd_plane *pd, ENTROPY_CONTEXT t_above[MAX_MIB_SIZE], ENTROPY_CONTEXT t_left[MAX_MIB_SIZE]) { - const int num_4x4_w = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int num_4x4_h = block_size_high[plane_bsize] >> tx_size_high_log2[0]; - const ENTROPY_CONTEXT *const above = pd->above_context; - const ENTROPY_CONTEXT *const left = pd->left_context; + const int num_4x4_w = mi_size_wide[plane_bsize]; + const int num_4x4_h = mi_size_high[plane_bsize]; + const ENTROPY_CONTEXT *const above = pd->above_entropy_context; + const ENTROPY_CONTEXT *const left = pd->left_entropy_context; memcpy(t_above, above, sizeof(ENTROPY_CONTEXT) * num_4x4_w); memcpy(t_left, left, sizeof(ENTROPY_CONTEXT) * num_4x4_h); } -void av1_get_entropy_contexts(BLOCK_SIZE bsize, +void av1_get_entropy_contexts(BLOCK_SIZE plane_bsize, const struct macroblockd_plane *pd, ENTROPY_CONTEXT t_above[MAX_MIB_SIZE], ENTROPY_CONTEXT t_left[MAX_MIB_SIZE]) { - assert(bsize < BLOCK_SIZES_ALL); - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + assert(plane_bsize < BLOCK_SIZES_ALL); get_entropy_contexts_plane(plane_bsize, pd, t_above, t_left); } @@ -1012,7 +998,8 @@ void av1_mv_pred(const AV1_COMP *cpi, MACROBLOCK *x, uint8_t *ref_y_buffer, if (ref_mv.as_int != ref_mv1.as_int) { pred_mv[num_mv_refs++] = ref_mv1.as_mv; } - if (cpi->sf.adaptive_motion_search && block_size < x->max_partition_size) { + if (cpi->sf.mv_sf.adaptive_motion_search && + block_size < x->max_partition_size) { pred_mv[num_mv_refs++] = x->pred_mv[ref_frame]; } @@ -1050,19 +1037,19 @@ void av1_mv_pred(const AV1_COMP *cpi, MACROBLOCK *x, uint8_t *ref_y_buffer, void av1_setup_pred_block(const MACROBLOCKD *xd, struct buf_2d dst[MAX_MB_PLANE], - const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col, + const YV12_BUFFER_CONFIG *src, const struct scale_factors *scale, const struct scale_factors *scale_uv, const int num_planes) { - int i; - dst[0].buf = src->y_buffer; dst[0].stride = src->y_stride; dst[1].buf = src->u_buffer; dst[2].buf = src->v_buffer; dst[1].stride = dst[2].stride = src->uv_stride; - for (i = 0; i < num_planes; ++i) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + for (int i = 0; i < num_planes; ++i) { setup_pred_plane(dst + i, xd->mi[0]->sb_type, dst[i].buf, i ? src->uv_crop_width : src->y_crop_width, i ? src->uv_crop_height : src->y_crop_height, @@ -1081,9 +1068,9 @@ YV12_BUFFER_CONFIG *av1_get_scaled_ref_frame(const AV1_COMP *cpi, : NULL; } -int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x, - const MACROBLOCKD *xd) { - if (cm->interp_filter == SWITCHABLE) { +int av1_get_switchable_rate(const MACROBLOCK *x, const MACROBLOCKD *xd, + InterpFilter interp_filter) { + if (interp_filter == SWITCHABLE) { const MB_MODE_INFO *const mbmi = xd->mi[0]; int inter_filter_cost = 0; int dir; @@ -1101,242 +1088,231 @@ int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x, } void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { - int i; RD_OPT *const rd = &cpi->rd; - SPEED_FEATURES *const sf = &cpi->sf; // Set baseline threshold values. - for (i = 0; i < MAX_MODES; ++i) rd->thresh_mult[i] = cpi->oxcf.mode == 0; + av1_zero(rd->thresh_mult); - if (sf->adaptive_rd_thresh) { - rd->thresh_mult[THR_NEARESTMV] = 300; - rd->thresh_mult[THR_NEARESTL2] = 300; - rd->thresh_mult[THR_NEARESTL3] = 300; - rd->thresh_mult[THR_NEARESTB] = 300; - rd->thresh_mult[THR_NEARESTA2] = 300; - rd->thresh_mult[THR_NEARESTA] = 300; - rd->thresh_mult[THR_NEARESTG] = 300; - } else { - rd->thresh_mult[THR_NEARESTMV] = 0; - rd->thresh_mult[THR_NEARESTL2] = 0; - rd->thresh_mult[THR_NEARESTL3] = 100; - rd->thresh_mult[THR_NEARESTB] = 0; - rd->thresh_mult[THR_NEARESTA2] = 0; - rd->thresh_mult[THR_NEARESTA] = 0; - rd->thresh_mult[THR_NEARESTG] = 0; - } + rd->thresh_mult[THR_NEARESTMV] = 300; + rd->thresh_mult[THR_NEARESTL2] = 300; + rd->thresh_mult[THR_NEARESTL3] = 300; + rd->thresh_mult[THR_NEARESTB] = 300; + rd->thresh_mult[THR_NEARESTA2] = 300; + rd->thresh_mult[THR_NEARESTA] = 300; + rd->thresh_mult[THR_NEARESTG] = 300; - rd->thresh_mult[THR_NEWMV] += 1000; - rd->thresh_mult[THR_NEWL2] += 1000; - rd->thresh_mult[THR_NEWL3] += 1000; - rd->thresh_mult[THR_NEWB] += 1000; + rd->thresh_mult[THR_NEWMV] = 1000; + rd->thresh_mult[THR_NEWL2] = 1000; + rd->thresh_mult[THR_NEWL3] = 1000; + rd->thresh_mult[THR_NEWB] = 1000; rd->thresh_mult[THR_NEWA2] = 1100; - rd->thresh_mult[THR_NEWA] += 1000; - rd->thresh_mult[THR_NEWG] += 1000; + rd->thresh_mult[THR_NEWA] = 1000; + rd->thresh_mult[THR_NEWG] = 1000; - rd->thresh_mult[THR_NEARMV] += 1000; - rd->thresh_mult[THR_NEARL2] += 1000; - rd->thresh_mult[THR_NEARL3] += 1000; - rd->thresh_mult[THR_NEARB] += 1000; + rd->thresh_mult[THR_NEARMV] = 1000; + rd->thresh_mult[THR_NEARL2] = 1000; + rd->thresh_mult[THR_NEARL3] = 1000; + rd->thresh_mult[THR_NEARB] = 1000; rd->thresh_mult[THR_NEARA2] = 1000; - rd->thresh_mult[THR_NEARA] += 1000; - rd->thresh_mult[THR_NEARG] += 1000; + rd->thresh_mult[THR_NEARA] = 1000; + rd->thresh_mult[THR_NEARG] = 1000; - rd->thresh_mult[THR_GLOBALMV] += 2200; - rd->thresh_mult[THR_GLOBALL2] += 2000; - rd->thresh_mult[THR_GLOBALL3] += 2000; - rd->thresh_mult[THR_GLOBALB] += 2400; + rd->thresh_mult[THR_GLOBALMV] = 2200; + rd->thresh_mult[THR_GLOBALL2] = 2000; + rd->thresh_mult[THR_GLOBALL3] = 2000; + rd->thresh_mult[THR_GLOBALB] = 2400; rd->thresh_mult[THR_GLOBALA2] = 2000; - rd->thresh_mult[THR_GLOBALG] += 2000; - rd->thresh_mult[THR_GLOBALA] += 2400; + rd->thresh_mult[THR_GLOBALG] = 2000; + rd->thresh_mult[THR_GLOBALA] = 2400; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLA] += 1100; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2A] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3A] += 800; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTGA] += 900; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLB] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2B] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3B] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTGB] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLA2] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2A2] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3A2] += 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTGA2] += 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLA] = 1100; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2A] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3A] = 800; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTGA] = 900; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLB] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2B] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3B] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTGB] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLA2] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2A2] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTL3A2] = 1000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTGA2] = 1000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLL2] += 2000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLL3] += 2000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTLG] += 2000; - rd->thresh_mult[THR_COMP_NEAREST_NEARESTBA] += 2000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLL2] = 2000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLL3] = 2000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLG] = 2000; + rd->thresh_mult[THR_COMP_NEAREST_NEARESTBA] = 2000; - rd->thresh_mult[THR_COMP_NEAR_NEARLA] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWLA] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTLA] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWLA] += 1530; - rd->thresh_mult[THR_COMP_NEW_NEARLA] += 1870; - rd->thresh_mult[THR_COMP_NEW_NEWLA] += 2400; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLA] += 2750; + rd->thresh_mult[THR_COMP_NEAR_NEARLA] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWLA] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTLA] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWLA] = 1530; + rd->thresh_mult[THR_COMP_NEW_NEARLA] = 1870; + rd->thresh_mult[THR_COMP_NEW_NEWLA] = 2400; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLA] = 2750; - rd->thresh_mult[THR_COMP_NEAR_NEARL2A] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWL2A] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL2A] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL2A] += 1870; - rd->thresh_mult[THR_COMP_NEW_NEARL2A] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL2A] += 1800; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2A] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARL2A] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWL2A] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL2A] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL2A] = 1870; + rd->thresh_mult[THR_COMP_NEW_NEARL2A] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL2A] = 1800; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2A] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARL3A] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWL3A] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL3A] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL3A] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARL3A] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL3A] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3A] += 3000; + rd->thresh_mult[THR_COMP_NEAR_NEARL3A] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWL3A] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL3A] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL3A] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARL3A] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL3A] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3A] = 3000; - rd->thresh_mult[THR_COMP_NEAR_NEARGA] += 1320; - rd->thresh_mult[THR_COMP_NEAREST_NEWGA] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTGA] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWGA] += 2040; - rd->thresh_mult[THR_COMP_NEW_NEARGA] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWGA] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGA] += 2250; + rd->thresh_mult[THR_COMP_NEAR_NEARGA] = 1320; + rd->thresh_mult[THR_COMP_NEAREST_NEWGA] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTGA] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWGA] = 2040; + rd->thresh_mult[THR_COMP_NEW_NEARGA] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWGA] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGA] = 2250; - rd->thresh_mult[THR_COMP_NEAR_NEARLB] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWLB] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTLB] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWLB] += 1360; - rd->thresh_mult[THR_COMP_NEW_NEARLB] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWLB] += 2400; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLB] += 2250; + rd->thresh_mult[THR_COMP_NEAR_NEARLB] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWLB] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTLB] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWLB] = 1360; + rd->thresh_mult[THR_COMP_NEW_NEARLB] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWLB] = 2400; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLB] = 2250; - rd->thresh_mult[THR_COMP_NEAR_NEARL2B] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWL2B] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL2B] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL2B] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARL2B] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL2B] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2B] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARL2B] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWL2B] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL2B] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL2B] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARL2B] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL2B] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2B] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARL3B] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWL3B] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL3B] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL3B] += 1870; - rd->thresh_mult[THR_COMP_NEW_NEARL3B] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL3B] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3B] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARL3B] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWL3B] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL3B] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL3B] = 1870; + rd->thresh_mult[THR_COMP_NEW_NEARL3B] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL3B] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3B] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARGB] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWGB] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTGB] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWGB] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARGB] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWGB] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGB] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARGB] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWGB] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTGB] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWGB] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARGB] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWGB] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGB] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARLA2] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWLA2] += 1800; - rd->thresh_mult[THR_COMP_NEW_NEARESTLA2] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWLA2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARLA2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWLA2] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLA2] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARLA2] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWLA2] = 1800; + rd->thresh_mult[THR_COMP_NEW_NEARESTLA2] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWLA2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARLA2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWLA2] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLA2] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARL2A2] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWL2A2] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL2A2] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL2A2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARL2A2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL2A2] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2A2] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARL2A2] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWL2A2] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL2A2] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL2A2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARL2A2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL2A2] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL2A2] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARL3A2] += 1440; - rd->thresh_mult[THR_COMP_NEAREST_NEWL3A2] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTL3A2] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWL3A2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARL3A2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWL3A2] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3A2] += 2500; + rd->thresh_mult[THR_COMP_NEAR_NEARL3A2] = 1440; + rd->thresh_mult[THR_COMP_NEAREST_NEWL3A2] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTL3A2] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWL3A2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARL3A2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWL3A2] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALL3A2] = 2500; - rd->thresh_mult[THR_COMP_NEAR_NEARGA2] += 1200; - rd->thresh_mult[THR_COMP_NEAREST_NEWGA2] += 1500; - rd->thresh_mult[THR_COMP_NEW_NEARESTGA2] += 1500; - rd->thresh_mult[THR_COMP_NEAR_NEWGA2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEARGA2] += 1700; - rd->thresh_mult[THR_COMP_NEW_NEWGA2] += 2000; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGA2] += 2750; + rd->thresh_mult[THR_COMP_NEAR_NEARGA2] = 1200; + rd->thresh_mult[THR_COMP_NEAREST_NEWGA2] = 1500; + rd->thresh_mult[THR_COMP_NEW_NEARESTGA2] = 1500; + rd->thresh_mult[THR_COMP_NEAR_NEWGA2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEARGA2] = 1700; + rd->thresh_mult[THR_COMP_NEW_NEWGA2] = 2000; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALGA2] = 2750; - rd->thresh_mult[THR_COMP_NEAR_NEARLL2] += 1600; - rd->thresh_mult[THR_COMP_NEAREST_NEWLL2] += 2000; - rd->thresh_mult[THR_COMP_NEW_NEARESTLL2] += 2000; - rd->thresh_mult[THR_COMP_NEAR_NEWLL2] += 2640; - rd->thresh_mult[THR_COMP_NEW_NEARLL2] += 2200; - rd->thresh_mult[THR_COMP_NEW_NEWLL2] += 2400; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLL2] += 3200; + rd->thresh_mult[THR_COMP_NEAR_NEARLL2] = 1600; + rd->thresh_mult[THR_COMP_NEAREST_NEWLL2] = 2000; + rd->thresh_mult[THR_COMP_NEW_NEARESTLL2] = 2000; + rd->thresh_mult[THR_COMP_NEAR_NEWLL2] = 2640; + rd->thresh_mult[THR_COMP_NEW_NEARLL2] = 2200; + rd->thresh_mult[THR_COMP_NEW_NEWLL2] = 2400; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLL2] = 3200; - rd->thresh_mult[THR_COMP_NEAR_NEARLL3] += 1600; - rd->thresh_mult[THR_COMP_NEAREST_NEWLL3] += 2000; - rd->thresh_mult[THR_COMP_NEW_NEARESTLL3] += 1800; - rd->thresh_mult[THR_COMP_NEAR_NEWLL3] += 2200; - rd->thresh_mult[THR_COMP_NEW_NEARLL3] += 2200; - rd->thresh_mult[THR_COMP_NEW_NEWLL3] += 2400; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLL3] += 3200; + rd->thresh_mult[THR_COMP_NEAR_NEARLL3] = 1600; + rd->thresh_mult[THR_COMP_NEAREST_NEWLL3] = 2000; + rd->thresh_mult[THR_COMP_NEW_NEARESTLL3] = 1800; + rd->thresh_mult[THR_COMP_NEAR_NEWLL3] = 2200; + rd->thresh_mult[THR_COMP_NEW_NEARLL3] = 2200; + rd->thresh_mult[THR_COMP_NEW_NEWLL3] = 2400; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLL3] = 3200; - rd->thresh_mult[THR_COMP_NEAR_NEARLG] += 1760; - rd->thresh_mult[THR_COMP_NEAREST_NEWLG] += 2400; - rd->thresh_mult[THR_COMP_NEW_NEARESTLG] += 2000; - rd->thresh_mult[THR_COMP_NEAR_NEWLG] += 1760; - rd->thresh_mult[THR_COMP_NEW_NEARLG] += 2640; - rd->thresh_mult[THR_COMP_NEW_NEWLG] += 2400; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLG] += 3200; + rd->thresh_mult[THR_COMP_NEAR_NEARLG] = 1760; + rd->thresh_mult[THR_COMP_NEAREST_NEWLG] = 2400; + rd->thresh_mult[THR_COMP_NEW_NEARESTLG] = 2000; + rd->thresh_mult[THR_COMP_NEAR_NEWLG] = 1760; + rd->thresh_mult[THR_COMP_NEW_NEARLG] = 2640; + rd->thresh_mult[THR_COMP_NEW_NEWLG] = 2400; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALLG] = 3200; - rd->thresh_mult[THR_COMP_NEAR_NEARBA] += 1600; - rd->thresh_mult[THR_COMP_NEAREST_NEWBA] += 2000; - rd->thresh_mult[THR_COMP_NEW_NEARESTBA] += 2000; - rd->thresh_mult[THR_COMP_NEAR_NEWBA] += 2200; - rd->thresh_mult[THR_COMP_NEW_NEARBA] += 1980; - rd->thresh_mult[THR_COMP_NEW_NEWBA] += 2640; - rd->thresh_mult[THR_COMP_GLOBAL_GLOBALBA] += 3200; + rd->thresh_mult[THR_COMP_NEAR_NEARBA] = 1600; + rd->thresh_mult[THR_COMP_NEAREST_NEWBA] = 2000; + rd->thresh_mult[THR_COMP_NEW_NEARESTBA] = 2000; + rd->thresh_mult[THR_COMP_NEAR_NEWBA] = 2200; + rd->thresh_mult[THR_COMP_NEW_NEARBA] = 1980; + rd->thresh_mult[THR_COMP_NEW_NEWBA] = 2640; + rd->thresh_mult[THR_COMP_GLOBAL_GLOBALBA] = 3200; - rd->thresh_mult[THR_DC] += 1000; - rd->thresh_mult[THR_PAETH] += 1000; - rd->thresh_mult[THR_SMOOTH] += 2200; - rd->thresh_mult[THR_SMOOTH_V] += 2000; - rd->thresh_mult[THR_SMOOTH_H] += 2000; - rd->thresh_mult[THR_H_PRED] += 2000; - rd->thresh_mult[THR_V_PRED] += 1800; - rd->thresh_mult[THR_D135_PRED] += 2500; - rd->thresh_mult[THR_D203_PRED] += 2000; - rd->thresh_mult[THR_D157_PRED] += 2500; - rd->thresh_mult[THR_D67_PRED] += 2000; - rd->thresh_mult[THR_D113_PRED] += 2500; - rd->thresh_mult[THR_D45_PRED] += 2500; + rd->thresh_mult[THR_DC] = 1000; + rd->thresh_mult[THR_PAETH] = 1000; + rd->thresh_mult[THR_SMOOTH] = 2200; + rd->thresh_mult[THR_SMOOTH_V] = 2000; + rd->thresh_mult[THR_SMOOTH_H] = 2000; + rd->thresh_mult[THR_H_PRED] = 2000; + rd->thresh_mult[THR_V_PRED] = 1800; + rd->thresh_mult[THR_D135_PRED] = 2500; + rd->thresh_mult[THR_D203_PRED] = 2000; + rd->thresh_mult[THR_D157_PRED] = 2500; + rd->thresh_mult[THR_D67_PRED] = 2000; + rd->thresh_mult[THR_D113_PRED] = 2500; + rd->thresh_mult[THR_D45_PRED] = 2500; } void av1_update_rd_thresh_fact(const AV1_COMMON *const cm, - int (*factor_buf)[MAX_MODES], int rd_thresh, - int bsize, int best_mode_index) { - if (rd_thresh > 0) { - const int top_mode = MAX_MODES; - int mode; - BLOCK_SIZE min_size; - BLOCK_SIZE max_size; - if (bsize <= cm->seq_params.sb_size) { - min_size = AOMMAX(bsize - 1, BLOCK_4X4); - max_size = AOMMIN(bsize + 2, (int)cm->seq_params.sb_size); - } else { - // This part handles block sizes with 1:4 and 4:1 aspect ratios - // TODO(any): Experiment with threshold update for parent/child blocks - min_size = bsize; - max_size = bsize; - } - for (mode = 0; mode < top_mode; ++mode) { - BLOCK_SIZE bs; - for (bs = min_size; bs <= max_size; ++bs) { - int *const fact = &factor_buf[bs][mode]; - if (mode == best_mode_index) { - *fact -= (*fact >> 4); - } else { - *fact = AOMMIN(*fact + RD_THRESH_INC, rd_thresh * RD_THRESH_MAX_FACT); - } + int (*factor_buf)[MAX_MODES], + int use_adaptive_rd_thresh, BLOCK_SIZE bsize, + THR_MODES best_mode_index) { + assert(use_adaptive_rd_thresh > 0); + const THR_MODES top_mode = MAX_MODES; + const int max_rd_thresh_factor = use_adaptive_rd_thresh * RD_THRESH_MAX_FACT; + + const int bsize_is_1_to_4 = bsize > cm->seq_params.sb_size; + BLOCK_SIZE min_size, max_size; + if (bsize_is_1_to_4) { + // This part handles block sizes with 1:4 and 4:1 aspect ratios + // TODO(any): Experiment with threshold update for parent/child blocks + min_size = bsize; + max_size = bsize; + } else { + min_size = AOMMAX(bsize - 2, BLOCK_4X4); + max_size = AOMMIN(bsize + 2, (int)cm->seq_params.sb_size); + } + + for (THR_MODES mode = 0; mode < top_mode; ++mode) { + for (BLOCK_SIZE bs = min_size; bs <= max_size; ++bs) { + int *const fact = &factor_buf[bs][mode]; + if (mode == best_mode_index) { + *fact -= (*fact >> RD_THRESH_LOG_DEC_FACTOR); + } else { + *fact = AOMMIN(*fact + RD_THRESH_INC, max_rd_thresh_factor); } } } diff --git a/media/libaom/src/av1/encoder/rd.h b/media/libaom/src/av1/encoder/rd.h index eaae19ea72..1addbaeb96 100644 --- a/media/libaom/src/av1/encoder/rd.h +++ b/media/libaom/src/av1/encoder/rd.h @@ -44,16 +44,22 @@ extern "C" { #define MV_COST_WEIGHT 108 #define MV_COST_WEIGHT_SUB 120 -#define RD_THRESH_MAX_FACT 64 -#define RD_THRESH_INC 1 +// The fractional part of rd_thresh factor is stored with 5 bits. The maximum +// factor that we allow is two, which is stored as 2 ** (5+1) = 64 +#define RD_THRESH_FAC_FRAC_BITS (5) +#define RD_THRESH_FAC_FRAC_VAL (1 << (RD_THRESH_FAC_FRAC_BITS)) +#define RD_THRESH_MAX_FACT ((RD_THRESH_FAC_FRAC_VAL) << 1) +#define RD_THRESH_LOG_DEC_FACTOR (4) +#define RD_THRESH_INC (1) // Factor to weigh the rate for switchable interp filters. #define SWITCHABLE_INTERP_RATE_FACTOR 1 enum { - // Default initialization + // Default initialization when we are not using winner mode framework. e.g. + // intrabc DEFAULT_EVAL = 0, - // Initialization for default mode evaluation + // Initialization for selecting winner mode MODE_EVAL, // Initialization for winner mode evaluation WINNER_MODE_EVAL, @@ -73,11 +79,23 @@ typedef struct RD_OPT { int RDMULT; double r0, arf_r0; -#if !USE_TPL_CLASSIC_MODEL double mc_saved_base, mc_count_base; -#endif // !USE_TPL_CLASSIC_MODEL } RD_OPT; +typedef struct { + // Cost of transmitting the actual motion vector. + // mv_component[0][i] is the cost of motion vector with horizontal component + // (mv_row) equal to i - MV_MAX. + // mv_component[1][i] is the cost of motion vector with vertical component + // (mv_col) equal to i - MV_MAX. + int mv_component[2][MV_VALS]; + + // joint_mv[i] is the cost of transmitting joint mv(MV_JOINT_TYPE) of + // type i. + // TODO(huisu@google.com): we can update dv_joint_cost per SB. + int joint_mv[MV_JOINTS]; +} IntraBCMVCosts; + static INLINE void av1_init_rd_stats(RD_STATS *rd_stats) { #if CONFIG_RD_DEBUG int plane; @@ -224,8 +242,8 @@ void av1_model_rd_curvfit(BLOCK_SIZE bsize, double sse_norm, double xqr, void av1_model_rd_surffit(BLOCK_SIZE bsize, double sse_norm, double xm, double yl, double *rate_f, double *distbysse_f); -int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x, - const MACROBLOCKD *xd); +int av1_get_switchable_rate(const MACROBLOCK *x, const MACROBLOCKD *xd, + InterpFilter interp_filter); YV12_BUFFER_CONFIG *av1_get_scaled_ref_frame(const struct AV1_COMP *cpi, int ref_frame); @@ -234,7 +252,7 @@ void av1_init_me_luts(void); void av1_set_mvcost(MACROBLOCK *x, int ref, int ref_mv_idx); -void av1_get_entropy_contexts(BLOCK_SIZE bsize, +void av1_get_entropy_contexts(BLOCK_SIZE plane_bsize, const struct macroblockd_plane *pd, ENTROPY_CONTEXT t_above[MAX_MIB_SIZE], ENTROPY_CONTEXT t_left[MAX_MIB_SIZE]); @@ -242,8 +260,16 @@ void av1_get_entropy_contexts(BLOCK_SIZE bsize, void av1_set_rd_speed_thresholds(struct AV1_COMP *cpi); void av1_update_rd_thresh_fact(const AV1_COMMON *const cm, - int (*fact)[MAX_MODES], int rd_thresh, int bsize, - int best_mode_index); + int (*fact)[MAX_MODES], int rd_thresh, + BLOCK_SIZE bsize, THR_MODES best_mode_index); + +static INLINE void reset_thresh_freq_fact(MACROBLOCK *const x) { + for (int i = 0; i < BLOCK_SIZES_ALL; ++i) { + for (int j = 0; j < MAX_MODES; ++j) { + x->thresh_freq_fact[i][j] = RD_THRESH_FAC_FRAC_VAL; + } + } +} static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh, int thresh_fact) { @@ -282,9 +308,41 @@ static INLINE uint32_t get_rd_opt_coeff_thresh( return coeff_opt_thresh; } +// Used to reset the state of tx/mb rd hash information +static INLINE void reset_hash_records(MACROBLOCK *const x, + int use_inter_txb_hash) { + int32_t record_idx; + + // Reset the state for use_inter_txb_hash + if (use_inter_txb_hash) { + for (record_idx = 0; + record_idx < ((MAX_MIB_SIZE >> 1) * (MAX_MIB_SIZE >> 1)); record_idx++) + x->txb_rd_record_8X8[record_idx].num = + x->txb_rd_record_8X8[record_idx].index_start = 0; + for (record_idx = 0; + record_idx < ((MAX_MIB_SIZE >> 2) * (MAX_MIB_SIZE >> 2)); record_idx++) + x->txb_rd_record_16X16[record_idx].num = + x->txb_rd_record_16X16[record_idx].index_start = 0; + for (record_idx = 0; + record_idx < ((MAX_MIB_SIZE >> 3) * (MAX_MIB_SIZE >> 3)); record_idx++) + x->txb_rd_record_32X32[record_idx].num = + x->txb_rd_record_32X32[record_idx].index_start = 0; + for (record_idx = 0; + record_idx < ((MAX_MIB_SIZE >> 4) * (MAX_MIB_SIZE >> 4)); record_idx++) + x->txb_rd_record_64X64[record_idx].num = + x->txb_rd_record_64X64[record_idx].index_start = 0; + } + + // Reset the state for use_intra_txb_hash + x->txb_rd_record_intra.num = x->txb_rd_record_intra.index_start = 0; + + // Reset the state for use_mb_rd_hash + x->mb_rd_record.num = x->mb_rd_record.index_start = 0; +} + void av1_setup_pred_block(const MACROBLOCKD *xd, struct buf_2d dst[MAX_MB_PLANE], - const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col, + const YV12_BUFFER_CONFIG *src, const struct scale_factors *scale, const struct scale_factors *scale_uv, const int num_planes); diff --git a/media/libaom/src/av1/encoder/rdopt.c b/media/libaom/src/av1/encoder/rdopt.c index 8c456a4095..02afcd1ff0 100644 --- a/media/libaom/src/av1/encoder/rdopt.c +++ b/media/libaom/src/av1/encoder/rdopt.c @@ -13,6 +13,7 @@ #include #include +#include "config/aom_config.h" #include "config/aom_dsp_rtcd.h" #include "config/av1_rtcd.h" @@ -23,6 +24,7 @@ #include "aom_ports/mem.h" #include "aom_ports/system_state.h" +#include "av1/common/av1_common_int.h" #include "av1/common/cfl.h" #include "av1/common/common.h" #include "av1/common/common_data.h" @@ -31,7 +33,6 @@ #include "av1/common/idct.h" #include "av1/common/mvref_common.h" #include "av1/common/obmc.h" -#include "av1/common/onyxc_int.h" #include "av1/common/pred_common.h" #include "av1/common/quant_common.h" #include "av1/common/reconinter.h" @@ -44,14 +45,19 @@ #include "av1/encoder/aq_variance.h" #include "av1/encoder/av1_quantize.h" #include "av1/encoder/cost.h" +#include "av1/encoder/compound_type.h" #include "av1/encoder/encodemb.h" #include "av1/encoder/encodemv.h" #include "av1/encoder/encoder.h" #include "av1/encoder/encodetxb.h" #include "av1/encoder/hybrid_fwd_txfm.h" +#include "av1/encoder/interp_search.h" +#include "av1/encoder/intra_mode_search.h" #include "av1/encoder/mcomp.h" #include "av1/encoder/ml.h" #include "av1/encoder/mode_prune_model_weights.h" +#include "av1/encoder/model_rd.h" +#include "av1/encoder/motion_search_facade.h" #include "av1/encoder/palette.h" #include "av1/encoder/pustats.h" #include "av1/encoder/random.h" @@ -61,343 +67,39 @@ #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/tokenize.h" #include "av1/encoder/tpl_model.h" -#include "av1/encoder/tx_prune_model_weights.h" - -// Set this macro as 1 to collect data about tx size selection. -#define COLLECT_TX_SIZE_DATA 0 - -#if COLLECT_TX_SIZE_DATA -static const char av1_tx_size_data_output_file[] = "tx_size_data.txt"; -#endif - -typedef void (*model_rd_for_sb_type)( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -typedef void (*model_rd_from_sse_type)(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, int *rate, - int64_t *dist); - -static AOM_INLINE void model_rd_for_sb( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -static AOM_INLINE void model_rd_for_sb_with_curvfit( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -static AOM_INLINE void model_rd_for_sb_with_surffit( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -static AOM_INLINE void model_rd_for_sb_with_dnn( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -static AOM_INLINE void model_rd_for_sb_with_fullrdy( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist); -static AOM_INLINE void model_rd_from_sse(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist); -static AOM_INLINE void model_rd_with_dnn(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist); -static AOM_INLINE void model_rd_with_curvfit(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist); -static AOM_INLINE void model_rd_with_surffit(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist); - -enum { - MODELRD_LEGACY, - MODELRD_CURVFIT, - MODELRD_SUFFIT, - MODELRD_DNN, - MODELRD_FULLRDY, - MODELRD_TYPES -} UENUM1BYTE(ModelRdType); - -static model_rd_for_sb_type model_rd_sb_fn[MODELRD_TYPES] = { - model_rd_for_sb, model_rd_for_sb_with_curvfit, model_rd_for_sb_with_surffit, - model_rd_for_sb_with_dnn, model_rd_for_sb_with_fullrdy -}; - -static model_rd_from_sse_type model_rd_sse_fn[MODELRD_TYPES] = { - model_rd_from_sse, model_rd_with_curvfit, model_rd_with_surffit, - model_rd_with_dnn, NULL -}; - -// 0: Legacy model -// 1: Curve fit model -// 2: Surface fit model -// 3: DNN regression model -// 4: Full rd model -#define MODELRD_TYPE_INTERP_FILTER 1 -#define MODELRD_TYPE_TX_SEARCH_PRUNE 1 -#define MODELRD_TYPE_MASKED_COMPOUND 1 -#define MODELRD_TYPE_INTERINTRA 1 -#define MODELRD_TYPE_INTRA 1 -#define MODELRD_TYPE_DIST_WTD_COMPOUND 1 -#define MODELRD_TYPE_MOTION_MODE_RD 1 - -#define DUAL_FILTER_SET_SIZE (SWITCHABLE_FILTERS * SWITCHABLE_FILTERS) -static const int_interpfilters filter_sets[DUAL_FILTER_SET_SIZE] = { - { 0x00000000 }, { 0x00010000 }, { 0x00020000 }, // y = 0 - { 0x00000001 }, { 0x00010001 }, { 0x00020001 }, // y = 1 - { 0x00000002 }, { 0x00010002 }, { 0x00020002 }, // y = 2 -}; - -typedef struct { - PREDICTION_MODE mode; - MV_REFERENCE_FRAME ref_frame[2]; -} MODE_DEFINITION; - -enum { - FTXS_NONE = 0, - FTXS_DCT_AND_1D_DCT_ONLY = 1 << 0, - FTXS_DISABLE_TRELLIS_OPT = 1 << 1, - FTXS_USE_TRANSFORM_DOMAIN = 1 << 2 -} UENUM1BYTE(FAST_TX_SEARCH_MODE); - -struct rdcost_block_args { - const AV1_COMP *cpi; - MACROBLOCK *x; - ENTROPY_CONTEXT t_above[MAX_MIB_SIZE]; - ENTROPY_CONTEXT t_left[MAX_MIB_SIZE]; - RD_STATS rd_stats; - int64_t this_rd; - int64_t best_rd; - int exit_early; - int incomplete_exit; - int use_fast_coef_costing; - FAST_TX_SEARCH_MODE ftxs_mode; - int skip_trellis; -}; - -// Structure to store the compound type related stats for best compound type -typedef struct { - INTERINTER_COMPOUND_DATA best_compound_data; - int64_t comp_best_model_rd; - int best_compmode_interinter_cost; -} BEST_COMP_TYPE_STATS; +#include "av1/encoder/tx_search.h" #define LAST_NEW_MV_INDEX 6 -// This array defines the mapping from the enums in THR_MODES to the actual -// prediction modes and refrence frames -static const MODE_DEFINITION av1_mode_defs[MAX_MODES] = { - { NEARESTMV, { LAST_FRAME, NONE_FRAME } }, - { NEARESTMV, { LAST2_FRAME, NONE_FRAME } }, - { NEARESTMV, { LAST3_FRAME, NONE_FRAME } }, - { NEARESTMV, { BWDREF_FRAME, NONE_FRAME } }, - { NEARESTMV, { ALTREF2_FRAME, NONE_FRAME } }, - { NEARESTMV, { ALTREF_FRAME, NONE_FRAME } }, - { NEARESTMV, { GOLDEN_FRAME, NONE_FRAME } }, - { NEWMV, { LAST_FRAME, NONE_FRAME } }, - { NEWMV, { LAST2_FRAME, NONE_FRAME } }, - { NEWMV, { LAST3_FRAME, NONE_FRAME } }, - { NEWMV, { BWDREF_FRAME, NONE_FRAME } }, - { NEWMV, { ALTREF2_FRAME, NONE_FRAME } }, - { NEWMV, { ALTREF_FRAME, NONE_FRAME } }, - { NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, - - { NEARMV, { LAST_FRAME, NONE_FRAME } }, - { NEARMV, { LAST2_FRAME, NONE_FRAME } }, - { NEARMV, { LAST3_FRAME, NONE_FRAME } }, - { NEARMV, { BWDREF_FRAME, NONE_FRAME } }, - { NEARMV, { ALTREF2_FRAME, NONE_FRAME } }, - { NEARMV, { ALTREF_FRAME, NONE_FRAME } }, - { NEARMV, { GOLDEN_FRAME, NONE_FRAME } }, - - { GLOBALMV, { LAST_FRAME, NONE_FRAME } }, - { GLOBALMV, { LAST2_FRAME, NONE_FRAME } }, - { GLOBALMV, { LAST3_FRAME, NONE_FRAME } }, - { GLOBALMV, { BWDREF_FRAME, NONE_FRAME } }, - { GLOBALMV, { ALTREF2_FRAME, NONE_FRAME } }, - { GLOBALMV, { ALTREF_FRAME, NONE_FRAME } }, - { GLOBALMV, { GOLDEN_FRAME, NONE_FRAME } }, - - // TODO(zoeliu): May need to reconsider the order on the modes to check - - { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - - { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, - { NEAREST_NEARESTMV, { LAST_FRAME, LAST3_FRAME } }, - { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF_FRAME } }, - - { NEAR_NEARMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEW_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEAREST_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEW_NEARMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEAR_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, - { NEW_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF_FRAME } }, - - { NEAR_NEARMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEW_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEAREST_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEW_NEARMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEAR_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, - { NEW_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF_FRAME } }, - - { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEW_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { NEW_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, BWDREF_FRAME } }, - - { NEAR_NEARMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEW_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEAREST_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEW_NEARMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEAR_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, - { NEW_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST2_FRAME, BWDREF_FRAME } }, - - { NEAR_NEARMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEW_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEAREST_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEW_NEARMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEAR_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, - { NEW_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, - { GLOBAL_GLOBALMV, { LAST3_FRAME, BWDREF_FRAME } }, - - { NEAR_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEW_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEAREST_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEW_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - { GLOBAL_GLOBALMV, { GOLDEN_FRAME, BWDREF_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF2_FRAME } }, - - { NEAR_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEW_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEW_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEAR_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { NEW_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, - { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF2_FRAME } }, - - { NEAR_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEW_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEW_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEAR_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { NEW_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, - { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF2_FRAME } }, - - { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { NEW_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { NEW_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, LAST2_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, LAST3_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, LAST3_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, LAST3_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, LAST3_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, LAST3_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, LAST3_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, LAST3_FRAME } }, - - { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, - { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, - { GLOBAL_GLOBALMV, { LAST_FRAME, GOLDEN_FRAME } }, - - { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, - { GLOBAL_GLOBALMV, { BWDREF_FRAME, ALTREF_FRAME } }, - - // intra modes - { DC_PRED, { INTRA_FRAME, NONE_FRAME } }, - { PAETH_PRED, { INTRA_FRAME, NONE_FRAME } }, - { SMOOTH_PRED, { INTRA_FRAME, NONE_FRAME } }, - { SMOOTH_V_PRED, { INTRA_FRAME, NONE_FRAME } }, - { SMOOTH_H_PRED, { INTRA_FRAME, NONE_FRAME } }, - { H_PRED, { INTRA_FRAME, NONE_FRAME } }, - { V_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D135_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D203_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D157_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D67_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D113_PRED, { INTRA_FRAME, NONE_FRAME } }, - { D45_PRED, { INTRA_FRAME, NONE_FRAME } }, +// Mode_threshold multiplication factor table for prune_inter_modes_if_skippable +// The values are kept in Q12 format and equation used to derive is +// (2.5 - ((float)x->qindex / MAXQ) * 1.5) +#define MODE_THRESH_QBITS 12 +static const int mode_threshold_mul_factor[QINDEX_RANGE] = { + 10240, 10216, 10192, 10168, 10144, 10120, 10095, 10071, 10047, 10023, 9999, + 9975, 9951, 9927, 9903, 9879, 9854, 9830, 9806, 9782, 9758, 9734, + 9710, 9686, 9662, 9638, 9614, 9589, 9565, 9541, 9517, 9493, 9469, + 9445, 9421, 9397, 9373, 9349, 9324, 9300, 9276, 9252, 9228, 9204, + 9180, 9156, 9132, 9108, 9083, 9059, 9035, 9011, 8987, 8963, 8939, + 8915, 8891, 8867, 8843, 8818, 8794, 8770, 8746, 8722, 8698, 8674, + 8650, 8626, 8602, 8578, 8553, 8529, 8505, 8481, 8457, 8433, 8409, + 8385, 8361, 8337, 8312, 8288, 8264, 8240, 8216, 8192, 8168, 8144, + 8120, 8096, 8072, 8047, 8023, 7999, 7975, 7951, 7927, 7903, 7879, + 7855, 7831, 7806, 7782, 7758, 7734, 7710, 7686, 7662, 7638, 7614, + 7590, 7566, 7541, 7517, 7493, 7469, 7445, 7421, 7397, 7373, 7349, + 7325, 7301, 7276, 7252, 7228, 7204, 7180, 7156, 7132, 7108, 7084, + 7060, 7035, 7011, 6987, 6963, 6939, 6915, 6891, 6867, 6843, 6819, + 6795, 6770, 6746, 6722, 6698, 6674, 6650, 6626, 6602, 6578, 6554, + 6530, 6505, 6481, 6457, 6433, 6409, 6385, 6361, 6337, 6313, 6289, + 6264, 6240, 6216, 6192, 6168, 6144, 6120, 6096, 6072, 6048, 6024, + 5999, 5975, 5951, 5927, 5903, 5879, 5855, 5831, 5807, 5783, 5758, + 5734, 5710, 5686, 5662, 5638, 5614, 5590, 5566, 5542, 5518, 5493, + 5469, 5445, 5421, 5397, 5373, 5349, 5325, 5301, 5277, 5253, 5228, + 5204, 5180, 5156, 5132, 5108, 5084, 5060, 5036, 5012, 4987, 4963, + 4939, 4915, 4891, 4867, 4843, 4819, 4795, 4771, 4747, 4722, 4698, + 4674, 4650, 4626, 4602, 4578, 4554, 4530, 4506, 4482, 4457, 4433, + 4409, 4385, 4361, 4337, 4313, 4289, 4265, 4241, 4216, 4192, 4168, + 4144, 4120, 4096 }; static const THR_MODES av1_default_mode_order[MAX_MODES] = { @@ -610,328 +312,6 @@ static int find_last_single_ref_mode_idx(const THR_MODES *mode_order) { return -1; } -static const THR_MODES intra_to_mode_idx[INTRA_MODE_NUM] = { - THR_DC, // DC_PRED, - THR_V_PRED, // V_PRED, - THR_H_PRED, // H_PRED, - THR_D45_PRED, // D45_PRED, - THR_D135_PRED, // D135_PRED, - THR_D113_PRED, // D113_PRED, - THR_D157_PRED, // D157_PRED, - THR_D203_PRED, // D203_PRED, - THR_D67_PRED, // D67_PRED, - THR_SMOOTH, // SMOOTH_PRED, - THR_SMOOTH_V, // SMOOTH_V_PRED, - THR_SMOOTH_H, // SMOOTH_H_PRED, - THR_PAETH, // PAETH_PRED, -}; - -/* clang-format off */ -static const THR_MODES single_inter_to_mode_idx[SINGLE_INTER_MODE_NUM] - [REF_FRAMES] = { - // NEARESTMV, - { THR_INVALID, THR_NEARESTMV, THR_NEARESTL2, THR_NEARESTL3, - THR_NEARESTG, THR_NEARESTB, THR_NEARESTA2, THR_NEARESTA, }, - // NEARMV, - { THR_INVALID, THR_NEARMV, THR_NEARL2, THR_NEARL3, - THR_NEARG, THR_NEARB, THR_NEARA2, THR_NEARA, }, - // GLOBALMV, - { THR_INVALID, THR_GLOBALMV, THR_GLOBALL2, THR_GLOBALL3, - THR_GLOBALG, THR_GLOBALB, THR_GLOBALA2, THR_GLOBALA, }, - // NEWMV, - { THR_INVALID, THR_NEWMV, THR_NEWL2, THR_NEWL3, - THR_NEWG, THR_NEWB, THR_NEWA2, THR_NEWA, }, -}; -/* clang-format on */ - -/* clang-format off */ -static const THR_MODES comp_inter_to_mode_idx[COMP_INTER_MODE_NUM][REF_FRAMES] - [REF_FRAMES] = { - // NEAREST_NEARESTMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEAREST_NEARESTLL2, THR_COMP_NEAREST_NEARESTLL3, - THR_COMP_NEAREST_NEARESTLG, THR_COMP_NEAREST_NEARESTLB, - THR_COMP_NEAREST_NEARESTLA2, THR_COMP_NEAREST_NEARESTLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEARESTL2B, - THR_COMP_NEAREST_NEARESTL2A2, THR_COMP_NEAREST_NEARESTL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEARESTL3B, - THR_COMP_NEAREST_NEARESTL3A2, THR_COMP_NEAREST_NEARESTL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEARESTGB, - THR_COMP_NEAREST_NEARESTGA2, THR_COMP_NEAREST_NEARESTGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEARESTBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEAR_NEARMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEAR_NEARLL2, THR_COMP_NEAR_NEARLL3, - THR_COMP_NEAR_NEARLG, THR_COMP_NEAR_NEARLB, - THR_COMP_NEAR_NEARLA2, THR_COMP_NEAR_NEARLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEARL2B, - THR_COMP_NEAR_NEARL2A2, THR_COMP_NEAR_NEARL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEARL3B, - THR_COMP_NEAR_NEARL3A2, THR_COMP_NEAR_NEARL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEARGB, - THR_COMP_NEAR_NEARGA2, THR_COMP_NEAR_NEARGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEARBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEAREST_NEWMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEAREST_NEWLL2, THR_COMP_NEAREST_NEWLL3, - THR_COMP_NEAREST_NEWLG, THR_COMP_NEAREST_NEWLB, - THR_COMP_NEAREST_NEWLA2, THR_COMP_NEAREST_NEWLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEWL2B, - THR_COMP_NEAREST_NEWL2A2, THR_COMP_NEAREST_NEWL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEWL3B, - THR_COMP_NEAREST_NEWL3A2, THR_COMP_NEAREST_NEWL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEWGB, - THR_COMP_NEAREST_NEWGA2, THR_COMP_NEAREST_NEWGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAREST_NEWBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEW_NEARESTMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEW_NEARESTLL2, THR_COMP_NEW_NEARESTLL3, - THR_COMP_NEW_NEARESTLG, THR_COMP_NEW_NEARESTLB, - THR_COMP_NEW_NEARESTLA2, THR_COMP_NEW_NEARESTLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARESTL2B, - THR_COMP_NEW_NEARESTL2A2, THR_COMP_NEW_NEARESTL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARESTL3B, - THR_COMP_NEW_NEARESTL3A2, THR_COMP_NEW_NEARESTL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARESTGB, - THR_COMP_NEW_NEARESTGA2, THR_COMP_NEW_NEARESTGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARESTBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEAR_NEWMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEAR_NEWLL2, THR_COMP_NEAR_NEWLL3, - THR_COMP_NEAR_NEWLG, THR_COMP_NEAR_NEWLB, - THR_COMP_NEAR_NEWLA2, THR_COMP_NEAR_NEWLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEWL2B, - THR_COMP_NEAR_NEWL2A2, THR_COMP_NEAR_NEWL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEWL3B, - THR_COMP_NEAR_NEWL3A2, THR_COMP_NEAR_NEWL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEWGB, - THR_COMP_NEAR_NEWGA2, THR_COMP_NEAR_NEWGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEAR_NEWBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEW_NEARMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEW_NEARLL2, THR_COMP_NEW_NEARLL3, - THR_COMP_NEW_NEARLG, THR_COMP_NEW_NEARLB, - THR_COMP_NEW_NEARLA2, THR_COMP_NEW_NEARLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARL2B, - THR_COMP_NEW_NEARL2A2, THR_COMP_NEW_NEARL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARL3B, - THR_COMP_NEW_NEARL3A2, THR_COMP_NEW_NEARL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARGB, - THR_COMP_NEW_NEARGA2, THR_COMP_NEW_NEARGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEARBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // GLOBAL_GLOBALMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_GLOBAL_GLOBALLL2, THR_COMP_GLOBAL_GLOBALLL3, - THR_COMP_GLOBAL_GLOBALLG, THR_COMP_GLOBAL_GLOBALLB, - THR_COMP_GLOBAL_GLOBALLA2, THR_COMP_GLOBAL_GLOBALLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_GLOBAL_GLOBALL2B, - THR_COMP_GLOBAL_GLOBALL2A2, THR_COMP_GLOBAL_GLOBALL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_GLOBAL_GLOBALL3B, - THR_COMP_GLOBAL_GLOBALL3A2, THR_COMP_GLOBAL_GLOBALL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_GLOBAL_GLOBALGB, - THR_COMP_GLOBAL_GLOBALGA2, THR_COMP_GLOBAL_GLOBALGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_GLOBAL_GLOBALBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, - // NEW_NEWMV, - { - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, - THR_COMP_NEW_NEWLL2, THR_COMP_NEW_NEWLL3, - THR_COMP_NEW_NEWLG, THR_COMP_NEW_NEWLB, - THR_COMP_NEW_NEWLA2, THR_COMP_NEW_NEWLA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEWL2B, - THR_COMP_NEW_NEWL2A2, THR_COMP_NEW_NEWL2A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEWL3B, - THR_COMP_NEW_NEWL3A2, THR_COMP_NEW_NEWL3A, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEWGB, - THR_COMP_NEW_NEWGA2, THR_COMP_NEW_NEWGA, }, - { THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, - THR_INVALID, THR_COMP_NEW_NEWBA, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, - THR_INVALID, THR_INVALID, THR_INVALID, }, - }, -}; -/* clang-format on */ -// Calculate rd threshold based on ref best rd and relevant scaling factors -static INLINE int64_t get_rd_thresh_from_best_rd(int64_t ref_best_rd, - int mul_factor, - int div_factor) { - int64_t rd_thresh = ref_best_rd; - if (div_factor != 0) { - rd_thresh = ref_best_rd < (div_factor * (INT64_MAX / mul_factor)) - ? ((ref_best_rd / div_factor) * mul_factor) - : INT64_MAX; - } - return rd_thresh; -} - -static THR_MODES get_prediction_mode_idx(PREDICTION_MODE this_mode, - MV_REFERENCE_FRAME ref_frame, - MV_REFERENCE_FRAME second_ref_frame) { - if (this_mode < INTRA_MODE_END) { - assert(ref_frame == INTRA_FRAME); - assert(second_ref_frame == NONE_FRAME); - return intra_to_mode_idx[this_mode - INTRA_MODE_START]; - } - if (this_mode >= SINGLE_INTER_MODE_START && - this_mode < SINGLE_INTER_MODE_END) { - assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME)); - return single_inter_to_mode_idx[this_mode - SINGLE_INTER_MODE_START] - [ref_frame]; - } - if (this_mode >= COMP_INTER_MODE_START && this_mode < COMP_INTER_MODE_END) { - assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME)); - assert((second_ref_frame > INTRA_FRAME) && - (second_ref_frame <= ALTREF_FRAME)); - return comp_inter_to_mode_idx[this_mode - COMP_INTER_MODE_START][ref_frame] - [second_ref_frame]; - } - assert(0); - return THR_INVALID; -} - -static const PREDICTION_MODE intra_rd_search_mode_order[INTRA_MODES] = { - DC_PRED, H_PRED, V_PRED, SMOOTH_PRED, PAETH_PRED, - SMOOTH_V_PRED, SMOOTH_H_PRED, D135_PRED, D203_PRED, D157_PRED, - D67_PRED, D113_PRED, D45_PRED, -}; - -static const UV_PREDICTION_MODE uv_rd_search_mode_order[UV_INTRA_MODES] = { - UV_DC_PRED, UV_CFL_PRED, UV_H_PRED, UV_V_PRED, - UV_SMOOTH_PRED, UV_PAETH_PRED, UV_SMOOTH_V_PRED, UV_SMOOTH_H_PRED, - UV_D135_PRED, UV_D203_PRED, UV_D157_PRED, UV_D67_PRED, - UV_D113_PRED, UV_D45_PRED, -}; - typedef struct SingleInterModeState { int64_t rd; MV_REFERENCE_FRAME ref_frame; @@ -940,30 +320,19 @@ typedef struct SingleInterModeState { typedef struct InterModeSearchState { int64_t best_rd; + int64_t best_skip_rd[2]; MB_MODE_INFO best_mbmode; int best_rate_y; int best_rate_uv; int best_mode_skippable; int best_skip2; THR_MODES best_mode_index; - int skip_intra_modes; int num_available_refs; int64_t dist_refs[REF_FRAMES]; int dist_order_refs[REF_FRAMES]; int64_t mode_threshold[MAX_MODES]; - PREDICTION_MODE best_intra_mode; int64_t best_intra_rd; - int angle_stats_ready; - uint8_t directional_mode_skip_mask[INTRA_MODES]; unsigned int best_pred_sse; - int rate_uv_intra; - int rate_uv_tokenonly; - int64_t dist_uvs; - int skip_uvs; - UV_PREDICTION_MODE mode_uv; - PALETTE_MODE_INFO pmi_uv; - int8_t uv_angle_delta; - int64_t best_pred_rd[REFERENCE_MODES]; int64_t best_pred_diff[REFERENCE_MODES]; // Save a set of single_newmv for each checked ref_mv. int_mv single_newmv[MAX_REF_MV_SEARCH][REF_FRAMES]; @@ -980,30 +349,9 @@ typedef struct InterModeSearchState { [FWD_REFS]; int single_state_modelled_cnt[2][SINGLE_INTER_MODE_NUM]; MV_REFERENCE_FRAME single_rd_order[2][SINGLE_INTER_MODE_NUM][FWD_REFS]; + IntraModeSearchState intra_search_state; } InterModeSearchState; -static void alloc_compound_type_rd_buffers_no_check( - CompoundTypeRdBuffers *const bufs) { - bufs->pred0 = - (uint8_t *)aom_memalign(16, 2 * MAX_SB_SQUARE * sizeof(*bufs->pred0)); - bufs->pred1 = - (uint8_t *)aom_memalign(16, 2 * MAX_SB_SQUARE * sizeof(*bufs->pred1)); - bufs->residual1 = - (int16_t *)aom_memalign(32, MAX_SB_SQUARE * sizeof(*bufs->residual1)); - bufs->diff10 = - (int16_t *)aom_memalign(32, MAX_SB_SQUARE * sizeof(*bufs->diff10)); - bufs->tmp_best_mask_buf = (uint8_t *)aom_malloc( - 2 * MAX_SB_SQUARE * sizeof(*bufs->tmp_best_mask_buf)); -} - -static int inter_mode_data_block_idx(BLOCK_SIZE bsize) { - if (bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 || - bsize == BLOCK_4X16 || bsize == BLOCK_16X4) { - return -1; - } - return 1; -} - void av1_inter_mode_data_init(TileDataEnc *tile_data) { for (int i = 0; i < BLOCK_SIZES_ALL; ++i) { InterModeRdModel *md = &tile_data->inter_mode_rd_models[i]; @@ -1163,530 +511,6 @@ static AOM_INLINE void inter_modes_info_sort( compare_rd_idx_pair); } -static INLINE int write_uniform_cost(int n, int v) { - const int l = get_unsigned_bits(n); - const int m = (1 << l) - n; - if (l == 0) return 0; - if (v < m) - return av1_cost_literal(l - 1); - else - return av1_cost_literal(l); -} - -// Similar to store_cfl_required(), but for use during the RDO process, -// where we haven't yet determined whether this block uses CfL. -static INLINE CFL_ALLOWED_TYPE store_cfl_required_rdo(const AV1_COMMON *cm, - const MACROBLOCK *x) { - const MACROBLOCKD *xd = &x->e_mbd; - - if (cm->seq_params.monochrome || x->skip_chroma_rd) return CFL_DISALLOWED; - - if (!xd->cfl.is_chroma_reference) { - // For non-chroma-reference blocks, we should always store the luma pixels, - // in case the corresponding chroma-reference block uses CfL. - // Note that this can only happen for block sizes which are <8 on - // their shortest side, as otherwise they would be chroma reference - // blocks. - return CFL_ALLOWED; - } - - // For chroma reference blocks, we should store data in the encoder iff we're - // allowed to try out CfL. - return is_cfl_allowed(xd); -} - -static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, - RD_STATS *rd_stats, BLOCK_SIZE bsize, - int64_t ref_best_rd, FAST_TX_SEARCH_MODE ftxs_mode); - -static unsigned pixel_dist_visible_only( - const AV1_COMP *const cpi, const MACROBLOCK *x, const uint8_t *src, - const int src_stride, const uint8_t *dst, const int dst_stride, - const BLOCK_SIZE tx_bsize, int txb_rows, int txb_cols, int visible_rows, - int visible_cols) { - unsigned sse; - - if (txb_rows == visible_rows && txb_cols == visible_cols) { - cpi->fn_ptr[tx_bsize].vf(src, src_stride, dst, dst_stride, &sse); - return sse; - } - -#if CONFIG_AV1_HIGHBITDEPTH - const MACROBLOCKD *xd = &x->e_mbd; - if (is_cur_buf_hbd(xd)) { - uint64_t sse64 = aom_highbd_sse_odd_size(src, src_stride, dst, dst_stride, - visible_cols, visible_rows); - return (unsigned int)ROUND_POWER_OF_TWO(sse64, (xd->bd - 8) * 2); - } -#else - (void)x; -#endif - sse = aom_sse_odd_size(src, src_stride, dst, dst_stride, visible_cols, - visible_rows); - return sse; -} - -#if CONFIG_DIST_8X8 -static uint64_t cdef_dist_8x8_16bit(uint16_t *dst, int dstride, uint16_t *src, - int sstride, int coeff_shift) { - uint64_t svar = 0; - uint64_t dvar = 0; - uint64_t sum_s = 0; - uint64_t sum_d = 0; - uint64_t sum_s2 = 0; - uint64_t sum_d2 = 0; - uint64_t sum_sd = 0; - uint64_t dist = 0; - - int i, j; - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - sum_s += src[i * sstride + j]; - sum_d += dst[i * dstride + j]; - sum_s2 += src[i * sstride + j] * src[i * sstride + j]; - sum_d2 += dst[i * dstride + j] * dst[i * dstride + j]; - sum_sd += src[i * sstride + j] * dst[i * dstride + j]; - } - } - /* Compute the variance -- the calculation cannot go negative. */ - svar = sum_s2 - ((sum_s * sum_s + 32) >> 6); - dvar = sum_d2 - ((sum_d * sum_d + 32) >> 6); - - // Tuning of jm's original dering distortion metric used in CDEF tool, - // suggested by jm - const uint64_t a = 4; - const uint64_t b = 2; - const uint64_t c1 = (400 * a << 2 * coeff_shift); - const uint64_t c2 = (b * 20000 * a * a << 4 * coeff_shift); - - dist = (uint64_t)floor(.5 + (sum_d2 + sum_s2 - 2 * sum_sd) * .5 * - (svar + dvar + c1) / - (sqrt(svar * (double)dvar + c2))); - - // Calibrate dist to have similar rate for the same QP with MSE only - // distortion (as in master branch) - dist = (uint64_t)((float)dist * 0.75); - - return dist; -} - -static int od_compute_var_4x4(uint16_t *x, int stride) { - int sum; - int s2; - int i; - sum = 0; - s2 = 0; - for (i = 0; i < 4; i++) { - int j; - for (j = 0; j < 4; j++) { - int t; - - t = x[i * stride + j]; - sum += t; - s2 += t * t; - } - } - - return (s2 - (sum * sum >> 4)) >> 4; -} - -/* OD_DIST_LP_MID controls the frequency weighting filter used for computing - the distortion. For a value X, the filter is [1 X 1]/(X + 2) and - is applied both horizontally and vertically. For X=5, the filter is - a good approximation for the OD_QM8_Q4_HVS quantization matrix. */ -#define OD_DIST_LP_MID (5) -#define OD_DIST_LP_NORM (OD_DIST_LP_MID + 2) - -static double od_compute_dist_8x8(int use_activity_masking, uint16_t *x, - uint16_t *y, od_coeff *e_lp, int stride) { - double sum; - int min_var; - double mean_var; - double var_stat; - double activity; - double calibration; - int i; - int j; - double vardist; - - vardist = 0; - -#if 1 - min_var = INT_MAX; - mean_var = 0; - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - int varx; - int vary; - varx = od_compute_var_4x4(x + 2 * i * stride + 2 * j, stride); - vary = od_compute_var_4x4(y + 2 * i * stride + 2 * j, stride); - min_var = OD_MINI(min_var, varx); - mean_var += 1. / (1 + varx); - /* The cast to (double) is to avoid an overflow before the sqrt.*/ - vardist += varx - 2 * sqrt(varx * (double)vary) + vary; - } - } - /* We use a different variance statistic depending on whether activity - masking is used, since the harmonic mean appeared slightly worse with - masking off. The calibration constant just ensures that we preserve the - rate compared to activity=1. */ - if (use_activity_masking) { - calibration = 1.95; - var_stat = 9. / mean_var; - } else { - calibration = 1.62; - var_stat = min_var; - } - /* 1.62 is a calibration constant, 0.25 is a noise floor and 1/6 is the - activity masking constant. */ - activity = calibration * pow(.25 + var_stat, -1. / 6); -#else - activity = 1; -#endif // 1 - sum = 0; - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) - sum += e_lp[i * stride + j] * (double)e_lp[i * stride + j]; - } - /* Normalize the filter to unit DC response. */ - sum *= 1. / (OD_DIST_LP_NORM * OD_DIST_LP_NORM * OD_DIST_LP_NORM * - OD_DIST_LP_NORM); - return activity * activity * (sum + vardist); -} - -// Note : Inputs x and y are in a pixel domain -static double od_compute_dist_common(int activity_masking, uint16_t *x, - uint16_t *y, int bsize_w, int bsize_h, - int qindex, od_coeff *tmp, - od_coeff *e_lp) { - int i, j; - double sum = 0; - const int mid = OD_DIST_LP_MID; - - for (j = 0; j < bsize_w; j++) { - e_lp[j] = mid * tmp[j] + 2 * tmp[bsize_w + j]; - e_lp[(bsize_h - 1) * bsize_w + j] = mid * tmp[(bsize_h - 1) * bsize_w + j] + - 2 * tmp[(bsize_h - 2) * bsize_w + j]; - } - for (i = 1; i < bsize_h - 1; i++) { - for (j = 0; j < bsize_w; j++) { - e_lp[i * bsize_w + j] = mid * tmp[i * bsize_w + j] + - tmp[(i - 1) * bsize_w + j] + - tmp[(i + 1) * bsize_w + j]; - } - } - for (i = 0; i < bsize_h; i += 8) { - for (j = 0; j < bsize_w; j += 8) { - sum += od_compute_dist_8x8(activity_masking, &x[i * bsize_w + j], - &y[i * bsize_w + j], &e_lp[i * bsize_w + j], - bsize_w); - } - } - /* Scale according to linear regression against SSE, for 8x8 blocks. */ - if (activity_masking) { - sum *= 2.2 + (1.7 - 2.2) * (qindex - 99) / (210 - 99) + - (qindex < 99 ? 2.5 * (qindex - 99) / 99 * (qindex - 99) / 99 : 0); - } else { - sum *= qindex >= 128 - ? 1.4 + (0.9 - 1.4) * (qindex - 128) / (209 - 128) - : qindex <= 43 ? 1.5 + (2.0 - 1.5) * (qindex - 43) / (16 - 43) - : 1.5 + (1.4 - 1.5) * (qindex - 43) / (128 - 43); - } - - return sum; -} - -static double od_compute_dist(uint16_t *x, uint16_t *y, int bsize_w, - int bsize_h, int qindex) { - assert(bsize_w >= 8 && bsize_h >= 8); - - int activity_masking = 0; - - int i, j; - DECLARE_ALIGNED(16, od_coeff, e[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, od_coeff, tmp[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, od_coeff, e_lp[MAX_SB_SQUARE]); - for (i = 0; i < bsize_h; i++) { - for (j = 0; j < bsize_w; j++) { - e[i * bsize_w + j] = x[i * bsize_w + j] - y[i * bsize_w + j]; - } - } - int mid = OD_DIST_LP_MID; - for (i = 0; i < bsize_h; i++) { - tmp[i * bsize_w] = mid * e[i * bsize_w] + 2 * e[i * bsize_w + 1]; - tmp[i * bsize_w + bsize_w - 1] = - mid * e[i * bsize_w + bsize_w - 1] + 2 * e[i * bsize_w + bsize_w - 2]; - for (j = 1; j < bsize_w - 1; j++) { - tmp[i * bsize_w + j] = mid * e[i * bsize_w + j] + e[i * bsize_w + j - 1] + - e[i * bsize_w + j + 1]; - } - } - return od_compute_dist_common(activity_masking, x, y, bsize_w, bsize_h, - qindex, tmp, e_lp); -} - -static double od_compute_dist_diff(uint16_t *x, int16_t *e, int bsize_w, - int bsize_h, int qindex) { - assert(bsize_w >= 8 && bsize_h >= 8); - - int activity_masking = 0; - - DECLARE_ALIGNED(16, uint16_t, y[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, od_coeff, tmp[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, od_coeff, e_lp[MAX_SB_SQUARE]); - int i, j; - for (i = 0; i < bsize_h; i++) { - for (j = 0; j < bsize_w; j++) { - y[i * bsize_w + j] = x[i * bsize_w + j] - e[i * bsize_w + j]; - } - } - int mid = OD_DIST_LP_MID; - for (i = 0; i < bsize_h; i++) { - tmp[i * bsize_w] = mid * e[i * bsize_w] + 2 * e[i * bsize_w + 1]; - tmp[i * bsize_w + bsize_w - 1] = - mid * e[i * bsize_w + bsize_w - 1] + 2 * e[i * bsize_w + bsize_w - 2]; - for (j = 1; j < bsize_w - 1; j++) { - tmp[i * bsize_w + j] = mid * e[i * bsize_w + j] + e[i * bsize_w + j - 1] + - e[i * bsize_w + j + 1]; - } - } - return od_compute_dist_common(activity_masking, x, y, bsize_w, bsize_h, - qindex, tmp, e_lp); -} - -int64_t av1_dist_8x8(const AV1_COMP *const cpi, const MACROBLOCK *x, - const uint8_t *src, int src_stride, const uint8_t *dst, - int dst_stride, const BLOCK_SIZE tx_bsize, int bsw, - int bsh, int visible_w, int visible_h, int qindex) { - int64_t d = 0; - int i, j; - const MACROBLOCKD *xd = &x->e_mbd; - - DECLARE_ALIGNED(16, uint16_t, orig[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, uint16_t, rec[MAX_SB_SQUARE]); - - assert(bsw >= 8); - assert(bsh >= 8); - assert((bsw & 0x07) == 0); - assert((bsh & 0x07) == 0); - - if (x->tune_metric == AOM_TUNE_CDEF_DIST || - x->tune_metric == AOM_TUNE_DAALA_DIST) { - if (is_cur_buf_hbd(xd)) { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) - orig[j * bsw + i] = CONVERT_TO_SHORTPTR(src)[j * src_stride + i]; - - if ((bsw == visible_w) && (bsh == visible_h)) { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) - rec[j * bsw + i] = CONVERT_TO_SHORTPTR(dst)[j * dst_stride + i]; - } else { - for (j = 0; j < visible_h; j++) - for (i = 0; i < visible_w; i++) - rec[j * bsw + i] = CONVERT_TO_SHORTPTR(dst)[j * dst_stride + i]; - - if (visible_w < bsw) { - for (j = 0; j < bsh; j++) - for (i = visible_w; i < bsw; i++) - rec[j * bsw + i] = CONVERT_TO_SHORTPTR(src)[j * src_stride + i]; - } - - if (visible_h < bsh) { - for (j = visible_h; j < bsh; j++) - for (i = 0; i < bsw; i++) - rec[j * bsw + i] = CONVERT_TO_SHORTPTR(src)[j * src_stride + i]; - } - } - } else { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) orig[j * bsw + i] = src[j * src_stride + i]; - - if ((bsw == visible_w) && (bsh == visible_h)) { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) rec[j * bsw + i] = dst[j * dst_stride + i]; - } else { - for (j = 0; j < visible_h; j++) - for (i = 0; i < visible_w; i++) - rec[j * bsw + i] = dst[j * dst_stride + i]; - - if (visible_w < bsw) { - for (j = 0; j < bsh; j++) - for (i = visible_w; i < bsw; i++) - rec[j * bsw + i] = src[j * src_stride + i]; - } - - if (visible_h < bsh) { - for (j = visible_h; j < bsh; j++) - for (i = 0; i < bsw; i++) - rec[j * bsw + i] = src[j * src_stride + i]; - } - } - } - } - - if (x->tune_metric == AOM_TUNE_DAALA_DIST) { - d = (int64_t)od_compute_dist(orig, rec, bsw, bsh, qindex); - } else if (x->tune_metric == AOM_TUNE_CDEF_DIST) { - int coeff_shift = AOMMAX(xd->bd - 8, 0); - - for (i = 0; i < bsh; i += 8) { - for (j = 0; j < bsw; j += 8) { - d += cdef_dist_8x8_16bit(&rec[i * bsw + j], bsw, &orig[i * bsw + j], - bsw, coeff_shift); - } - } - if (is_cur_buf_hbd(xd)) d = ((uint64_t)d) >> 2 * coeff_shift; - } else { - // Otherwise, MSE by default - d = pixel_dist_visible_only(cpi, x, src, src_stride, dst, dst_stride, - tx_bsize, bsh, bsw, visible_h, visible_w); - } - - return d; -} - -static int64_t dist_8x8_diff(const MACROBLOCK *x, const uint8_t *src, - int src_stride, const int16_t *diff, - int diff_stride, int bsw, int bsh, int visible_w, - int visible_h, int qindex) { - int64_t d = 0; - int i, j; - const MACROBLOCKD *xd = &x->e_mbd; - - DECLARE_ALIGNED(16, uint16_t, orig[MAX_SB_SQUARE]); - DECLARE_ALIGNED(16, int16_t, diff16[MAX_SB_SQUARE]); - - assert(bsw >= 8); - assert(bsh >= 8); - assert((bsw & 0x07) == 0); - assert((bsh & 0x07) == 0); - - if (x->tune_metric == AOM_TUNE_CDEF_DIST || - x->tune_metric == AOM_TUNE_DAALA_DIST) { - if (is_cur_buf_hbd(xd)) { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) - orig[j * bsw + i] = CONVERT_TO_SHORTPTR(src)[j * src_stride + i]; - } else { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) orig[j * bsw + i] = src[j * src_stride + i]; - } - - if ((bsw == visible_w) && (bsh == visible_h)) { - for (j = 0; j < bsh; j++) - for (i = 0; i < bsw; i++) - diff16[j * bsw + i] = diff[j * diff_stride + i]; - } else { - for (j = 0; j < visible_h; j++) - for (i = 0; i < visible_w; i++) - diff16[j * bsw + i] = diff[j * diff_stride + i]; - - if (visible_w < bsw) { - for (j = 0; j < bsh; j++) - for (i = visible_w; i < bsw; i++) diff16[j * bsw + i] = 0; - } - - if (visible_h < bsh) { - for (j = visible_h; j < bsh; j++) - for (i = 0; i < bsw; i++) diff16[j * bsw + i] = 0; - } - } - } - - if (x->tune_metric == AOM_TUNE_DAALA_DIST) { - d = (int64_t)od_compute_dist_diff(orig, diff16, bsw, bsh, qindex); - } else if (x->tune_metric == AOM_TUNE_CDEF_DIST) { - int coeff_shift = AOMMAX(xd->bd - 8, 0); - DECLARE_ALIGNED(16, uint16_t, dst16[MAX_SB_SQUARE]); - - for (i = 0; i < bsh; i++) { - for (j = 0; j < bsw; j++) { - dst16[i * bsw + j] = orig[i * bsw + j] - diff16[i * bsw + j]; - } - } - - for (i = 0; i < bsh; i += 8) { - for (j = 0; j < bsw; j += 8) { - d += cdef_dist_8x8_16bit(&dst16[i * bsw + j], bsw, &orig[i * bsw + j], - bsw, coeff_shift); - } - } - // Don't scale 'd' for HBD since it will be done by caller side for diff - // input - } else { - // Otherwise, MSE by default - d = aom_sum_squares_2d_i16(diff, diff_stride, visible_w, visible_h); - } - - return d; -} -#endif // CONFIG_DIST_8X8 - -static AOM_INLINE void get_energy_distribution_finer(const int16_t *diff, - int stride, int bw, int bh, - float *hordist, - float *verdist) { - // First compute downscaled block energy values (esq); downscale factors - // are defined by w_shift and h_shift. - unsigned int esq[256]; - const int w_shift = bw <= 8 ? 0 : 1; - const int h_shift = bh <= 8 ? 0 : 1; - const int esq_w = bw >> w_shift; - const int esq_h = bh >> h_shift; - const int esq_sz = esq_w * esq_h; - int i, j; - memset(esq, 0, esq_sz * sizeof(esq[0])); - if (w_shift) { - for (i = 0; i < bh; i++) { - unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w; - const int16_t *cur_diff_row = diff + i * stride; - for (j = 0; j < bw; j += 2) { - cur_esq_row[j >> 1] += (cur_diff_row[j] * cur_diff_row[j] + - cur_diff_row[j + 1] * cur_diff_row[j + 1]); - } - } - } else { - for (i = 0; i < bh; i++) { - unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w; - const int16_t *cur_diff_row = diff + i * stride; - for (j = 0; j < bw; j++) { - cur_esq_row[j] += cur_diff_row[j] * cur_diff_row[j]; - } - } - } - - uint64_t total = 0; - for (i = 0; i < esq_sz; i++) total += esq[i]; - - // Output hordist and verdist arrays are normalized 1D projections of esq - if (total == 0) { - float hor_val = 1.0f / esq_w; - for (j = 0; j < esq_w - 1; j++) hordist[j] = hor_val; - float ver_val = 1.0f / esq_h; - for (i = 0; i < esq_h - 1; i++) verdist[i] = ver_val; - return; - } - - const float e_recip = 1.0f / (float)total; - memset(hordist, 0, (esq_w - 1) * sizeof(hordist[0])); - memset(verdist, 0, (esq_h - 1) * sizeof(verdist[0])); - const unsigned int *cur_esq_row; - for (i = 0; i < esq_h - 1; i++) { - cur_esq_row = esq + i * esq_w; - for (j = 0; j < esq_w - 1; j++) { - hordist[j] += (float)cur_esq_row[j]; - verdist[i] += (float)cur_esq_row[j]; - } - verdist[i] += (float)cur_esq_row[j]; - } - cur_esq_row = esq + i * esq_w; - for (j = 0; j < esq_w - 1; j++) hordist[j] += (float)cur_esq_row[j]; - - for (j = 0; j < esq_w - 1; j++) hordist[j] *= e_recip; - for (i = 0; i < esq_h - 1; i++) verdist[i] *= e_recip; -} - // Similar to get_horver_correlation, but also takes into account first // row/column, when computing horizontal/vertical correlation. void av1_get_horver_correlation_full_c(const int16_t *diff, int stride, @@ -1786,321 +610,30 @@ void av1_get_horver_correlation_full_c(const int16_t *diff, int stride, } } -// These thresholds were calibrated to provide a certain number of TX types -// pruned by the model on average, i.e. selecting a threshold with index i -// will lead to pruning i+1 TX types on average -static const float *prune_2D_adaptive_thresholds[] = { - // TX_4X4 - (float[]){ 0.00549f, 0.01306f, 0.02039f, 0.02747f, 0.03406f, 0.04065f, - 0.04724f, 0.05383f, 0.06067f, 0.06799f, 0.07605f, 0.08533f, - 0.09778f, 0.11780f }, - // TX_8X8 - (float[]){ 0.00037f, 0.00183f, 0.00525f, 0.01038f, 0.01697f, 0.02502f, - 0.03381f, 0.04333f, 0.05286f, 0.06287f, 0.07434f, 0.08850f, - 0.10803f, 0.14124f }, - // TX_16X16 - (float[]){ 0.01404f, 0.02000f, 0.04211f, 0.05164f, 0.05798f, 0.06335f, - 0.06897f, 0.07629f, 0.08875f, 0.11169f }, - // TX_32X32 - NULL, - // TX_64X64 - NULL, - // TX_4X8 - (float[]){ 0.00183f, 0.00745f, 0.01428f, 0.02185f, 0.02966f, 0.03723f, - 0.04456f, 0.05188f, 0.05920f, 0.06702f, 0.07605f, 0.08704f, - 0.10168f, 0.12585f }, - // TX_8X4 - (float[]){ 0.00085f, 0.00476f, 0.01135f, 0.01892f, 0.02698f, 0.03528f, - 0.04358f, 0.05164f, 0.05994f, 0.06848f, 0.07849f, 0.09021f, - 0.10583f, 0.13123f }, - // TX_8X16 - (float[]){ 0.00037f, 0.00232f, 0.00671f, 0.01257f, 0.01965f, 0.02722f, - 0.03552f, 0.04382f, 0.05237f, 0.06189f, 0.07336f, 0.08728f, - 0.10730f, 0.14221f }, - // TX_16X8 - (float[]){ 0.00061f, 0.00330f, 0.00818f, 0.01453f, 0.02185f, 0.02966f, - 0.03772f, 0.04578f, 0.05383f, 0.06262f, 0.07288f, 0.08582f, - 0.10339f, 0.13464f }, - // TX_16X32 - NULL, - // TX_32X16 - NULL, - // TX_32X64 - NULL, - // TX_64X32 - NULL, - // TX_4X16 - (float[]){ 0.00232f, 0.00671f, 0.01257f, 0.01941f, 0.02673f, 0.03430f, - 0.04211f, 0.04968f, 0.05750f, 0.06580f, 0.07507f, 0.08655f, - 0.10242f, 0.12878f }, - // TX_16X4 - (float[]){ 0.00110f, 0.00525f, 0.01208f, 0.01990f, 0.02795f, 0.03601f, - 0.04358f, 0.05115f, 0.05896f, 0.06702f, 0.07629f, 0.08752f, - 0.10217f, 0.12610f }, - // TX_8X32 - NULL, - // TX_32X8 - NULL, - // TX_16X64 - NULL, - // TX_64X16 - NULL, -}; - -// Probablities are sorted in descending order. -static INLINE void sort_probability(float prob[], int txk[], int len) { - int i, j, k; - - for (i = 1; i <= len - 1; ++i) { - for (j = 0; j < i; ++j) { - if (prob[j] < prob[i]) { - float temp; - int tempi; - - temp = prob[i]; - tempi = txk[i]; - - for (k = i; k > j; k--) { - prob[k] = prob[k - 1]; - txk[k] = txk[k - 1]; - } - - prob[j] = temp; - txk[j] = tempi; - break; - } - } - } -} - -static uint16_t prune_tx_2D(MACROBLOCK *x, BLOCK_SIZE bsize, TX_SIZE tx_size, - int blk_row, int blk_col, TxSetType tx_set_type, - TX_TYPE_PRUNE_MODE prune_mode, int *txk_map, - uint16_t allowed_tx_mask) { - int tx_type_table_2D[16] = { - DCT_DCT, DCT_ADST, DCT_FLIPADST, V_DCT, - ADST_DCT, ADST_ADST, ADST_FLIPADST, V_ADST, - FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST, - H_DCT, H_ADST, H_FLIPADST, IDTX - }; - if (tx_set_type != EXT_TX_SET_ALL16 && - tx_set_type != EXT_TX_SET_DTT9_IDTX_1DDCT) - return 0; -#if CONFIG_NN_V2 - NN_CONFIG_V2 *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size]; - NN_CONFIG_V2 *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size]; -#else - const NN_CONFIG *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size]; - const NN_CONFIG *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size]; -#endif - if (!nn_config_hor || !nn_config_ver) return 0; // Model not established yet. - - aom_clear_system_state(); - float hfeatures[16], vfeatures[16]; - float hscores[4], vscores[4]; - float scores_2D_raw[16]; - float scores_2D[16]; - const int bw = tx_size_wide[tx_size]; - const int bh = tx_size_high[tx_size]; - const int hfeatures_num = bw <= 8 ? bw : bw / 2; - const int vfeatures_num = bh <= 8 ? bh : bh / 2; - assert(hfeatures_num <= 16); - assert(vfeatures_num <= 16); - - const struct macroblock_plane *const p = &x->plane[0]; - const int diff_stride = block_size_wide[bsize]; - const int16_t *diff = p->src_diff + 4 * blk_row * diff_stride + 4 * blk_col; - get_energy_distribution_finer(diff, diff_stride, bw, bh, hfeatures, - vfeatures); - av1_get_horver_correlation_full(diff, diff_stride, bw, bh, - &hfeatures[hfeatures_num - 1], - &vfeatures[vfeatures_num - 1]); - aom_clear_system_state(); -#if CONFIG_NN_V2 - av1_nn_predict_v2(hfeatures, nn_config_hor, 0, hscores); - av1_nn_predict_v2(vfeatures, nn_config_ver, 0, vscores); -#else - av1_nn_predict(hfeatures, nn_config_hor, 1, hscores); - av1_nn_predict(vfeatures, nn_config_ver, 1, vscores); -#endif - aom_clear_system_state(); - - for (int i = 0; i < 4; i++) { - float *cur_scores_2D = scores_2D_raw + i * 4; - cur_scores_2D[0] = vscores[i] * hscores[0]; - cur_scores_2D[1] = vscores[i] * hscores[1]; - cur_scores_2D[2] = vscores[i] * hscores[2]; - cur_scores_2D[3] = vscores[i] * hscores[3]; - } - - av1_nn_softmax(scores_2D_raw, scores_2D, 16); - - const int prune_aggr_table[3][2] = { { 4, 1 }, { 6, 3 }, { 9, 6 } }; - int pruning_aggressiveness = 0; - if (tx_set_type == EXT_TX_SET_ALL16) { - pruning_aggressiveness = - prune_aggr_table[prune_mode - PRUNE_2D_ACCURATE][0]; - } else if (tx_set_type == EXT_TX_SET_DTT9_IDTX_1DDCT) { - pruning_aggressiveness = - prune_aggr_table[prune_mode - PRUNE_2D_ACCURATE][1]; - } - - // Always keep the TX type with the highest score, prune all others with - // score below score_thresh. - int max_score_i = 0; - float max_score = 0.0f; - for (int i = 0; i < 16; i++) { - if (scores_2D[i] > max_score && - (allowed_tx_mask & (1 << tx_type_table_2D[i]))) { - max_score = scores_2D[i]; - max_score_i = i; - } - } - - const float score_thresh = - prune_2D_adaptive_thresholds[tx_size][pruning_aggressiveness]; - - uint16_t prune_bitmask = 0; - for (int i = 0; i < 16; i++) { - if (scores_2D[i] < score_thresh && i != max_score_i) - prune_bitmask |= (1 << tx_type_table_2D[i]); - } - - sort_probability(scores_2D, tx_type_table_2D, TX_TYPES); - memcpy(txk_map, tx_type_table_2D, sizeof(tx_type_table_2D)); - - return prune_bitmask; -} - -static AOM_INLINE void model_rd_from_sse(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist) { - (void)num_samples; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - - // Fast approximate the modelling function. - if (cpi->sf.simple_model_rd_from_var) { - const int64_t square_error = sse; - int quantizer = p->dequant_QTX[1] >> dequant_shift; - if (quantizer < 120) - *rate = (int)AOMMIN( - (square_error * (280 - quantizer)) >> (16 - AV1_PROB_COST_SHIFT), - INT_MAX); - else - *rate = 0; - assert(*rate >= 0); - *dist = (square_error * quantizer) >> 8; - } else { - av1_model_rd_from_var_lapndz(sse, num_pels_log2_lookup[plane_bsize], - p->dequant_QTX[1] >> dequant_shift, rate, - dist); - } - *dist <<= 4; -} - -static int64_t get_sse(const AV1_COMP *cpi, const MACROBLOCK *x) { +static int64_t get_sse(const AV1_COMP *cpi, const MACROBLOCK *x, + int64_t *sse_y) { const AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); const MACROBLOCKD *xd = &x->e_mbd; const MB_MODE_INFO *mbmi = xd->mi[0]; int64_t total_sse = 0; for (int plane = 0; plane < num_planes; ++plane) { + if (plane && !xd->is_chroma_ref) break; const struct macroblock_plane *const p = &x->plane[plane]; const struct macroblockd_plane *const pd = &xd->plane[plane]; const BLOCK_SIZE bs = get_plane_block_size(mbmi->sb_type, pd->subsampling_x, pd->subsampling_y); unsigned int sse; - if (x->skip_chroma_rd && plane) continue; - cpi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, &sse); total_sse += sse; + if (!plane && sse_y) *sse_y = sse; } total_sse <<= 4; return total_sse; } -static int64_t calculate_sse(MACROBLOCKD *const xd, - const struct macroblock_plane *p, - struct macroblockd_plane *pd, const int bw, - const int bh) { - int64_t sse = 0; - const int shift = xd->bd - 8; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - sse = aom_highbd_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, - bw, bh); - } else { - sse = - aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh); - } -#else - sse = aom_sse(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, bw, bh); -#endif - sse = ROUND_POWER_OF_TWO(sse, shift * 2); - return sse; -} - -static AOM_INLINE void model_rd_for_sb( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist) { - // Note our transform coeffs are 8 times an orthogonal transform. - // Hence quantizer step is also 8 times. To get effective quantizer - // we need to divide by 8 before sending to modeling function. - int plane; - (void)mi_row; - (void)mi_col; - const int ref = xd->mi[0]->ref_frame[0]; - - int64_t rate_sum = 0; - int64_t dist_sum = 0; - int64_t total_sse = 0; - - assert(bsize < BLOCK_SIZES_ALL); - - for (plane = plane_from; plane <= plane_to; ++plane) { - struct macroblock_plane *const p = &x->plane[plane]; - struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - assert(plane_bsize < BLOCK_SIZES_ALL); - const int bw = block_size_wide[plane_bsize]; - const int bh = block_size_high[plane_bsize]; - int64_t sse; - int rate; - int64_t dist; - - if (x->skip_chroma_rd && plane) continue; - - sse = calculate_sse(xd, p, pd, bw, bh); - - model_rd_from_sse(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, &dist); - - if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); - - total_sse += sse; - rate_sum += rate; - dist_sum += dist; - if (plane_rate) plane_rate[plane] = rate; - if (plane_sse) plane_sse[plane] = sse; - if (plane_dist) plane_dist[plane] = dist; - assert(rate_sum >= 0); - } - - if (skip_txfm_sb) *skip_txfm_sb = total_sse == 0; - if (skip_sse_sb) *skip_sse_sb = total_sse << 4; - rate_sum = AOMMIN(rate_sum, INT_MAX); - *out_rate_sum = (int)rate_sum; - *out_dist_sum = dist_sum; -} - int64_t av1_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz) { int i; @@ -2116,6 +649,18 @@ int64_t av1_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, return error; } +int64_t av1_block_error_lp_c(const int16_t *coeff, const int16_t *dqcoeff, + intptr_t block_size) { + int64_t error = 0; + + for (int i = 0; i < block_size; i++) { + const int diff = coeff[i] - dqcoeff[i]; + error += diff * diff; + } + + return error; +} + #if CONFIG_AV1_HIGHBITDEPTH int64_t av1_highbd_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, @@ -2139,2209 +684,6 @@ int64_t av1_highbd_block_error_c(const tran_low_t *coeff, } #endif -// Get transform block visible dimensions cropped to the MI units. -static AOM_INLINE void get_txb_dimensions(const MACROBLOCKD *xd, int plane, - BLOCK_SIZE plane_bsize, int blk_row, - int blk_col, BLOCK_SIZE tx_bsize, - int *width, int *height, - int *visible_width, - int *visible_height) { - assert(tx_bsize <= plane_bsize); - const int txb_height = block_size_high[tx_bsize]; - const int txb_width = block_size_wide[tx_bsize]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int tx_unit_size = tx_size_wide_log2[0]; - - // TODO(aconverse@google.com): Investigate using crop_width/height here rather - // than the MI size - if (xd->mb_to_bottom_edge >= 0) { - *visible_height = txb_height; - } else { - const int block_height = block_size_high[plane_bsize]; - const int block_rows = - (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) + block_height; - *visible_height = - clamp(block_rows - (blk_row << tx_unit_size), 0, txb_height); - } - if (height) *height = txb_height; - - if (xd->mb_to_right_edge >= 0) { - *visible_width = txb_width; - } else { - const int block_width = block_size_wide[plane_bsize]; - const int block_cols = - (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) + block_width; - *visible_width = - clamp(block_cols - (blk_col << tx_unit_size), 0, txb_width); - } - if (width) *width = txb_width; -} - -// Compute the pixel domain distortion from src and dst on all visible 4x4s in -// the -// transform block. -static unsigned pixel_dist(const AV1_COMP *const cpi, const MACROBLOCK *x, - int plane, const uint8_t *src, const int src_stride, - const uint8_t *dst, const int dst_stride, - int blk_row, int blk_col, - const BLOCK_SIZE plane_bsize, - const BLOCK_SIZE tx_bsize) { - int txb_rows, txb_cols, visible_rows, visible_cols; - const MACROBLOCKD *xd = &x->e_mbd; - - get_txb_dimensions(xd, plane, plane_bsize, blk_row, blk_col, tx_bsize, - &txb_cols, &txb_rows, &visible_cols, &visible_rows); - assert(visible_rows > 0); - assert(visible_cols > 0); - -#if CONFIG_DIST_8X8 - if (x->using_dist_8x8 && plane == 0) - return (unsigned)av1_dist_8x8(cpi, x, src, src_stride, dst, dst_stride, - tx_bsize, txb_cols, txb_rows, visible_cols, - visible_rows, x->qindex); -#endif // CONFIG_DIST_8X8 - - unsigned sse = pixel_dist_visible_only(cpi, x, src, src_stride, dst, - dst_stride, tx_bsize, txb_rows, - txb_cols, visible_rows, visible_cols); - - return sse; -} - -// Compute the pixel domain distortion from diff on all visible 4x4s in the -// transform block. -static INLINE int64_t pixel_diff_dist(const MACROBLOCK *x, int plane, - int blk_row, int blk_col, - const BLOCK_SIZE plane_bsize, - const BLOCK_SIZE tx_bsize, - unsigned int *block_mse_q8) { - int visible_rows, visible_cols; - const MACROBLOCKD *xd = &x->e_mbd; - get_txb_dimensions(xd, plane, plane_bsize, blk_row, blk_col, tx_bsize, NULL, - NULL, &visible_cols, &visible_rows); - const int diff_stride = block_size_wide[plane_bsize]; - const int16_t *diff = x->plane[plane].src_diff; -#if CONFIG_DIST_8X8 - int txb_height = block_size_high[tx_bsize]; - int txb_width = block_size_wide[tx_bsize]; - if (x->using_dist_8x8 && plane == 0) { - const int src_stride = x->plane[plane].src.stride; - const int src_idx = (blk_row * src_stride + blk_col) - << tx_size_wide_log2[0]; - const int diff_idx = (blk_row * diff_stride + blk_col) - << tx_size_wide_log2[0]; - const uint8_t *src = &x->plane[plane].src.buf[src_idx]; - return dist_8x8_diff(x, src, src_stride, diff + diff_idx, diff_stride, - txb_width, txb_height, visible_cols, visible_rows, - x->qindex); - } -#endif - diff += ((blk_row * diff_stride + blk_col) << tx_size_wide_log2[0]); - uint64_t sse = - aom_sum_squares_2d_i16(diff, diff_stride, visible_cols, visible_rows); - if (block_mse_q8 != NULL) { - if (visible_cols > 0 && visible_rows > 0) - *block_mse_q8 = - (unsigned int)((256 * sse) / (visible_cols * visible_rows)); - else - *block_mse_q8 = UINT_MAX; - } - return sse; -} - -int av1_count_colors(const uint8_t *src, int stride, int rows, int cols, - int *val_count) { - const int max_pix_val = 1 << 8; - memset(val_count, 0, max_pix_val * sizeof(val_count[0])); - for (int r = 0; r < rows; ++r) { - for (int c = 0; c < cols; ++c) { - const int this_val = src[r * stride + c]; - assert(this_val < max_pix_val); - ++val_count[this_val]; - } - } - int n = 0; - for (int i = 0; i < max_pix_val; ++i) { - if (val_count[i]) ++n; - } - return n; -} - -int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols, - int bit_depth, int *val_count) { - assert(bit_depth <= 12); - const int max_pix_val = 1 << bit_depth; - const uint16_t *src = CONVERT_TO_SHORTPTR(src8); - memset(val_count, 0, max_pix_val * sizeof(val_count[0])); - for (int r = 0; r < rows; ++r) { - for (int c = 0; c < cols; ++c) { - const int this_val = src[r * stride + c]; - assert(this_val < max_pix_val); - if (this_val >= max_pix_val) return 0; - ++val_count[this_val]; - } - } - int n = 0; - for (int i = 0; i < max_pix_val; ++i) { - if (val_count[i]) ++n; - } - return n; -} - -static AOM_INLINE void inverse_transform_block_facade(MACROBLOCKD *xd, - int plane, int block, - int blk_row, int blk_col, - int eob, - int reduced_tx_set) { - if (!eob) return; - - struct macroblockd_plane *const pd = &xd->plane[plane]; - tran_low_t *dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); - const PLANE_TYPE plane_type = get_plane_type(plane); - const TX_SIZE tx_size = av1_get_tx_size(plane, xd); - const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, - tx_size, reduced_tx_set); - const int dst_stride = pd->dst.stride; - uint8_t *dst = - &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]]; - av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, dst, - dst_stride, eob, reduced_tx_set); -} - -static int find_tx_size_rd_info(TXB_RD_RECORD *cur_record, const uint32_t hash); - -static uint32_t get_intra_txb_hash(MACROBLOCK *x, int plane, int blk_row, - int blk_col, BLOCK_SIZE plane_bsize, - TX_SIZE tx_size) { - int16_t tmp_data[64 * 64]; - const int diff_stride = block_size_wide[plane_bsize]; - const int16_t *diff = x->plane[plane].src_diff; - const int16_t *cur_diff_row = diff + 4 * blk_row * diff_stride + 4 * blk_col; - const int txb_w = tx_size_wide[tx_size]; - const int txb_h = tx_size_high[tx_size]; - uint8_t *hash_data = (uint8_t *)cur_diff_row; - if (txb_w != diff_stride) { - int16_t *cur_hash_row = tmp_data; - for (int i = 0; i < txb_h; i++) { - memcpy(cur_hash_row, cur_diff_row, sizeof(*diff) * txb_w); - cur_hash_row += txb_w; - cur_diff_row += diff_stride; - } - hash_data = (uint8_t *)tmp_data; - } - CRC32C *crc = &x->mb_rd_record.crc_calculator; - const uint32_t hash = av1_get_crc32c_value(crc, hash_data, 2 * txb_w * txb_h); - return (hash << 5) + tx_size; -} - -static INLINE void dist_block_tx_domain(MACROBLOCK *x, int plane, int block, - TX_SIZE tx_size, int64_t *out_dist, - int64_t *out_sse) { - MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - // Transform domain distortion computation is more efficient as it does - // not involve an inverse transform, but it is less accurate. - const int buffer_length = av1_get_max_eob(tx_size); - int64_t this_sse; - // TX-domain results need to shift down to Q2/D10 to match pixel - // domain distortion values which are in Q2^2 - int shift = (MAX_TX_SCALE - av1_get_tx_scale(tx_size)) * 2; - const int block_offset = BLOCK_OFFSET(block); - tran_low_t *const coeff = p->coeff + block_offset; - tran_low_t *const dqcoeff = pd->dqcoeff + block_offset; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) - *out_dist = av1_highbd_block_error(coeff, dqcoeff, buffer_length, &this_sse, - xd->bd); - else - *out_dist = av1_block_error(coeff, dqcoeff, buffer_length, &this_sse); -#else - *out_dist = av1_block_error(coeff, dqcoeff, buffer_length, &this_sse); -#endif - *out_dist = RIGHT_SIGNED_SHIFT(*out_dist, shift); - *out_sse = RIGHT_SIGNED_SHIFT(this_sse, shift); -} - -static INLINE int64_t dist_block_px_domain(const AV1_COMP *cpi, MACROBLOCK *x, - int plane, BLOCK_SIZE plane_bsize, - int block, int blk_row, int blk_col, - TX_SIZE tx_size) { - MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - const uint16_t eob = p->eobs[block]; - const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size]; - const int bsw = block_size_wide[tx_bsize]; - const int bsh = block_size_high[tx_bsize]; - const int src_stride = x->plane[plane].src.stride; - const int dst_stride = xd->plane[plane].dst.stride; - // Scale the transform block index to pixel unit. - const int src_idx = (blk_row * src_stride + blk_col) << tx_size_wide_log2[0]; - const int dst_idx = (blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]; - const uint8_t *src = &x->plane[plane].src.buf[src_idx]; - const uint8_t *dst = &xd->plane[plane].dst.buf[dst_idx]; - const tran_low_t *dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); - - assert(cpi != NULL); - assert(tx_size_wide_log2[0] == tx_size_high_log2[0]); - - uint8_t *recon; - DECLARE_ALIGNED(16, uint16_t, recon16[MAX_TX_SQUARE]); - -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - recon = CONVERT_TO_BYTEPTR(recon16); - av1_highbd_convolve_2d_copy_sr(CONVERT_TO_SHORTPTR(dst), dst_stride, - CONVERT_TO_SHORTPTR(recon), MAX_TX_SIZE, bsw, - bsh, NULL, NULL, 0, 0, NULL, xd->bd); - } else { - recon = (uint8_t *)recon16; - av1_convolve_2d_copy_sr(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh, NULL, - NULL, 0, 0, NULL); - } -#else - recon = (uint8_t *)recon16; - av1_convolve_2d_copy_sr(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh, NULL, - NULL, 0, 0, NULL); -#endif - - const PLANE_TYPE plane_type = get_plane_type(plane); - TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size, - cpi->common.reduced_tx_set_used); - av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, recon, - MAX_TX_SIZE, eob, - cpi->common.reduced_tx_set_used); - - return 16 * pixel_dist(cpi, x, plane, src, src_stride, recon, MAX_TX_SIZE, - blk_row, blk_col, plane_bsize, tx_bsize); -} - -static double get_diff_mean(const uint8_t *src, int src_stride, - const uint8_t *dst, int dst_stride, int w, int h) { - double sum = 0.0; - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - const int diff = src[j * src_stride + i] - dst[j * dst_stride + i]; - sum += diff; - } - } - assert(w > 0 && h > 0); - return sum / (w * h); -} - -static double get_highbd_diff_mean(const uint8_t *src8, int src_stride, - const uint8_t *dst8, int dst_stride, int w, - int h) { - const uint16_t *src = CONVERT_TO_SHORTPTR(src8); - const uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); - double sum = 0.0; - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - const int diff = src[j * src_stride + i] - dst[j * dst_stride + i]; - sum += diff; - } - } - assert(w > 0 && h > 0); - return sum / (w * h); -} - -static double get_sse_norm(const int16_t *diff, int stride, int w, int h) { - double sum = 0.0; - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - const int err = diff[j * stride + i]; - sum += err * err; - } - } - assert(w > 0 && h > 0); - return sum / (w * h); -} - -static double get_sad_norm(const int16_t *diff, int stride, int w, int h) { - double sum = 0.0; - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - sum += abs(diff[j * stride + i]); - } - } - assert(w > 0 && h > 0); - return sum / (w * h); -} - -static AOM_INLINE void get_2x2_normalized_sses_and_sads( - const AV1_COMP *const cpi, BLOCK_SIZE tx_bsize, const uint8_t *const src, - int src_stride, const uint8_t *const dst, int dst_stride, - const int16_t *const src_diff, int diff_stride, double *const sse_norm_arr, - double *const sad_norm_arr) { - const BLOCK_SIZE tx_bsize_half = - get_partition_subsize(tx_bsize, PARTITION_SPLIT); - if (tx_bsize_half == BLOCK_INVALID) { // manually calculate stats - const int half_width = block_size_wide[tx_bsize] / 2; - const int half_height = block_size_high[tx_bsize] / 2; - for (int row = 0; row < 2; ++row) { - for (int col = 0; col < 2; ++col) { - const int16_t *const this_src_diff = - src_diff + row * half_height * diff_stride + col * half_width; - if (sse_norm_arr) { - sse_norm_arr[row * 2 + col] = - get_sse_norm(this_src_diff, diff_stride, half_width, half_height); - } - if (sad_norm_arr) { - sad_norm_arr[row * 2 + col] = - get_sad_norm(this_src_diff, diff_stride, half_width, half_height); - } - } - } - } else { // use function pointers to calculate stats - const int half_width = block_size_wide[tx_bsize_half]; - const int half_height = block_size_high[tx_bsize_half]; - const int num_samples_half = half_width * half_height; - for (int row = 0; row < 2; ++row) { - for (int col = 0; col < 2; ++col) { - const uint8_t *const this_src = - src + row * half_height * src_stride + col * half_width; - const uint8_t *const this_dst = - dst + row * half_height * dst_stride + col * half_width; - - if (sse_norm_arr) { - unsigned int this_sse; - cpi->fn_ptr[tx_bsize_half].vf(this_src, src_stride, this_dst, - dst_stride, &this_sse); - sse_norm_arr[row * 2 + col] = (double)this_sse / num_samples_half; - } - - if (sad_norm_arr) { - const unsigned int this_sad = cpi->fn_ptr[tx_bsize_half].sdf( - this_src, src_stride, this_dst, dst_stride); - sad_norm_arr[row * 2 + col] = (double)this_sad / num_samples_half; - } - } - } - } -} - -// NOTE: CONFIG_COLLECT_RD_STATS has 3 possible values -// 0: Do not collect any RD stats -// 1: Collect RD stats for transform units -// 2: Collect RD stats for partition units -#if CONFIG_COLLECT_RD_STATS - -static AOM_INLINE void get_energy_distribution_fine( - const AV1_COMP *cpi, BLOCK_SIZE bsize, const uint8_t *src, int src_stride, - const uint8_t *dst, int dst_stride, int need_4th, double *hordist, - double *verdist) { - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - unsigned int esq[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - if (bsize < BLOCK_16X16 || (bsize >= BLOCK_4X16 && bsize <= BLOCK_32X8)) { - // Special cases: calculate 'esq' values manually, as we don't have 'vf' - // functions for the 16 (very small) sub-blocks of this block. - const int w_shift = (bw == 4) ? 0 : (bw == 8) ? 1 : (bw == 16) ? 2 : 3; - const int h_shift = (bh == 4) ? 0 : (bh == 8) ? 1 : (bh == 16) ? 2 : 3; - assert(bw <= 32); - assert(bh <= 32); - assert(((bw - 1) >> w_shift) + (((bh - 1) >> h_shift) << 2) == 15); - if (cpi->common.seq_params.use_highbitdepth) { - const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); - const uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); - for (int i = 0; i < bh; ++i) - for (int j = 0; j < bw; ++j) { - const int index = (j >> w_shift) + ((i >> h_shift) << 2); - esq[index] += - (src16[j + i * src_stride] - dst16[j + i * dst_stride]) * - (src16[j + i * src_stride] - dst16[j + i * dst_stride]); - } - } else { - for (int i = 0; i < bh; ++i) - for (int j = 0; j < bw; ++j) { - const int index = (j >> w_shift) + ((i >> h_shift) << 2); - esq[index] += (src[j + i * src_stride] - dst[j + i * dst_stride]) * - (src[j + i * src_stride] - dst[j + i * dst_stride]); - } - } - } else { // Calculate 'esq' values using 'vf' functions on the 16 sub-blocks. - const int f_index = - (bsize < BLOCK_SIZES) ? bsize - BLOCK_16X16 : bsize - BLOCK_8X16; - assert(f_index >= 0 && f_index < BLOCK_SIZES_ALL); - const BLOCK_SIZE subsize = (BLOCK_SIZE)f_index; - assert(block_size_wide[bsize] == 4 * block_size_wide[subsize]); - assert(block_size_high[bsize] == 4 * block_size_high[subsize]); - cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[0]); - cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, - &esq[1]); - cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, - &esq[2]); - cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, - dst_stride, &esq[3]); - src += bh / 4 * src_stride; - dst += bh / 4 * dst_stride; - - cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[4]); - cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, - &esq[5]); - cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, - &esq[6]); - cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, - dst_stride, &esq[7]); - src += bh / 4 * src_stride; - dst += bh / 4 * dst_stride; - - cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[8]); - cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, - &esq[9]); - cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, - &esq[10]); - cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, - dst_stride, &esq[11]); - src += bh / 4 * src_stride; - dst += bh / 4 * dst_stride; - - cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[12]); - cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, - &esq[13]); - cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, - &esq[14]); - cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, - dst_stride, &esq[15]); - } - - double total = (double)esq[0] + esq[1] + esq[2] + esq[3] + esq[4] + esq[5] + - esq[6] + esq[7] + esq[8] + esq[9] + esq[10] + esq[11] + - esq[12] + esq[13] + esq[14] + esq[15]; - if (total > 0) { - const double e_recip = 1.0 / total; - hordist[0] = ((double)esq[0] + esq[4] + esq[8] + esq[12]) * e_recip; - hordist[1] = ((double)esq[1] + esq[5] + esq[9] + esq[13]) * e_recip; - hordist[2] = ((double)esq[2] + esq[6] + esq[10] + esq[14]) * e_recip; - if (need_4th) { - hordist[3] = ((double)esq[3] + esq[7] + esq[11] + esq[15]) * e_recip; - } - verdist[0] = ((double)esq[0] + esq[1] + esq[2] + esq[3]) * e_recip; - verdist[1] = ((double)esq[4] + esq[5] + esq[6] + esq[7]) * e_recip; - verdist[2] = ((double)esq[8] + esq[9] + esq[10] + esq[11]) * e_recip; - if (need_4th) { - verdist[3] = ((double)esq[12] + esq[13] + esq[14] + esq[15]) * e_recip; - } - } else { - hordist[0] = verdist[0] = 0.25; - hordist[1] = verdist[1] = 0.25; - hordist[2] = verdist[2] = 0.25; - if (need_4th) { - hordist[3] = verdist[3] = 0.25; - } - } -} - -#if CONFIG_COLLECT_RD_STATS == 1 -static double get_mean(const int16_t *diff, int stride, int w, int h) { - double sum = 0.0; - for (int j = 0; j < h; ++j) { - for (int i = 0; i < w; ++i) { - sum += diff[j * stride + i]; - } - } - assert(w > 0 && h > 0); - return sum / (w * h); -} - -static AOM_INLINE void PrintTransformUnitStats( - const AV1_COMP *const cpi, MACROBLOCK *x, const RD_STATS *const rd_stats, - int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, - TX_TYPE tx_type, int64_t rd) { - if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return; - - // Generate small sample to restrict output size. - static unsigned int seed = 21743; - if (lcg_rand16(&seed) % 256 > 0) return; - - const char output_file[] = "tu_stats.txt"; - FILE *fout = fopen(output_file, "a"); - if (!fout) return; - - const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size]; - const MACROBLOCKD *const xd = &x->e_mbd; - const int plane = 0; - struct macroblock_plane *const p = &x->plane[plane]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int txw = tx_size_wide[tx_size]; - const int txh = tx_size_high[tx_size]; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int q_step = p->dequant_QTX[1] >> dequant_shift; - const int num_samples = txw * txh; - - const double rate_norm = (double)rd_stats->rate / num_samples; - const double dist_norm = (double)rd_stats->dist / num_samples; - - fprintf(fout, "%g %g", rate_norm, dist_norm); - - const int src_stride = p->src.stride; - const uint8_t *const src = - &p->src.buf[(blk_row * src_stride + blk_col) << tx_size_wide_log2[0]]; - const int dst_stride = pd->dst.stride; - const uint8_t *const dst = - &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]]; - unsigned int sse; - cpi->fn_ptr[tx_bsize].vf(src, src_stride, dst, dst_stride, &sse); - const double sse_norm = (double)sse / num_samples; - - const unsigned int sad = - cpi->fn_ptr[tx_bsize].sdf(src, src_stride, dst, dst_stride); - const double sad_norm = (double)sad / num_samples; - - fprintf(fout, " %g %g", sse_norm, sad_norm); - - const int diff_stride = block_size_wide[plane_bsize]; - const int16_t *const src_diff = - &p->src_diff[(blk_row * diff_stride + blk_col) << tx_size_wide_log2[0]]; - - double sse_norm_arr[4], sad_norm_arr[4]; - get_2x2_normalized_sses_and_sads(cpi, tx_bsize, src, src_stride, dst, - dst_stride, src_diff, diff_stride, - sse_norm_arr, sad_norm_arr); - for (int i = 0; i < 4; ++i) { - fprintf(fout, " %g", sse_norm_arr[i]); - } - for (int i = 0; i < 4; ++i) { - fprintf(fout, " %g", sad_norm_arr[i]); - } - - const TX_TYPE_1D tx_type_1d_row = htx_tab[tx_type]; - const TX_TYPE_1D tx_type_1d_col = vtx_tab[tx_type]; - - fprintf(fout, " %d %d %d %d %d", q_step, tx_size_wide[tx_size], - tx_size_high[tx_size], tx_type_1d_row, tx_type_1d_col); - - int model_rate; - int64_t model_dist; - model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, tx_bsize, plane, sse, num_samples, - &model_rate, &model_dist); - const double model_rate_norm = (double)model_rate / num_samples; - const double model_dist_norm = (double)model_dist / num_samples; - fprintf(fout, " %g %g", model_rate_norm, model_dist_norm); - - const double mean = get_mean(src_diff, diff_stride, txw, txh); - float hor_corr, vert_corr; - av1_get_horver_correlation_full(src_diff, diff_stride, txw, txh, &hor_corr, - &vert_corr); - fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr); - - double hdist[4] = { 0 }, vdist[4] = { 0 }; - get_energy_distribution_fine(cpi, tx_bsize, src, src_stride, dst, dst_stride, - 1, hdist, vdist); - fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2], - hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]); - - fprintf(fout, " %d %" PRId64, x->rdmult, rd); - - fprintf(fout, "\n"); - fclose(fout); -} -#endif // CONFIG_COLLECT_RD_STATS == 1 - -#if CONFIG_COLLECT_RD_STATS >= 2 -static AOM_INLINE void PrintPredictionUnitStats(const AV1_COMP *const cpi, - const TileDataEnc *tile_data, - MACROBLOCK *x, - const RD_STATS *const rd_stats, - BLOCK_SIZE plane_bsize) { - if (rd_stats->invalid_rate) return; - if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return; - - if (cpi->sf.inter_mode_rd_model_estimation == 1 && - (tile_data == NULL || - !tile_data->inter_mode_rd_models[plane_bsize].ready)) - return; - (void)tile_data; - // Generate small sample to restrict output size. - static unsigned int seed = 95014; - - if ((lcg_rand16(&seed) % (1 << (14 - num_pels_log2_lookup[plane_bsize]))) != - 1) - return; - - const char output_file[] = "pu_stats.txt"; - FILE *fout = fopen(output_file, "a"); - if (!fout) return; - - const MACROBLOCKD *const xd = &x->e_mbd; - const int plane = 0; - struct macroblock_plane *const p = &x->plane[plane]; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - const int diff_stride = block_size_wide[plane_bsize]; - int bw, bh; - get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw, - &bh); - const int num_samples = bw * bh; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int q_step = p->dequant_QTX[1] >> dequant_shift; - - const double rate_norm = (double)rd_stats->rate / num_samples; - const double dist_norm = (double)rd_stats->dist / num_samples; - const double rdcost_norm = - (double)RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) / num_samples; - - fprintf(fout, "%g %g %g", rate_norm, dist_norm, rdcost_norm); - - const int src_stride = p->src.stride; - const uint8_t *const src = p->src.buf; - const int dst_stride = pd->dst.stride; - const uint8_t *const dst = pd->dst.buf; - const int16_t *const src_diff = p->src_diff; - - int64_t sse = calculate_sse(xd, p, pd, bw, bh); - const double sse_norm = (double)sse / num_samples; - - const unsigned int sad = - cpi->fn_ptr[plane_bsize].sdf(src, src_stride, dst, dst_stride); - const double sad_norm = - (double)sad / (1 << num_pels_log2_lookup[plane_bsize]); - - fprintf(fout, " %g %g", sse_norm, sad_norm); - - double sse_norm_arr[4], sad_norm_arr[4]; - get_2x2_normalized_sses_and_sads(cpi, plane_bsize, src, src_stride, dst, - dst_stride, src_diff, diff_stride, - sse_norm_arr, sad_norm_arr); - if (shift) { - for (int k = 0; k < 4; ++k) sse_norm_arr[k] /= (1 << (2 * shift)); - for (int k = 0; k < 4; ++k) sad_norm_arr[k] /= (1 << shift); - } - for (int i = 0; i < 4; ++i) { - fprintf(fout, " %g", sse_norm_arr[i]); - } - for (int i = 0; i < 4; ++i) { - fprintf(fout, " %g", sad_norm_arr[i]); - } - - fprintf(fout, " %d %d %d %d", q_step, x->rdmult, bw, bh); - - int model_rate; - int64_t model_dist; - model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, plane_bsize, plane, sse, num_samples, - &model_rate, &model_dist); - const double model_rdcost_norm = - (double)RDCOST(x->rdmult, model_rate, model_dist) / num_samples; - const double model_rate_norm = (double)model_rate / num_samples; - const double model_dist_norm = (double)model_dist / num_samples; - fprintf(fout, " %g %g %g", model_rate_norm, model_dist_norm, - model_rdcost_norm); - - double mean; - if (is_cur_buf_hbd(xd)) { - mean = get_highbd_diff_mean(p->src.buf, p->src.stride, pd->dst.buf, - pd->dst.stride, bw, bh); - } else { - mean = get_diff_mean(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, - bw, bh); - } - mean /= (1 << shift); - float hor_corr, vert_corr; - av1_get_horver_correlation_full(src_diff, diff_stride, bw, bh, &hor_corr, - &vert_corr); - fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr); - - double hdist[4] = { 0 }, vdist[4] = { 0 }; - get_energy_distribution_fine(cpi, plane_bsize, src, src_stride, dst, - dst_stride, 1, hdist, vdist); - fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2], - hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]); - - if (cpi->sf.inter_mode_rd_model_estimation == 1) { - assert(tile_data->inter_mode_rd_models[plane_bsize].ready); - const int64_t overall_sse = get_sse(cpi, x); - int est_residue_cost = 0; - int64_t est_dist = 0; - get_est_rate_dist(tile_data, plane_bsize, overall_sse, &est_residue_cost, - &est_dist); - const double est_residue_cost_norm = (double)est_residue_cost / num_samples; - const double est_dist_norm = (double)est_dist / num_samples; - const double est_rdcost_norm = - (double)RDCOST(x->rdmult, est_residue_cost, est_dist) / num_samples; - fprintf(fout, " %g %g %g", est_residue_cost_norm, est_dist_norm, - est_rdcost_norm); - } - - fprintf(fout, "\n"); - fclose(fout); -} -#endif // CONFIG_COLLECT_RD_STATS >= 2 -#endif // CONFIG_COLLECT_RD_STATS - -static AOM_INLINE void model_rd_with_dnn(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - const struct macroblock_plane *const p = &x->plane[plane]; - const int log_numpels = num_pels_log2_lookup[plane_bsize]; - - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int q_step = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1); - - int bw, bh; - get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw, - &bh); - const int src_stride = p->src.stride; - const uint8_t *const src = p->src.buf; - const int dst_stride = pd->dst.stride; - const uint8_t *const dst = pd->dst.buf; - const int16_t *const src_diff = p->src_diff; - const int diff_stride = block_size_wide[plane_bsize]; - const int shift = (xd->bd - 8); - - if (sse == 0) { - if (rate) *rate = 0; - if (dist) *dist = 0; - return; - } - if (plane) { - int model_rate; - int64_t model_dist; - model_rd_with_curvfit(cpi, x, plane_bsize, plane, sse, num_samples, - &model_rate, &model_dist); - if (rate) *rate = model_rate; - if (dist) *dist = model_dist; - return; - } - - aom_clear_system_state(); - const double sse_norm = (double)sse / num_samples; - - double sse_norm_arr[4]; - get_2x2_normalized_sses_and_sads(cpi, plane_bsize, src, src_stride, dst, - dst_stride, src_diff, diff_stride, - sse_norm_arr, NULL); - double mean; - if (is_cur_buf_hbd(xd)) { - mean = get_highbd_diff_mean(src, src_stride, dst, dst_stride, bw, bh); - } else { - mean = get_diff_mean(src, src_stride, dst, dst_stride, bw, bh); - } - if (shift) { - for (int k = 0; k < 4; ++k) sse_norm_arr[k] /= (1 << (2 * shift)); - mean /= (1 << shift); - } - double sse_norm_sum = 0.0, sse_frac_arr[3]; - for (int k = 0; k < 4; ++k) sse_norm_sum += sse_norm_arr[k]; - for (int k = 0; k < 3; ++k) - sse_frac_arr[k] = - sse_norm_sum > 0.0 ? sse_norm_arr[k] / sse_norm_sum : 0.25; - const double q_sqr = (double)(q_step * q_step); - const double q_sqr_by_sse_norm = q_sqr / (sse_norm + 1.0); - const double mean_sqr_by_sse_norm = mean * mean / (sse_norm + 1.0); - float hor_corr, vert_corr; - av1_get_horver_correlation_full(src_diff, diff_stride, bw, bh, &hor_corr, - &vert_corr); - - float features[NUM_FEATURES_PUSTATS]; - features[0] = (float)hor_corr; - features[1] = (float)log_numpels; - features[2] = (float)mean_sqr_by_sse_norm; - features[3] = (float)q_sqr_by_sse_norm; - features[4] = (float)sse_frac_arr[0]; - features[5] = (float)sse_frac_arr[1]; - features[6] = (float)sse_frac_arr[2]; - features[7] = (float)vert_corr; - - float rate_f, dist_by_sse_norm_f; - av1_nn_predict(features, &av1_pustats_dist_nnconfig, 1, &dist_by_sse_norm_f); - av1_nn_predict(features, &av1_pustats_rate_nnconfig, 1, &rate_f); - aom_clear_system_state(); - const float dist_f = (float)((double)dist_by_sse_norm_f * (1.0 + sse_norm)); - int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5); - int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5); - - // Check if skip is better - if (rate_i == 0) { - dist_i = sse << 4; - } else if (RDCOST(x->rdmult, rate_i, dist_i) >= - RDCOST(x->rdmult, 0, sse << 4)) { - rate_i = 0; - dist_i = sse << 4; - } - - if (rate) *rate = rate_i; - if (dist) *dist = dist_i; - return; -} - -static AOM_INLINE void model_rd_for_sb_with_dnn( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist) { - (void)mi_row; - (void)mi_col; - // Note our transform coeffs are 8 times an orthogonal transform. - // Hence quantizer step is also 8 times. To get effective quantizer - // we need to divide by 8 before sending to modeling function. - const int ref = xd->mi[0]->ref_frame[0]; - - int64_t rate_sum = 0; - int64_t dist_sum = 0; - int64_t total_sse = 0; - - for (int plane = plane_from; plane <= plane_to; ++plane) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - int64_t dist, sse; - int rate; - - if (x->skip_chroma_rd && plane) continue; - - const struct macroblock_plane *const p = &x->plane[plane]; - int bw, bh; - get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, - &bw, &bh); - sse = calculate_sse(xd, p, pd, bw, bh); - - model_rd_with_dnn(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, &dist); - - if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); - - total_sse += sse; - rate_sum += rate; - dist_sum += dist; - - if (plane_rate) plane_rate[plane] = rate; - if (plane_sse) plane_sse[plane] = sse; - if (plane_dist) plane_dist[plane] = dist; - } - - if (skip_txfm_sb) *skip_txfm_sb = rate_sum == 0; - if (skip_sse_sb) *skip_sse_sb = total_sse << 4; - *out_rate_sum = (int)rate_sum; - *out_dist_sum = dist_sum; -} - -// Fits a surface for rate and distortion using as features: -// log2(sse_norm + 1) and log2(sse_norm/qstep^2) -static AOM_INLINE void model_rd_with_surffit(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist) { - (void)cpi; - (void)plane_bsize; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int qstep = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1); - if (sse == 0) { - if (rate) *rate = 0; - if (dist) *dist = 0; - return; - } - aom_clear_system_state(); - const double sse_norm = (double)sse / num_samples; - const double qstepsqr = (double)qstep * qstep; - const double xm = log(sse_norm + 1.0) / log(2.0); - const double yl = log(sse_norm / qstepsqr) / log(2.0); - double rate_f, dist_by_sse_norm_f; - - av1_model_rd_surffit(plane_bsize, sse_norm, xm, yl, &rate_f, - &dist_by_sse_norm_f); - - const double dist_f = dist_by_sse_norm_f * sse_norm; - int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5); - int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5); - aom_clear_system_state(); - - // Check if skip is better - if (rate_i == 0) { - dist_i = sse << 4; - } else if (RDCOST(x->rdmult, rate_i, dist_i) >= - RDCOST(x->rdmult, 0, sse << 4)) { - rate_i = 0; - dist_i = sse << 4; - } - - if (rate) *rate = rate_i; - if (dist) *dist = dist_i; -} - -static AOM_INLINE void model_rd_for_sb_with_surffit( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist) { - (void)mi_row; - (void)mi_col; - // Note our transform coeffs are 8 times an orthogonal transform. - // Hence quantizer step is also 8 times. To get effective quantizer - // we need to divide by 8 before sending to modeling function. - const int ref = xd->mi[0]->ref_frame[0]; - - int64_t rate_sum = 0; - int64_t dist_sum = 0; - int64_t total_sse = 0; - - for (int plane = plane_from; plane <= plane_to; ++plane) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - int64_t dist, sse; - int rate; - - if (x->skip_chroma_rd && plane) continue; - - int bw, bh; - const struct macroblock_plane *const p = &x->plane[plane]; - get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, - &bw, &bh); - sse = calculate_sse(xd, p, pd, bw, bh); - - model_rd_with_surffit(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, - &dist); - - if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); - - total_sse += sse; - rate_sum += rate; - dist_sum += dist; - - if (plane_rate) plane_rate[plane] = rate; - if (plane_sse) plane_sse[plane] = sse; - if (plane_dist) plane_dist[plane] = dist; - } - - if (skip_txfm_sb) *skip_txfm_sb = rate_sum == 0; - if (skip_sse_sb) *skip_sse_sb = total_sse << 4; - *out_rate_sum = (int)rate_sum; - *out_dist_sum = dist_sum; -} - -// Fits a curve for rate and distortion using as feature: -// log2(sse_norm/qstep^2) -static AOM_INLINE void model_rd_with_curvfit(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - BLOCK_SIZE plane_bsize, int plane, - int64_t sse, int num_samples, - int *rate, int64_t *dist) { - (void)cpi; - (void)plane_bsize; - const MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblock_plane *const p = &x->plane[plane]; - const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; - const int qstep = AOMMAX(p->dequant_QTX[1] >> dequant_shift, 1); - - if (sse == 0) { - if (rate) *rate = 0; - if (dist) *dist = 0; - return; - } - aom_clear_system_state(); - const double sse_norm = (double)sse / num_samples; - const double qstepsqr = (double)qstep * qstep; - 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, - &dist_by_sse_norm_f); - - const double dist_f = dist_by_sse_norm_f * sse_norm; - int rate_i = (int)(AOMMAX(0.0, rate_f * num_samples) + 0.5); - int64_t dist_i = (int64_t)(AOMMAX(0.0, dist_f * num_samples) + 0.5); - aom_clear_system_state(); - - // Check if skip is better - if (rate_i == 0) { - dist_i = sse << 4; - } else if (RDCOST(x->rdmult, rate_i, dist_i) >= - RDCOST(x->rdmult, 0, sse << 4)) { - rate_i = 0; - dist_i = sse << 4; - } - - if (rate) *rate = rate_i; - if (dist) *dist = dist_i; -} - -static AOM_INLINE void model_rd_for_sb_with_curvfit( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist) { - (void)mi_row; - (void)mi_col; - // Note our transform coeffs are 8 times an orthogonal transform. - // Hence quantizer step is also 8 times. To get effective quantizer - // we need to divide by 8 before sending to modeling function. - const int ref = xd->mi[0]->ref_frame[0]; - - int64_t rate_sum = 0; - int64_t dist_sum = 0; - int64_t total_sse = 0; - - for (int plane = plane_from; plane <= plane_to; ++plane) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - int64_t dist, sse; - int rate; - - if (x->skip_chroma_rd && plane) continue; - - int bw, bh; - const struct macroblock_plane *const p = &x->plane[plane]; - get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, - &bw, &bh); - - sse = calculate_sse(xd, p, pd, bw, bh); - model_rd_with_curvfit(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, - &dist); - - if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); - - total_sse += sse; - rate_sum += rate; - dist_sum += dist; - - if (plane_rate) plane_rate[plane] = rate; - if (plane_sse) plane_sse[plane] = sse; - if (plane_dist) plane_dist[plane] = dist; - } - - if (skip_txfm_sb) *skip_txfm_sb = rate_sum == 0; - if (skip_sse_sb) *skip_sse_sb = total_sse << 4; - *out_rate_sum = (int)rate_sum; - *out_dist_sum = dist_sum; -} - -static int64_t search_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, - int block, int blk_row, int blk_col, - 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, 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]; - MB_MODE_INFO *mbmi = xd->mi[0]; - const int is_inter = is_inter_block(mbmi); - int64_t best_rd = INT64_MAX; - uint16_t best_eob = 0; - TX_TYPE best_tx_type = DCT_DCT; - TX_TYPE last_tx_type = TX_TYPES; - const int fast_tx_search = ftxs_mode & FTXS_DCT_AND_1D_DCT_ONLY; - // The buffer used to swap dqcoeff in macroblockd_plane so we can keep dqcoeff - // of the best tx_type - DECLARE_ALIGNED(32, tran_low_t, this_dqcoeff[MAX_SB_SQUARE]); - tran_low_t *orig_dqcoeff = pd->dqcoeff; - tran_low_t *best_dqcoeff = this_dqcoeff; - const int tx_type_map_idx = - plane ? 0 : blk_row * xd->tx_type_map_stride + blk_col; - int perform_block_coeff_opt = 0; - av1_invalid_rd_stats(best_rd_stats); - - TXB_RD_INFO *intra_txb_rd_info = NULL; - uint16_t cur_joint_ctx = 0; - 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); - const int within_border = - mi_row >= xd->tile.mi_row_start && - (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]) { - const uint32_t intra_hash = - get_intra_txb_hash(x, plane, blk_row, blk_col, plane_bsize, tx_size); - const int intra_hash_idx = - find_tx_size_rd_info(&x->txb_rd_record_intra, intra_hash); - intra_txb_rd_info = &x->txb_rd_record_intra.tx_rd_info[intra_hash_idx]; - - cur_joint_ctx = (txb_ctx->dc_sign_ctx << 8) + txb_ctx->txb_skip_ctx; - if (intra_txb_rd_info->entropy_context == cur_joint_ctx && - x->txb_rd_record_intra.tx_rd_info[intra_hash_idx].valid) { - xd->tx_type_map[tx_type_map_idx] = intra_txb_rd_info->tx_type; - const TX_TYPE ref_tx_type = - av1_get_tx_type(xd, get_plane_type(plane), blk_row, blk_col, tx_size, - cpi->common.reduced_tx_set_used); - if (ref_tx_type == intra_txb_rd_info->tx_type) { - best_rd_stats->rate = intra_txb_rd_info->rate; - best_rd_stats->dist = intra_txb_rd_info->dist; - best_rd_stats->sse = intra_txb_rd_info->sse; - best_rd_stats->skip = intra_txb_rd_info->eob == 0; - x->plane[plane].eobs[block] = intra_txb_rd_info->eob; - x->plane[plane].txb_entropy_ctx[block] = - intra_txb_rd_info->txb_entropy_ctx; - best_rd = RDCOST(x->rdmult, best_rd_stats->rate, best_rd_stats->dist); - best_eob = intra_txb_rd_info->eob; - best_tx_type = intra_txb_rd_info->tx_type; - perform_block_coeff_opt = intra_txb_rd_info->perform_block_coeff_opt; - update_txk_array(xd, blk_row, blk_col, tx_size, best_tx_type); - goto RECON_INTRA; - } - } - } - - int rate_cost = 0; - // if txk_allowed = TX_TYPES, >1 tx types are allowed, else, if txk_allowed < - // TX_TYPES, only that specific tx type is allowed. - TX_TYPE txk_allowed = TX_TYPES; - int txk_map[TX_TYPES] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - }; - - if ((!is_inter && x->use_default_intra_tx_type) || - (is_inter && x->use_default_inter_tx_type)) { - txk_allowed = - get_default_tx_type(0, xd, tx_size, cpi->is_screen_content_type); - } else if (x->rd_model == LOW_TXFM_RD) { - if (plane == 0) txk_allowed = DCT_DCT; - } - - uint8_t best_txb_ctx = 0; - const TxSetType tx_set_type = - av1_get_ext_tx_set_type(tx_size, is_inter, cm->reduced_tx_set_used); - - TX_TYPE uv_tx_type = DCT_DCT; - if (plane) { - // tx_type of PLANE_TYPE_UV should be the same as PLANE_TYPE_Y - uv_tx_type = txk_allowed = - av1_get_tx_type(xd, get_plane_type(plane), blk_row, blk_col, tx_size, - cm->reduced_tx_set_used); - } - PREDICTION_MODE intra_dir = - mbmi->filter_intra_mode_info.use_filter_intra - ? fimode_to_intradir[mbmi->filter_intra_mode_info.filter_intra_mode] - : mbmi->mode; - const uint16_t ext_tx_used_flag = - cpi->sf.tx_type_search.use_reduced_intra_txset && - tx_set_type == EXT_TX_SET_DTT4_IDTX_1DDCT - ? av1_reduced_intra_tx_used_flag[intra_dir] - : av1_ext_tx_used_flag[tx_set_type]; - if (xd->lossless[mbmi->segment_id] || txsize_sqr_up_map[tx_size] > TX_32X32 || - ext_tx_used_flag == 0x0001 || - (is_inter && cpi->oxcf.use_inter_dct_only) || - (!is_inter && cpi->oxcf.use_intra_dct_only)) { - txk_allowed = DCT_DCT; - } - uint16_t allowed_tx_mask = 0; // 1: allow; 0: skip. - if (txk_allowed < TX_TYPES) { - allowed_tx_mask = 1 << txk_allowed; - allowed_tx_mask &= ext_tx_used_flag; - } else if (fast_tx_search) { - allowed_tx_mask = 0x0c01; // V_DCT, H_DCT, DCT_DCT - allowed_tx_mask &= ext_tx_used_flag; - } else { - assert(plane == 0); - allowed_tx_mask = ext_tx_used_flag; - int num_allowed = 0; - const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); - const int *tx_type_probs = cpi->tx_type_probs[update_type][tx_size]; - int i; - - if (cpi->sf.tx_type_search.prune_tx_type_using_stats) { - const int thresh = cpi->tx_type_probs_thresh[update_type]; - uint16_t prune = 0; - int max_prob = -1; - int max_idx = 0; - for (i = 0; i < TX_TYPES; i++) { - if (tx_type_probs[i] > max_prob && (allowed_tx_mask & (1 << i))) { - max_prob = tx_type_probs[i]; - max_idx = i; - } - } - - for (i = 0; i < TX_TYPES; i++) { - if (tx_type_probs[i] < thresh && i != max_idx) prune |= (1 << i); - } - allowed_tx_mask &= (~prune); - } - - for (i = 0; i < TX_TYPES; i++) { - if (allowed_tx_mask & (1 << i)) num_allowed++; - } - assert(num_allowed > 0); - - // Go through ML model only if num_allowed > 5. - // !fast_tx_search && txk_end != txk_start && plane == 0 - if (cpi->sf.tx_type_search.prune_mode >= PRUNE_2D_ACCURATE && is_inter && - num_allowed > 5) { - const uint16_t prune = prune_tx_2D( - x, plane_bsize, tx_size, blk_row, blk_col, tx_set_type, - cpi->sf.tx_type_search.prune_mode, txk_map, allowed_tx_mask); - allowed_tx_mask &= (~prune); - } - } - - 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_allowed = (plane ? uv_tx_type : DCT_DCT); - allowed_tx_mask = (1 << txk_allowed); - } - - const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size]; - int64_t block_sse = 0; - unsigned int block_mse_q8 = UINT_MAX; - block_sse = pixel_diff_dist(x, plane, blk_row, blk_col, plane_bsize, tx_bsize, - &block_mse_q8); - assert(block_mse_q8 != UINT_MAX); - if (is_cur_buf_hbd(xd)) { - block_sse = ROUND_POWER_OF_TWO(block_sse, (xd->bd - 8) * 2); - block_mse_q8 = ROUND_POWER_OF_TWO(block_mse_q8, (xd->bd - 8) * 2); - } - block_sse *= 16; - // Tranform domain distortion is accurate for higher residuals. - // TODO(any): Experiment with variance and mean based thresholds - int use_transform_domain_distortion = - (x->use_transform_domain_distortion > 0) && - (block_mse_q8 >= x->tx_domain_dist_threshold) && - // Any 64-pt transforms only preserves half the coefficients. - // Therefore transform domain distortion is not valid for these - // transform sizes. - txsize_sqr_up_map[tx_size] != TX_64X64; -#if CONFIG_DIST_8X8 - if (x->using_dist_8x8) use_transform_domain_distortion = 0; -#endif - int calc_pixel_domain_distortion_final = - x->use_transform_domain_distortion == 1 && - use_transform_domain_distortion && x->rd_model != LOW_TXFM_RD; - if (calc_pixel_domain_distortion_final && - (txk_allowed < TX_TYPES || allowed_tx_mask == 0x0001)) - calc_pixel_domain_distortion_final = use_transform_domain_distortion = 0; - - 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 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 <= x->coeff_opt_dist_threshold); - - assert(IMPLIES(txk_allowed < TX_TYPES, allowed_tx_mask == 1 << txk_allowed)); - - for (int idx = 0; idx < TX_TYPES; ++idx) { - const TX_TYPE tx_type = (TX_TYPE)txk_map[idx]; - if (!(allowed_tx_mask & (1 << tx_type))) continue; - if (plane == 0) xd->tx_type_map[tx_type_map_idx] = tx_type; - RD_STATS this_rd_stats; - av1_invalid_rd_stats(&this_rd_stats); - 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); - rate_cost = - av1_cost_coeffs(x, plane, block, tx_size, tx_type, txb_ctx, - use_fast_coef_costing, cm->reduced_tx_set_used); - } else { - av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize, - tx_size, tx_type, AV1_XFORM_QUANT_FP); - if (cpi->sf.optimize_b_precheck && best_rd < INT64_MAX && - eobs_ptr[block] >= 4) { - // Calculate distortion quickly in transform domain. - dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, - &this_rd_stats.sse); - - const int64_t best_rd_ = AOMMIN(best_rd, ref_best_rd); - const int64_t dist_cost_estimate = - 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, - cpi->sf.trellis_eob_fast, &rate_cost); - } - // If rd cost based on coeff rate is more than best_rd, skip the calculation - // of distortion - int64_t tmp_rd = RDCOST(x->rdmult, rate_cost, 0); - if (tmp_rd > best_rd) continue; - if (eobs_ptr[block] == 0) { - // When eob is 0, pixel domain distortion is more efficient and accurate. - this_rd_stats.dist = this_rd_stats.sse = block_sse; - } else if (use_transform_domain_distortion) { - dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, - &this_rd_stats.sse); - } else { - 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; - } - - this_rd_stats.rate = rate_cost; - - const int64_t rd = - RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); - - if (rd < best_rd) { - best_rd = rd; - *best_rd_stats = this_rd_stats; - best_tx_type = tx_type; - best_txb_ctx = x->plane[plane].txb_entropy_ctx[block]; - best_eob = x->plane[plane].eobs[block]; - last_tx_type = best_tx_type; - - // Swap qcoeff and dqcoeff buffers - tran_low_t *const tmp_dqcoeff = best_dqcoeff; - best_dqcoeff = pd->dqcoeff; - pd->dqcoeff = tmp_dqcoeff; - } - -#if CONFIG_COLLECT_RD_STATS == 1 - if (plane == 0) { - PrintTransformUnitStats(cpi, x, &this_rd_stats, blk_row, blk_col, - plane_bsize, tx_size, tx_type, rd); - } -#endif // CONFIG_COLLECT_RD_STATS == 1 - -#if COLLECT_TX_SIZE_DATA - // Generate small sample to restrict output size. - static unsigned int seed = 21743; - if (lcg_rand16(&seed) % 200 == 0) { - FILE *fp = NULL; - - if (within_border) { - fp = fopen(av1_tx_size_data_output_file, "a"); - } - - if (fp) { - // Transform info and RD - const int txb_w = tx_size_wide[tx_size]; - const int txb_h = tx_size_high[tx_size]; - - // Residue signal. - const int diff_stride = block_size_wide[plane_bsize]; - struct macroblock_plane *const p = &x->plane[plane]; - const int16_t *src_diff = - &p->src_diff[(blk_row * diff_stride + blk_col) * 4]; - - for (int r = 0; r < txb_h; ++r) { - for (int c = 0; c < txb_w; ++c) { - fprintf(fp, "%d,", src_diff[c]); - } - src_diff += diff_stride; - } - - fprintf(fp, "%d,%d,%d,%" PRId64, txb_w, txb_h, tx_type, rd); - fprintf(fp, "\n"); - fclose(fp); - } - } -#endif // COLLECT_TX_SIZE_DATA - - if (cpi->sf.adaptive_txb_search_level) { - if ((best_rd - (best_rd >> cpi->sf.adaptive_txb_search_level)) > - ref_best_rd) { - break; - } - } - - // Skip transform type search when we found the block has been quantized to - // all zero and at the same time, it has better rdcost than doing transform. - if (cpi->sf.tx_type_search.skip_tx_search && !best_eob) break; - } - - assert(best_rd != INT64_MAX); - - best_rd_stats->skip = best_eob == 0; - if (plane == 0) update_txk_array(xd, blk_row, blk_col, tx_size, best_tx_type); - x->plane[plane].txb_entropy_ctx[block] = best_txb_ctx; - x->plane[plane].eobs[block] = best_eob; - - pd->dqcoeff = best_dqcoeff; - - if (calc_pixel_domain_distortion_final && best_eob) { - best_rd_stats->dist = dist_block_px_domain( - cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size); - best_rd_stats->sse = block_sse; - } - - if (intra_txb_rd_info != NULL) { - intra_txb_rd_info->valid = 1; - intra_txb_rd_info->entropy_context = cur_joint_ctx; - intra_txb_rd_info->rate = best_rd_stats->rate; - intra_txb_rd_info->dist = best_rd_stats->dist; - intra_txb_rd_info->sse = best_rd_stats->sse; - intra_txb_rd_info->eob = best_eob; - intra_txb_rd_info->txb_entropy_ctx = best_txb_ctx; - intra_txb_rd_info->perform_block_coeff_opt = perform_block_coeff_opt; - if (plane == 0) intra_txb_rd_info->tx_type = best_tx_type; - } - -RECON_INTRA: - if (!is_inter && best_eob && - (blk_row + tx_size_high_unit[tx_size] < mi_size_high[plane_bsize] || - blk_col + tx_size_wide_unit[tx_size] < mi_size_wide[plane_bsize])) { - // intra mode needs decoded result such that the next transform block - // can use it for prediction. - // 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 (skip_trellis || (!perform_block_coeff_opt)) { - av1_xform_quant( - cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, - best_tx_type, - USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP); - } 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, - cpi->sf.trellis_eob_fast, &rate_cost); - } - } - - inverse_transform_block_facade(xd, plane, block, blk_row, blk_col, - x->plane[plane].eobs[block], - cm->reduced_tx_set_used); - - // This may happen because of hash collision. The eob stored in the hash - // table is non-zero, but the real eob is zero. We need to make sure tx_type - // is DCT_DCT in this case. - if (plane == 0 && x->plane[plane].eobs[block] == 0 && - best_tx_type != DCT_DCT) { - update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); - } - } - pd->dqcoeff = orig_dqcoeff; - - return best_rd; -} - -static AOM_INLINE void block_rd_txfm(int plane, int block, int blk_row, - int blk_col, BLOCK_SIZE plane_bsize, - TX_SIZE tx_size, void *arg) { - struct rdcost_block_args *args = arg; - MACROBLOCK *const x = args->x; - MACROBLOCKD *const xd = &x->e_mbd; - const int is_inter = is_inter_block(xd->mi[0]); - const AV1_COMP *cpi = args->cpi; - ENTROPY_CONTEXT *a = args->t_above + blk_col; - ENTROPY_CONTEXT *l = args->t_left + blk_row; - const AV1_COMMON *cm = &cpi->common; - RD_STATS this_rd_stats; - - av1_init_rd_stats(&this_rd_stats); - - if (args->exit_early) { - args->incomplete_exit = 1; - return; - } - - if (!is_inter) { - av1_predict_intra_block_facade(cm, xd, plane, blk_col, blk_row, tx_size); - av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size); - } - TXB_CTX txb_ctx; - 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->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); - cfl_store_tx(xd, blk_row, blk_col, tx_size, plane_bsize); - } - -#if CONFIG_RD_DEBUG - av1_update_txb_coeff_cost(&this_rd_stats, plane, tx_size, blk_row, blk_col, - this_rd_stats.rate); -#endif // CONFIG_RD_DEBUG - av1_set_txb_context(x, plane, block, tx_size, a, l); - - const int blk_idx = - blk_row * (block_size_wide[plane_bsize] >> tx_size_wide_log2[0]) + - blk_col; - - if (plane == 0) - set_blk_skip(x, plane, blk_idx, x->plane[plane].eobs[block] == 0); - else - set_blk_skip(x, plane, blk_idx, 0); - - int64_t rd; - if (is_inter) { - const int64_t rd1 = - RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); - const int64_t rd2 = RDCOST(x->rdmult, 0, this_rd_stats.sse); - - // TODO(jingning): temporarily enabled only for luma component - rd = AOMMIN(rd1, rd2); - this_rd_stats.skip &= !x->plane[plane].eobs[block]; - } else { - // Signal non-skip for Intra blocks - rd = RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); - this_rd_stats.skip = 0; - } - - av1_merge_rd_stats(&args->rd_stats, &this_rd_stats); - - args->this_rd += rd; - - if (args->this_rd > args->best_rd) args->exit_early = 1; -} - -static AOM_INLINE 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, - int skip_trellis) { - MACROBLOCKD *const xd = &x->e_mbd; - const struct macroblockd_plane *const pd = &xd->plane[plane]; - struct rdcost_block_args args; - av1_zero(args); - args.x = x; - args.cpi = cpi; - args.best_rd = ref_best_rd; - 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) { - av1_invalid_rd_stats(rd_stats); - return; - } - - if (plane == 0) xd->mi[0]->tx_size = tx_size; - - av1_get_entropy_contexts(bsize, pd, args.t_above, args.t_left); - - if (args.this_rd > args.best_rd) { - args.exit_early = 1; - } - - av1_foreach_transformed_block_in_plane(xd, bsize, plane, block_rd_txfm, - &args); - - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int is_inter = is_inter_block(mbmi); - const int invalid_rd = is_inter ? args.incomplete_exit : args.exit_early; - - if (invalid_rd) { - av1_invalid_rd_stats(rd_stats); - } else { - *rd_stats = args.rd_stats; - } -} - -static int tx_size_cost(const MACROBLOCK *const x, BLOCK_SIZE bsize, - TX_SIZE tx_size) { - assert(bsize == x->e_mbd.mi[0]->sb_type); - if (x->tx_mode != TX_MODE_SELECT || !block_signals_txsize(bsize)) return 0; - - const int32_t tx_size_cat = bsize_to_tx_size_cat(bsize); - const int depth = tx_size_to_depth(tx_size, bsize); - const MACROBLOCKD *const xd = &x->e_mbd; - const int tx_size_ctx = get_tx_size_context(xd); - return x->tx_size_cost[tx_size_cat][tx_size_ctx][depth]; -} - -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, - int skip_trellis) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - int64_t rd = INT64_MAX; - const int skip_ctx = av1_get_skip_context(xd); - int s0, s1; - const int is_inter = is_inter_block(mbmi); - const int tx_select = - x->tx_mode == TX_MODE_SELECT && block_signals_txsize(mbmi->sb_type); - int ctx = txfm_partition_context( - xd->above_txfm_context, xd->left_txfm_context, mbmi->sb_type, tx_size); - const int r_tx_size = - is_inter ? x->txfm_partition_cost[ctx][0] : tx_size_cost(x, bs, tx_size); - - assert(IMPLIES(is_rect_tx(tx_size), is_rect_tx_allowed_bsize(bs))); - - s0 = x->skip_cost[skip_ctx][0]; - s1 = x->skip_cost[skip_ctx][1]; - - int64_t skip_rd = INT64_MAX; - int64_t this_rd = RDCOST(x->rdmult, s0 + r_tx_size * tx_select, 0); - - if (is_inter) skip_rd = RDCOST(x->rdmult, s1, 0); - - 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, 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 - // same is accounted in the caller functions after rd evaluation of all - // planes. However the decisions should be done after considering the - // skip/non-skip header cost - if (rd_stats->skip && is_inter) { - rd = RDCOST(x->rdmult, s1, rd_stats->sse); - } else { - // Intra blocks are always signalled as non-skip - rd = RDCOST(x->rdmult, rd_stats->rate + s0 + r_tx_size * tx_select, - rd_stats->dist); - rd_stats->rate += r_tx_size * tx_select; - } - if (is_inter && !xd->lossless[xd->mi[0]->segment_id]) { - int64_t temp_skip_rd = RDCOST(x->rdmult, s1, rd_stats->sse); - if (temp_skip_rd <= rd) { - rd = temp_skip_rd; - rd_stats->rate = 0; - rd_stats->dist = rd_stats->sse; - rd_stats->skip = 1; - } - } - - return rd; -} - -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; - if (ref_best_rd < 0) return INT64_MAX; - av1_subtract_plane(x, bs, 0); - x->rd_model = LOW_TXFM_RD; - 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) { - const int skip_ctx = av1_get_skip_context(xd); - if (rd_stats->skip) { - const int s1 = x->skip_cost[skip_ctx][1]; - rd_stats->rate = s1; - } else { - const int s0 = x->skip_cost[skip_ctx][0]; - rd_stats->rate += s0; - } - } - return rd; -} - -static AOM_INLINE void choose_largest_tx_size(const AV1_COMP *const cpi, - MACROBLOCK *x, RD_STATS *rd_stats, - int64_t ref_best_rd, - BLOCK_SIZE bs) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - mbmi->tx_size = tx_size_from_tx_mode(bs, x->tx_mode); - const int skip_ctx = av1_get_skip_context(xd); - int s0, s1; - - s0 = x->skip_cost[skip_ctx][0]; - s1 = x->skip_cost[skip_ctx][1]; - - int64_t skip_rd = INT64_MAX; - int64_t this_rd = RDCOST(x->rdmult, s0, 0); - - // Skip RDcost is used only for Inter blocks - if (is_inter_block(xd->mi[0])) skip_rd = RDCOST(x->rdmult, s1, 0); - - 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, 0); -} - -static AOM_INLINE void choose_smallest_tx_size(const AV1_COMP *const cpi, - MACROBLOCK *x, - RD_STATS *rd_stats, - int64_t ref_best_rd, - BLOCK_SIZE bs) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - - 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, 0); -} - -static INLINE int bsize_to_num_blk(BLOCK_SIZE bsize) { - int num_blk = 1 << (num_pels_log2_lookup[bsize] - 2 * tx_size_wide_log2[0]); - return num_blk; -} - -static int get_search_init_depth(int mi_width, int mi_height, int is_inter, - const SPEED_FEATURES *sf, - int tx_size_search_method) { - if (tx_size_search_method == USE_LARGESTALL) return MAX_VARTX_DEPTH; - - if (sf->tx_size_search_lgr_block) { - if (mi_width > mi_size_wide[BLOCK_64X64] || - mi_height > mi_size_high[BLOCK_64X64]) - return MAX_VARTX_DEPTH; - } - - if (is_inter) { - return (mi_height != mi_width) ? sf->inter_tx_size_search_init_depth_rect - : sf->inter_tx_size_search_init_depth_sqr; - } else { - return (mi_height != mi_width) ? sf->intra_tx_size_search_init_depth_rect - : sf->intra_tx_size_search_init_depth_sqr; - } -} - -static AOM_INLINE void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, - MACROBLOCK *x, - RD_STATS *rd_stats, - int64_t ref_best_rd, - BLOCK_SIZE bs) { - av1_invalid_rd_stats(rd_stats); - - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const TX_SIZE max_rect_tx_size = max_txsize_rect_lookup[bs]; - const int tx_select = x->tx_mode == TX_MODE_SELECT; - int start_tx; - int depth, init_depth; - - if (tx_select) { - start_tx = max_rect_tx_size; - init_depth = get_search_init_depth(mi_size_wide[bs], mi_size_high[bs], - is_inter_block(mbmi), &cpi->sf, - x->tx_size_search_method); - } else { - const TX_SIZE chosen_tx_size = tx_size_from_tx_mode(bs, x->tx_mode); - start_tx = chosen_tx_size; - init_depth = MAX_TX_DEPTH; - } - - uint8_t best_txk_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; - TX_SIZE best_tx_size = max_rect_tx_size; - 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 - if (x->using_dist_8x8) { - if (tx_size_wide[n] < 8 || tx_size_high[n] < 8) continue; - } -#endif - if (!cpi->oxcf.enable_tx64 && txsize_sqr_up_map[n] == TX_64X64) continue; - - RD_STATS this_rd_stats; - rd[depth] = - txfm_yrd(cpi, x, &this_rd_stats, ref_best_rd, bs, n, FTXS_NONE, 0); - - if (rd[depth] < best_rd) { - av1_copy_array(best_blk_skip, x->blk_skip, n4); - av1_copy_array(best_txk_type_map, xd->tx_type_map, n4); - best_tx_size = n; - 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) { - mbmi->tx_size = best_tx_size; - av1_copy_array(xd->tx_type_map, best_txk_type_map, n4); - av1_copy_array(x->blk_skip, best_blk_skip, n4); - } -} - -// 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 AOM_INLINE 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(xd->tx_type_map, DCT_DCT, sizeof(xd->tx_type_map[0]) * n4); - 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 AOM_INLINE 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_array(tx_rd_info->tx_type_map, xd->tx_type_map, n4); - tx_rd_info->rd_stats = *rd_stats; -} - -static AOM_INLINE 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_array(xd->tx_type_map, tx_rd_info->tx_type_map, n4); - *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 AOM_INLINE 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); - 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); - return; - } - - if (xd->lossless[xd->mi[0]->segment_id]) { - choose_smallest_tx_size(cpi, x, rd_stats, ref_best_rd, bs); - } else if (x->tx_size_search_method == USE_LARGESTALL) { - choose_largest_tx_size(cpi, x, rd_stats, ref_best_rd, bs); - } 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. -static int intra_mode_info_cost_y(const AV1_COMP *cpi, const MACROBLOCK *x, - const MB_MODE_INFO *mbmi, BLOCK_SIZE bsize, - int mode_cost) { - int total_rate = mode_cost; - const int use_palette = mbmi->palette_mode_info.palette_size[0] > 0; - const int use_filter_intra = mbmi->filter_intra_mode_info.use_filter_intra; - const int use_intrabc = mbmi->use_intrabc; - // Can only activate one mode. - assert(((mbmi->mode != DC_PRED) + use_palette + use_intrabc + - use_filter_intra) <= 1); - const int try_palette = - av1_allow_palette(cpi->common.allow_screen_content_tools, mbmi->sb_type); - if (try_palette && mbmi->mode == DC_PRED) { - const MACROBLOCKD *xd = &x->e_mbd; - const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); - const int mode_ctx = av1_get_palette_mode_ctx(xd); - total_rate += x->palette_y_mode_cost[bsize_ctx][mode_ctx][use_palette]; - if (use_palette) { - const uint8_t *const color_map = xd->plane[0].color_index_map; - int block_width, block_height, rows, cols; - av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, - &cols); - const int plt_size = mbmi->palette_mode_info.palette_size[0]; - int palette_mode_cost = - x->palette_y_size_cost[bsize_ctx][plt_size - PALETTE_MIN_SIZE] + - write_uniform_cost(plt_size, color_map[0]); - uint16_t color_cache[2 * PALETTE_MAX_SIZE]; - const int n_cache = av1_get_palette_cache(xd, 0, color_cache); - palette_mode_cost += - av1_palette_color_cost_y(&mbmi->palette_mode_info, color_cache, - n_cache, cpi->common.seq_params.bit_depth); - palette_mode_cost += - av1_cost_color_map(x, 0, bsize, mbmi->tx_size, PALETTE_MAP); - total_rate += palette_mode_cost; - } - } - if (av1_filter_intra_allowed(&cpi->common, mbmi)) { - total_rate += x->filter_intra_cost[mbmi->sb_type][use_filter_intra]; - if (use_filter_intra) { - total_rate += x->filter_intra_mode_cost[mbmi->filter_intra_mode_info - .filter_intra_mode]; - } - } - if (av1_is_directional_mode(mbmi->mode)) { - if (av1_use_angle_delta(bsize)) { - total_rate += x->angle_delta_cost[mbmi->mode - V_PRED] - [MAX_ANGLE_DELTA + - mbmi->angle_delta[PLANE_TYPE_Y]]; - } - } - if (av1_allow_intrabc(&cpi->common)) - total_rate += x->intrabc_cost[use_intrabc]; - return total_rate; -} - -// Return the rate cost for chroma prediction mode info. of intra blocks. -static int intra_mode_info_cost_uv(const AV1_COMP *cpi, const MACROBLOCK *x, - const MB_MODE_INFO *mbmi, BLOCK_SIZE bsize, - int mode_cost) { - int total_rate = mode_cost; - const int use_palette = mbmi->palette_mode_info.palette_size[1] > 0; - const UV_PREDICTION_MODE mode = mbmi->uv_mode; - // Can only activate one mode. - assert(((mode != UV_DC_PRED) + use_palette + mbmi->use_intrabc) <= 1); - - const int try_palette = - av1_allow_palette(cpi->common.allow_screen_content_tools, mbmi->sb_type); - if (try_palette && mode == UV_DC_PRED) { - const PALETTE_MODE_INFO *pmi = &mbmi->palette_mode_info; - total_rate += - x->palette_uv_mode_cost[pmi->palette_size[0] > 0][use_palette]; - if (use_palette) { - const int bsize_ctx = av1_get_palette_bsize_ctx(bsize); - const int plt_size = pmi->palette_size[1]; - const MACROBLOCKD *xd = &x->e_mbd; - const uint8_t *const color_map = xd->plane[1].color_index_map; - int palette_mode_cost = - x->palette_uv_size_cost[bsize_ctx][plt_size - PALETTE_MIN_SIZE] + - write_uniform_cost(plt_size, color_map[0]); - uint16_t color_cache[2 * PALETTE_MAX_SIZE]; - const int n_cache = av1_get_palette_cache(xd, 1, color_cache); - palette_mode_cost += av1_palette_color_cost_uv( - pmi, color_cache, n_cache, cpi->common.seq_params.bit_depth); - palette_mode_cost += - av1_cost_color_map(x, 1, bsize, mbmi->tx_size, PALETTE_MAP); - total_rate += palette_mode_cost; - } - } - if (av1_is_directional_mode(get_uv_mode(mode))) { - if (av1_use_angle_delta(bsize)) { - total_rate += - x->angle_delta_cost[mode - V_PRED][mbmi->angle_delta[PLANE_TYPE_UV] + - MAX_ANGLE_DELTA]; - } - } - return total_rate; -} - static int conditional_skipintra(PREDICTION_MODE mode, PREDICTION_MODE best_intra_mode) { if (mode == D113_PRED && best_intra_mode != V_PRED && @@ -4359,2481 +701,6 @@ static int conditional_skipintra(PREDICTION_MODE mode, return 0; } -// Model based RD estimation for luma intra blocks. -static int64_t intra_model_yrd(const AV1_COMP *const cpi, MACROBLOCK *const x, - BLOCK_SIZE bsize, int mode_cost, int mi_row, - int mi_col) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - RD_STATS this_rd_stats; - int row, col; - int64_t temp_sse, this_rd; - TX_SIZE tx_size = tx_size_from_tx_mode(bsize, x->tx_mode); - const int stepr = tx_size_high_unit[tx_size]; - const int stepc = tx_size_wide_unit[tx_size]; - const int max_blocks_wide = max_block_wide(xd, bsize, 0); - const int max_blocks_high = max_block_high(xd, bsize, 0); - mbmi->tx_size = tx_size; - // Prediction. - for (row = 0; row < max_blocks_high; row += stepr) { - for (col = 0; col < max_blocks_wide; col += stepc) { - av1_predict_intra_block_facade(cm, xd, 0, col, row, tx_size); - } - } - // RD estimation. - model_rd_sb_fn[MODELRD_TYPE_INTRA]( - cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &this_rd_stats.rate, - &this_rd_stats.dist, &this_rd_stats.skip, &temp_sse, NULL, NULL, NULL); - if (av1_is_directional_mode(mbmi->mode) && av1_use_angle_delta(bsize)) { - mode_cost += - x->angle_delta_cost[mbmi->mode - V_PRED] - [MAX_ANGLE_DELTA + mbmi->angle_delta[PLANE_TYPE_Y]]; - } - if (mbmi->mode == DC_PRED && - av1_filter_intra_allowed_bsize(cm, mbmi->sb_type)) { - if (mbmi->filter_intra_mode_info.use_filter_intra) { - const int mode = mbmi->filter_intra_mode_info.filter_intra_mode; - mode_cost += x->filter_intra_cost[mbmi->sb_type][1] + - x->filter_intra_mode_cost[mode]; - } else { - mode_cost += x->filter_intra_cost[mbmi->sb_type][0]; - } - } - this_rd = - RDCOST(x->rdmult, this_rd_stats.rate + mode_cost, this_rd_stats.dist); - return this_rd; -} - -// Update the intra model yrd and prune the current mode if the new estimate -// y_rd > 1.5 * best_model_rd. -static AOM_INLINE int model_intra_yrd_and_prune(const AV1_COMP *const cpi, - MACROBLOCK *x, BLOCK_SIZE bsize, - int mi_row, int mi_col, - int mode_info_cost, - int64_t *best_model_rd) { - const int64_t this_model_rd = - intra_model_yrd(cpi, x, bsize, mode_info_cost, mi_row, mi_col); - if (*best_model_rd != INT64_MAX && - this_model_rd > *best_model_rd + (*best_model_rd >> 1)) { - return 1; - } else if (this_model_rd < *best_model_rd) { - *best_model_rd = this_model_rd; - } - return 0; -} - -// Extends 'color_map' array from 'orig_width x orig_height' to 'new_width x -// new_height'. Extra rows and columns are filled in by copying last valid -// row/column. -static AOM_INLINE void extend_palette_color_map(uint8_t *const color_map, - int orig_width, int orig_height, - int new_width, int new_height) { - int j; - assert(new_width >= orig_width); - assert(new_height >= orig_height); - if (new_width == orig_width && new_height == orig_height) return; - - for (j = orig_height - 1; j >= 0; --j) { - memmove(color_map + j * new_width, color_map + j * orig_width, orig_width); - // Copy last column to extra columns. - memset(color_map + j * new_width + orig_width, - color_map[j * new_width + orig_width - 1], new_width - orig_width); - } - // Copy last row to extra rows. - for (j = orig_height; j < new_height; ++j) { - memcpy(color_map + j * new_width, color_map + (orig_height - 1) * new_width, - new_width); - } -} - -// Bias toward using colors in the cache. -// TODO(huisu): Try other schemes to improve compression. -static AOM_INLINE void optimize_palette_colors(uint16_t *color_cache, - int n_cache, int n_colors, - int stride, int *centroids) { - if (n_cache <= 0) return; - for (int i = 0; i < n_colors * stride; i += stride) { - int min_diff = abs(centroids[i] - (int)color_cache[0]); - int idx = 0; - for (int j = 1; j < n_cache; ++j) { - const int this_diff = abs(centroids[i] - color_cache[j]); - if (this_diff < min_diff) { - min_diff = this_diff; - idx = j; - } - } - if (min_diff <= 1) centroids[i] = color_cache[idx]; - } -} - -// Store best mode stats for winner mode processing -static void store_winner_mode_stats(MACROBLOCK *x, MB_MODE_INFO *mbmi, - int enable_multiwinner_mode_process, - uint8_t *color_map, BLOCK_SIZE bsize, - int64_t this_rd) { - WinnerModeStats *winner_mode_stats = x->winner_mode_stats; - int mode_idx = 0; - // Mode stat is not required when multiwinner mode processing is disabled - if (!enable_multiwinner_mode_process) return; - - assert(x->winner_mode_count >= 0 && - x->winner_mode_count <= MAX_WINNER_MODE_COUNT); - - if (x->winner_mode_count) { - // Find the mode which has higher rd cost than this_rd - for (mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++) - if (winner_mode_stats[mode_idx].rd > this_rd) break; - - if (mode_idx == MAX_WINNER_MODE_COUNT) { - // No mode has higher rd cost than this_rd - return; - } else if (mode_idx < MAX_WINNER_MODE_COUNT - 1) { - // Create a slot for current mode and move others to the next slot - memmove( - &winner_mode_stats[mode_idx + 1], &winner_mode_stats[mode_idx], - (MAX_WINNER_MODE_COUNT - mode_idx - 1) * sizeof(*winner_mode_stats)); - } - } - // Add a mode stat for winner mode processing - winner_mode_stats[mode_idx].mbmi = *mbmi; - winner_mode_stats[mode_idx].rd = this_rd; - if (color_map) { - // Store color_index_map for palette mode - const MACROBLOCKD *const xd = &x->e_mbd; - int block_width, block_height; - av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width, - &block_height, NULL, NULL); - memcpy(winner_mode_stats[mode_idx].color_index_map, color_map, - block_width * block_height * sizeof(color_map[0])); - } - - x->winner_mode_count = - AOMMIN(x->winner_mode_count + 1, MAX_WINNER_MODE_COUNT); -} - -// Given the base colors as specified in centroids[], calculate the RD cost -// of palette mode. -static AOM_INLINE void palette_rd_y( - const AV1_COMP *const cpi, MACROBLOCK *x, MB_MODE_INFO *mbmi, - BLOCK_SIZE bsize, int mi_row, int mi_col, int dc_mode_cost, const int *data, - int *centroids, int n, uint16_t *color_cache, int n_cache, - MB_MODE_INFO *best_mbmi, uint8_t *best_palette_color_map, int64_t *best_rd, - int64_t *best_model_rd, int *rate, int *rate_tokenonly, int *rate_overhead, - int64_t *distortion, int *skippable, int *beat_best_rd, - PICK_MODE_CONTEXT *ctx, uint8_t *blk_skip, uint8_t *tx_type_map) { - optimize_palette_colors(color_cache, n_cache, n, 1, centroids); - int k = av1_remove_duplicates(centroids, n); - if (k < PALETTE_MIN_SIZE) { - // Too few unique colors to create a palette. And DC_PRED will work - // well for that case anyway. So skip. - return; - } - PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; - if (cpi->common.seq_params.use_highbitdepth) - for (int i = 0; i < k; ++i) - pmi->palette_colors[i] = clip_pixel_highbd( - (int)centroids[i], cpi->common.seq_params.bit_depth); - else - for (int i = 0; i < k; ++i) - pmi->palette_colors[i] = clip_pixel(centroids[i]); - pmi->palette_size[0] = k; - MACROBLOCKD *const xd = &x->e_mbd; - uint8_t *const color_map = xd->plane[0].color_index_map; - int block_width, block_height, rows, cols; - av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, - &cols); - av1_calc_indices(data, centroids, color_map, rows * cols, k, 1); - extend_palette_color_map(color_map, cols, rows, block_width, block_height); - - const int palette_mode_cost = - intra_mode_info_cost_y(cpi, x, mbmi, bsize, dc_mode_cost); - if (model_intra_yrd_and_prune(cpi, x, bsize, mi_row, mi_col, - palette_mode_cost, best_model_rd)) { - return; - } - - RD_STATS tokenonly_rd_stats; - super_block_yrd(cpi, x, &tokenonly_rd_stats, bsize, *best_rd); - if (tokenonly_rd_stats.rate == INT_MAX) return; - int this_rate = tokenonly_rd_stats.rate + palette_mode_cost; - int64_t this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(mbmi->sb_type)) { - tokenonly_rd_stats.rate -= tx_size_cost(x, bsize, mbmi->tx_size); - } - // Collect mode stats for multiwinner mode processing - store_winner_mode_stats(x, mbmi, cpi->sf.enable_multiwinner_mode_process, - color_map, bsize, this_rd); - if (this_rd < *best_rd) { - *best_rd = this_rd; - // Setting beat_best_rd flag because current mode rd is better than best_rd. - // This flag need to be updated only for palette evaluation in key frames - if (beat_best_rd) *beat_best_rd = 1; - memcpy(best_palette_color_map, color_map, - block_width * block_height * sizeof(color_map[0])); - *best_mbmi = *mbmi; - memcpy(blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - av1_copy_array(tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - *rate_overhead = this_rate - tokenonly_rd_stats.rate; - if (rate) *rate = this_rate; - if (rate_tokenonly) *rate_tokenonly = tokenonly_rd_stats.rate; - if (distortion) *distortion = tokenonly_rd_stats.dist; - if (skippable) *skippable = tokenonly_rd_stats.skip; - } -} - -static int rd_pick_palette_intra_sby( - const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, - int mi_col, int dc_mode_cost, MB_MODE_INFO *best_mbmi, - uint8_t *best_palette_color_map, int64_t *best_rd, int64_t *best_model_rd, - int *rate, int *rate_tokenonly, int64_t *distortion, int *skippable, - int *beat_best_rd, PICK_MODE_CONTEXT *ctx, uint8_t *best_blk_skip, - uint8_t *tx_type_map) { - int rate_overhead = 0; - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - assert(av1_allow_palette(cpi->common.allow_screen_content_tools, bsize)); - const SequenceHeader *const seq_params = &cpi->common.seq_params; - int colors, n; - const int src_stride = x->plane[0].src.stride; - const uint8_t *const src = x->plane[0].src.buf; - uint8_t *const color_map = xd->plane[0].color_index_map; - int block_width, block_height, rows, cols; - av1_get_block_dimensions(bsize, 0, xd, &block_width, &block_height, &rows, - &cols); - - int count_buf[1 << 12]; // Maximum (1 << 12) color levels. - if (seq_params->use_highbitdepth) - colors = av1_count_colors_highbd(src, src_stride, rows, cols, - seq_params->bit_depth, count_buf); - else - colors = av1_count_colors(src, src_stride, rows, cols, count_buf); - mbmi->filter_intra_mode_info.use_filter_intra = 0; - - if (colors > 1 && colors <= 64) { - int r, c, i; - const int max_itr = 50; - int *const data = x->palette_buffer->kmeans_data_buf; - int centroids[PALETTE_MAX_SIZE]; - int lb, ub, val; - uint16_t *src16 = CONVERT_TO_SHORTPTR(src); - if (seq_params->use_highbitdepth) - lb = ub = src16[0]; - else - lb = ub = src[0]; - - if (seq_params->use_highbitdepth) { - for (r = 0; r < rows; ++r) { - for (c = 0; c < cols; ++c) { - val = src16[r * src_stride + c]; - data[r * cols + c] = val; - if (val < lb) - lb = val; - else if (val > ub) - ub = val; - } - } - } else { - for (r = 0; r < rows; ++r) { - for (c = 0; c < cols; ++c) { - val = src[r * src_stride + c]; - data[r * cols + c] = val; - if (val < lb) - lb = val; - else if (val > ub) - ub = val; - } - } - } - - mbmi->mode = DC_PRED; - mbmi->filter_intra_mode_info.use_filter_intra = 0; - - uint16_t color_cache[2 * PALETTE_MAX_SIZE]; - const int n_cache = av1_get_palette_cache(xd, 0, color_cache); - - // Find the dominant colors, stored in top_colors[]. - int top_colors[PALETTE_MAX_SIZE] = { 0 }; - for (i = 0; i < AOMMIN(colors, PALETTE_MAX_SIZE); ++i) { - int max_count = 0; - for (int j = 0; j < (1 << seq_params->bit_depth); ++j) { - if (count_buf[j] > max_count) { - max_count = count_buf[j]; - top_colors[i] = j; - } - } - assert(max_count > 0); - count_buf[top_colors[i]] = 0; - } - - // Try the dominant colors directly. - // TODO(huisu@google.com): Try to avoid duplicate computation in cases - // where the dominant colors and the k-means results are similar. - for (n = AOMMIN(colors, PALETTE_MAX_SIZE); n >= 2; --n) { - for (i = 0; i < n; ++i) centroids[i] = top_colors[i]; - palette_rd_y(cpi, x, mbmi, bsize, mi_row, mi_col, dc_mode_cost, data, - centroids, n, color_cache, n_cache, best_mbmi, - best_palette_color_map, best_rd, best_model_rd, rate, - rate_tokenonly, &rate_overhead, distortion, skippable, - beat_best_rd, ctx, best_blk_skip, tx_type_map); - } - - // K-means clustering. - for (n = AOMMIN(colors, PALETTE_MAX_SIZE); n >= 2; --n) { - if (colors == PALETTE_MIN_SIZE) { - // Special case: These colors automatically become the centroids. - assert(colors == n); - assert(colors == 2); - centroids[0] = lb; - centroids[1] = ub; - } else { - for (i = 0; i < n; ++i) { - centroids[i] = lb + (2 * i + 1) * (ub - lb) / n / 2; - } - av1_k_means(data, centroids, color_map, rows * cols, n, 1, max_itr); - } - palette_rd_y(cpi, x, mbmi, bsize, mi_row, mi_col, dc_mode_cost, data, - centroids, n, color_cache, n_cache, best_mbmi, - best_palette_color_map, best_rd, best_model_rd, rate, - rate_tokenonly, &rate_overhead, distortion, skippable, - beat_best_rd, ctx, best_blk_skip, tx_type_map); - } - } - - if (best_mbmi->palette_mode_info.palette_size[0] > 0) { - memcpy(color_map, best_palette_color_map, - block_width * block_height * sizeof(best_palette_color_map[0])); - } - *mbmi = *best_mbmi; - return rate_overhead; -} - -// Return 1 if an filter intra mode is selected; return 0 otherwise. -static int rd_pick_filter_intra_sby(const AV1_COMP *const cpi, MACROBLOCK *x, - int mi_row, int mi_col, int *rate, - int *rate_tokenonly, int64_t *distortion, - int *skippable, BLOCK_SIZE bsize, - int mode_cost, int64_t *best_rd, - int64_t *best_model_rd, - PICK_MODE_CONTEXT *ctx) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - int filter_intra_selected_flag = 0; - FILTER_INTRA_MODE mode; - TX_SIZE best_tx_size = TX_8X8; - FILTER_INTRA_MODE_INFO filter_intra_mode_info; - uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - (void)ctx; - av1_zero(filter_intra_mode_info); - mbmi->filter_intra_mode_info.use_filter_intra = 1; - mbmi->mode = DC_PRED; - mbmi->palette_mode_info.palette_size[0] = 0; - - for (mode = 0; mode < FILTER_INTRA_MODES; ++mode) { - int64_t this_rd; - RD_STATS tokenonly_rd_stats; - mbmi->filter_intra_mode_info.filter_intra_mode = mode; - - if (model_intra_yrd_and_prune(cpi, x, bsize, mi_row, mi_col, mode_cost, - best_model_rd)) { - continue; - } - super_block_yrd(cpi, x, &tokenonly_rd_stats, bsize, *best_rd); - if (tokenonly_rd_stats.rate == INT_MAX) continue; - const int this_rate = - tokenonly_rd_stats.rate + - intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); - this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - - // Collect mode stats for multiwinner mode processing - store_winner_mode_stats(x, mbmi, cpi->sf.enable_multiwinner_mode_process, - NULL, bsize, this_rd); - if (this_rd < *best_rd) { - *best_rd = this_rd; - best_tx_size = mbmi->tx_size; - filter_intra_mode_info = mbmi->filter_intra_mode_info; - av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - memcpy(ctx->blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - *rate = this_rate; - *rate_tokenonly = tokenonly_rd_stats.rate; - *distortion = tokenonly_rd_stats.dist; - *skippable = tokenonly_rd_stats.skip; - filter_intra_selected_flag = 1; - } - } - - if (filter_intra_selected_flag) { - mbmi->mode = DC_PRED; - mbmi->tx_size = best_tx_size; - mbmi->filter_intra_mode_info = filter_intra_mode_info; - av1_copy_array(ctx->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); - return 1; - } else { - return 0; - } -} - -// Run RD calculation with given luma intra prediction angle., and return -// the RD cost. Update the best mode info. if the RD cost is the best so far. -static int64_t calc_rd_given_intra_angle( - const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, - int mi_col, int mode_cost, int64_t best_rd_in, int8_t angle_delta, - int max_angle_delta, int *rate, RD_STATS *rd_stats, int *best_angle_delta, - TX_SIZE *best_tx_size, int64_t *best_rd, int64_t *best_model_rd, - uint8_t *best_tx_type_map, uint8_t *best_blk_skip, int skip_model_rd) { - RD_STATS tokenonly_rd_stats; - int64_t this_rd; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - const int n4 = bsize_to_num_blk(bsize); - assert(!is_inter_block(mbmi)); - mbmi->angle_delta[PLANE_TYPE_Y] = angle_delta; - if (!skip_model_rd) { - if (model_intra_yrd_and_prune(cpi, x, bsize, mi_row, mi_col, mode_cost, - best_model_rd)) { - return INT64_MAX; - } - } - super_block_yrd(cpi, x, &tokenonly_rd_stats, bsize, best_rd_in); - if (tokenonly_rd_stats.rate == INT_MAX) return INT64_MAX; - - int this_rate = - mode_cost + tokenonly_rd_stats.rate + - x->angle_delta_cost[mbmi->mode - V_PRED][max_angle_delta + angle_delta]; - this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - - if (this_rd < *best_rd) { - memcpy(best_blk_skip, x->blk_skip, sizeof(best_blk_skip[0]) * n4); - av1_copy_array(best_tx_type_map, xd->tx_type_map, n4); - *best_rd = this_rd; - *best_angle_delta = mbmi->angle_delta[PLANE_TYPE_Y]; - *best_tx_size = mbmi->tx_size; - *rate = this_rate; - rd_stats->rate = tokenonly_rd_stats.rate; - rd_stats->dist = tokenonly_rd_stats.dist; - rd_stats->skip = tokenonly_rd_stats.skip; - } - return this_rd; -} - -// With given luma directional intra prediction mode, pick the best angle delta -// Return the RD cost corresponding to the best angle delta. -static int64_t rd_pick_intra_angle_sby(const AV1_COMP *const cpi, MACROBLOCK *x, - int mi_row, int mi_col, int *rate, - RD_STATS *rd_stats, BLOCK_SIZE bsize, - int mode_cost, int64_t best_rd, - int64_t *best_model_rd, - int skip_model_rd_for_zero_deg) { - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - - int best_angle_delta = 0; - int64_t rd_cost[2 * (MAX_ANGLE_DELTA + 2)]; - TX_SIZE best_tx_size = mbmi->tx_size; - uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; - uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - - for (int i = 0; i < 2 * (MAX_ANGLE_DELTA + 2); ++i) rd_cost[i] = INT64_MAX; - - int first_try = 1; - for (int angle_delta = 0; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { - for (int i = 0; i < 2; ++i) { - const int64_t best_rd_in = - (best_rd == INT64_MAX) ? INT64_MAX - : (best_rd + (best_rd >> (first_try ? 3 : 5))); - const int64_t this_rd = calc_rd_given_intra_angle( - cpi, x, bsize, mi_row, mi_col, mode_cost, best_rd_in, - (1 - 2 * i) * angle_delta, MAX_ANGLE_DELTA, rate, rd_stats, - &best_angle_delta, &best_tx_size, &best_rd, best_model_rd, - best_tx_type_map, best_blk_skip, - (skip_model_rd_for_zero_deg & !angle_delta)); - rd_cost[2 * angle_delta + i] = this_rd; - if (first_try && this_rd == INT64_MAX) return best_rd; - first_try = 0; - if (angle_delta == 0) { - rd_cost[1] = this_rd; - break; - } - } - } - - assert(best_rd != INT64_MAX); - for (int angle_delta = 1; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { - for (int i = 0; i < 2; ++i) { - int skip_search = 0; - const int64_t rd_thresh = best_rd + (best_rd >> 5); - if (rd_cost[2 * (angle_delta + 1) + i] > rd_thresh && - rd_cost[2 * (angle_delta - 1) + i] > rd_thresh) - skip_search = 1; - if (!skip_search) { - calc_rd_given_intra_angle( - cpi, x, bsize, mi_row, mi_col, mode_cost, best_rd, - (1 - 2 * i) * angle_delta, MAX_ANGLE_DELTA, rate, rd_stats, - &best_angle_delta, &best_tx_size, &best_rd, best_model_rd, - best_tx_type_map, best_blk_skip, 0); - } - } - } - - if (rd_stats->rate != INT_MAX) { - mbmi->tx_size = best_tx_size; - mbmi->angle_delta[PLANE_TYPE_Y] = best_angle_delta; - const int n4 = bsize_to_num_blk(bsize); - memcpy(x->blk_skip, best_blk_skip, sizeof(best_blk_skip[0]) * n4); - av1_copy_array(xd->tx_type_map, best_tx_type_map, n4); - } - return best_rd; -} - -// Indices are sign, integer, and fractional part of the gradient value -static const uint8_t gradient_to_angle_bin[2][7][16] = { - { - { 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - }, - { - { 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4 }, - { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3 }, - { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, - { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, - { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, - { 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - }, -}; - -/* clang-format off */ -static const uint8_t mode_to_angle_bin[INTRA_MODES] = { - 0, 2, 6, 0, 4, 3, 5, 7, 1, 0, - 0, -}; -/* clang-format on */ - -static AOM_INLINE void get_gradient_hist(const uint8_t *src, int src_stride, - int rows, int cols, uint64_t *hist) { - src += src_stride; - for (int r = 1; r < rows; ++r) { - for (int c = 1; c < cols; ++c) { - int dx = src[c] - src[c - 1]; - int dy = src[c] - src[c - src_stride]; - int index; - const int temp = dx * dx + dy * dy; - if (dy == 0) { - index = 2; - } else { - const int sn = (dx > 0) ^ (dy > 0); - dx = abs(dx); - dy = abs(dy); - const int remd = (dx % dy) * 16 / dy; - const int quot = dx / dy; - index = gradient_to_angle_bin[sn][AOMMIN(quot, 6)][AOMMIN(remd, 15)]; - } - hist[index] += temp; - } - src += src_stride; - } -} - -static AOM_INLINE void get_highbd_gradient_hist(const uint8_t *src8, - int src_stride, int rows, - int cols, uint64_t *hist) { - uint16_t *src = CONVERT_TO_SHORTPTR(src8); - src += src_stride; - for (int r = 1; r < rows; ++r) { - for (int c = 1; c < cols; ++c) { - int dx = src[c] - src[c - 1]; - int dy = src[c] - src[c - src_stride]; - int index; - const int temp = dx * dx + dy * dy; - if (dy == 0) { - index = 2; - } else { - const int sn = (dx > 0) ^ (dy > 0); - dx = abs(dx); - dy = abs(dy); - const int remd = (dx % dy) * 16 / dy; - const int quot = dx / dy; - index = gradient_to_angle_bin[sn][AOMMIN(quot, 6)][AOMMIN(remd, 15)]; - } - hist[index] += temp; - } - src += src_stride; - } -} - -static AOM_INLINE void angle_estimation(const uint8_t *src, int src_stride, - int rows, int cols, BLOCK_SIZE bsize, - int is_hbd, - uint8_t *directional_mode_skip_mask) { - // Check if angle_delta is used - if (!av1_use_angle_delta(bsize)) return; - - uint64_t hist[DIRECTIONAL_MODES] = { 0 }; - if (is_hbd) - get_highbd_gradient_hist(src, src_stride, rows, cols, hist); - else - get_gradient_hist(src, src_stride, rows, cols, hist); - - int i; - uint64_t hist_sum = 0; - for (i = 0; i < DIRECTIONAL_MODES; ++i) hist_sum += hist[i]; - for (i = 0; i < INTRA_MODES; ++i) { - if (av1_is_directional_mode(i)) { - const uint8_t angle_bin = mode_to_angle_bin[i]; - uint64_t score = 2 * hist[angle_bin]; - int weight = 2; - if (angle_bin > 0) { - score += hist[angle_bin - 1]; - ++weight; - } - if (angle_bin < DIRECTIONAL_MODES - 1) { - score += hist[angle_bin + 1]; - ++weight; - } - const int thresh = 10; - if (score * thresh < hist_sum * weight) directional_mode_skip_mask[i] = 1; - } - } -} - -// Given selected prediction mode, search for the best tx type and size. -static AOM_INLINE int intra_block_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, const int *bmode_costs, - int64_t *best_rd, int *rate, - int *rate_tokenonly, int64_t *distortion, - int *skippable, MB_MODE_INFO *best_mbmi, - PICK_MODE_CONTEXT *ctx) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - RD_STATS rd_stats; - // In order to improve txfm search avoid rd based breakouts during winner - // mode evaluation. Hence passing ref_best_rd as a maximum value - super_block_yrd(cpi, x, &rd_stats, bsize, INT64_MAX); - if (rd_stats.rate == INT_MAX) return 0; - int this_rate_tokenonly = rd_stats.rate; - if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(mbmi->sb_type)) { - // super_block_yrd above includes the cost of the tx_size in the - // tokenonly rate, but for intra blocks, tx_size is always coded - // (prediction granularity), so we account for it in the full rate, - // not the tokenonly rate. - this_rate_tokenonly -= tx_size_cost(x, bsize, mbmi->tx_size); - } - const int this_rate = - rd_stats.rate + - intra_mode_info_cost_y(cpi, x, mbmi, bsize, bmode_costs[mbmi->mode]); - const int64_t this_rd = RDCOST(x->rdmult, this_rate, rd_stats.dist); - if (this_rd < *best_rd) { - *best_mbmi = *mbmi; - *best_rd = this_rd; - *rate = this_rate; - *rate_tokenonly = this_rate_tokenonly; - *distortion = rd_stats.dist; - *skippable = rd_stats.skip; - av1_copy_array(ctx->blk_skip, x->blk_skip, ctx->num_4x4_blk); - av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - return 1; - } - return 0; -} - -// This function is used only for intra_only frames -static int64_t rd_pick_intra_sby_mode(const AV1_COMP *const cpi, MACROBLOCK *x, - int mi_row, int mi_col, int *rate, - int *rate_tokenonly, int64_t *distortion, - int *skippable, BLOCK_SIZE bsize, - int64_t best_rd, PICK_MODE_CONTEXT *ctx) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - int64_t best_model_rd = INT64_MAX; - const int rows = block_size_high[bsize]; - const int cols = block_size_wide[bsize]; - int is_directional_mode; - uint8_t directional_mode_skip_mask[INTRA_MODES] = { 0 }; - // Flag to check rd of any intra mode is better than best_rd passed to this - // function - int beat_best_rd = 0; - const int *bmode_costs; - PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; - const int try_palette = - cpi->oxcf.enable_palette && - av1_allow_palette(cpi->common.allow_screen_content_tools, mbmi->sb_type); - uint8_t *best_palette_color_map = - try_palette ? x->palette_buffer->best_palette_color_map : NULL; - const MB_MODE_INFO *above_mi = xd->above_mbmi; - const MB_MODE_INFO *left_mi = xd->left_mbmi; - const PREDICTION_MODE A = av1_above_block_mode(above_mi); - const PREDICTION_MODE L = av1_left_block_mode(left_mi); - const int above_ctx = intra_mode_context[A]; - const int left_ctx = intra_mode_context[L]; - bmode_costs = x->y_mode_costs[above_ctx][left_ctx]; - - mbmi->angle_delta[PLANE_TYPE_Y] = 0; - if (cpi->sf.intra_angle_estimation) { - const int src_stride = x->plane[0].src.stride; - const uint8_t *src = x->plane[0].src.buf; - angle_estimation(src, src_stride, rows, cols, bsize, is_cur_buf_hbd(xd), - directional_mode_skip_mask); - } - mbmi->filter_intra_mode_info.use_filter_intra = 0; - pmi->palette_size[0] = 0; - - // Set params for mode evaluation - set_mode_eval_params(cpi, x, MODE_EVAL); - - MB_MODE_INFO best_mbmi = *mbmi; - x->winner_mode_count = 0; - // Initialize best mode stats for winner mode processing - store_winner_mode_stats(x, mbmi, cpi->sf.enable_multiwinner_mode_process, - NULL, bsize, best_rd); - /* Y Search for intra prediction mode */ - for (int mode_idx = INTRA_MODE_START; mode_idx < INTRA_MODE_END; ++mode_idx) { - RD_STATS this_rd_stats; - int this_rate, this_rate_tokenonly, s; - int64_t this_distortion, this_rd; - mbmi->mode = intra_rd_search_mode_order[mode_idx]; - 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; - if (!cpi->oxcf.enable_paeth_intra && mbmi->mode == PAETH_PRED) continue; - mbmi->angle_delta[PLANE_TYPE_Y] = 0; - - if (model_intra_yrd_and_prune(cpi, x, bsize, mi_row, mi_col, - bmode_costs[mbmi->mode], &best_model_rd)) { - continue; - } - - is_directional_mode = av1_is_directional_mode(mbmi->mode); - if (is_directional_mode && directional_mode_skip_mask[mbmi->mode]) continue; - if (is_directional_mode && av1_use_angle_delta(bsize) && - cpi->oxcf.enable_angle_delta) { - this_rd_stats.rate = INT_MAX; - rd_pick_intra_angle_sby(cpi, x, mi_row, mi_col, &this_rate, - &this_rd_stats, bsize, bmode_costs[mbmi->mode], - best_rd, &best_model_rd, 1); - } else { - super_block_yrd(cpi, x, &this_rd_stats, bsize, best_rd); - } - this_rate_tokenonly = this_rd_stats.rate; - this_distortion = this_rd_stats.dist; - s = this_rd_stats.skip; - - if (this_rate_tokenonly == INT_MAX) continue; - - if (!xd->lossless[mbmi->segment_id] && - block_signals_txsize(mbmi->sb_type)) { - // super_block_yrd above includes the cost of the tx_size in the - // tokenonly rate, but for intra blocks, tx_size is always coded - // (prediction granularity), so we account for it in the full rate, - // not the tokenonly rate. - this_rate_tokenonly -= tx_size_cost(x, bsize, mbmi->tx_size); - } - this_rate = - this_rd_stats.rate + - intra_mode_info_cost_y(cpi, x, mbmi, bsize, bmode_costs[mbmi->mode]); - this_rd = RDCOST(x->rdmult, this_rate, this_distortion); - // Collect mode stats for multiwinner mode processing - store_winner_mode_stats(x, mbmi, cpi->sf.enable_multiwinner_mode_process, - NULL, bsize, this_rd); - if (this_rd < best_rd) { - best_mbmi = *mbmi; - best_rd = this_rd; - // Setting beat_best_rd flag because current mode rd is better than - // best_rd passed to this function - beat_best_rd = 1; - *rate = this_rate; - *rate_tokenonly = this_rate_tokenonly; - *distortion = this_distortion; - *skippable = s; - memcpy(ctx->blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - } - } - - if (try_palette) { - rd_pick_palette_intra_sby( - cpi, x, bsize, mi_row, mi_col, bmode_costs[DC_PRED], &best_mbmi, - best_palette_color_map, &best_rd, &best_model_rd, rate, rate_tokenonly, - distortion, skippable, &beat_best_rd, ctx, ctx->blk_skip, - ctx->tx_type_map); - } - - if (beat_best_rd && av1_filter_intra_allowed_bsize(&cpi->common, bsize)) { - if (rd_pick_filter_intra_sby( - cpi, x, mi_row, mi_col, rate, rate_tokenonly, distortion, skippable, - bsize, bmode_costs[DC_PRED], &best_rd, &best_model_rd, ctx)) { - best_mbmi = *mbmi; - } - } - // No mode is identified with less rd value than best_rd passed to this - // function. In such cases winner mode processing is not necessary and return - // best_rd as INT64_MAX to indicate best mode is not identified - if (!beat_best_rd) return INT64_MAX; - - // In multi-winner mode processing, perform tx search for few best modes - // identified during mode evaluation. Winner mode processing uses best tx - // configuration for tx search. - if (cpi->sf.enable_multiwinner_mode_process) { - int best_mode_idx = 0; - int block_width, block_height; - uint8_t *color_map_dst = xd->plane[PLANE_TYPE_Y].color_index_map; - av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width, - &block_height, NULL, NULL); - - for (int mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++) { - *mbmi = x->winner_mode_stats[mode_idx].mbmi; - if (is_winner_mode_processing_enabled(cpi, mbmi, mbmi->mode)) { - // Restore color_map of palette mode before winner mode processing - if (mbmi->palette_mode_info.palette_size[0] > 0) { - uint8_t *color_map_src = - x->winner_mode_stats[mode_idx].color_index_map; - memcpy(color_map_dst, color_map_src, - block_width * block_height * sizeof(*color_map_src)); - } - // Set params for winner mode evaluation - set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); - - // Winner mode processing - // If previous searches use only the default tx type/no R-D optimization - // of quantized coeffs, do an extra search for the best tx type/better - // R-D optimization of quantized coeffs - if (intra_block_yrd(cpi, x, bsize, bmode_costs, &best_rd, rate, - rate_tokenonly, distortion, skippable, &best_mbmi, - ctx)) - best_mode_idx = mode_idx; - } - } - // Copy color_map of palette mode for final winner mode - if (best_mbmi.palette_mode_info.palette_size[0] > 0) { - uint8_t *color_map_src = - x->winner_mode_stats[best_mode_idx].color_index_map; - memcpy(color_map_dst, color_map_src, - block_width * block_height * sizeof(*color_map_src)); - } - } else { - // If previous searches use only the default tx type/no R-D optimization of - // quantized coeffs, do an extra search for the best tx type/better R-D - // optimization of quantized coeffs - if (is_winner_mode_processing_enabled(cpi, mbmi, best_mbmi.mode)) { - // Set params for winner mode evaluation - set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); - *mbmi = best_mbmi; - intra_block_yrd(cpi, x, bsize, bmode_costs, &best_rd, rate, - rate_tokenonly, distortion, skippable, &best_mbmi, ctx); - } - } - *mbmi = best_mbmi; - av1_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk); - return best_rd; -} - -// Return value 0: early termination triggered, no valid rd cost available; -// 1: rd cost values are valid. -static int super_block_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, - RD_STATS *rd_stats, BLOCK_SIZE bsize, - int64_t ref_best_rd) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_U]; - 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; - - if (x->skip_chroma_rd) return is_cost_valid; - - bsize = scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); - - if (is_inter && is_cost_valid) { - for (plane = 1; plane < MAX_MB_PLANE; ++plane) - av1_subtract_plane(x, bsize, plane); - } - - if (is_cost_valid) { - for (plane = 1; plane < MAX_MB_PLANE; ++plane) { - RD_STATS pn_rd_stats; - 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); - 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; - } - } - } - - if (!is_cost_valid) { - // reset cost value - av1_invalid_rd_stats(rd_stats); - } - - return is_cost_valid; -} - -// Pick transform type for a transform block of tx_size. -static AOM_INLINE void tx_type_rd(const AV1_COMP *cpi, MACROBLOCK *x, - TX_SIZE tx_size, int blk_row, int blk_col, - int plane, int block, int plane_bsize, - TXB_CTX *txb_ctx, RD_STATS *rd_stats, - FAST_TX_SEARCH_MODE ftxs_mode, - int64_t ref_rdcost, - TXB_RD_INFO *rd_info_array) { - const struct macroblock_plane *const p = &x->plane[plane]; - const uint16_t cur_joint_ctx = - (txb_ctx->dc_sign_ctx << 8) + txb_ctx->txb_skip_ctx; - MACROBLOCKD *xd = &x->e_mbd; - const int tx_type_map_idx = - plane ? 0 : blk_row * xd->tx_type_map_stride + blk_col; - // Look up RD and terminate early in case when we've already processed exactly - // the same residual with exactly the same entropy context. - if (rd_info_array != NULL && rd_info_array->valid && - rd_info_array->entropy_context == cur_joint_ctx) { - if (plane == 0) xd->tx_type_map[tx_type_map_idx] = rd_info_array->tx_type; - const TX_TYPE ref_tx_type = - av1_get_tx_type(&x->e_mbd, get_plane_type(plane), blk_row, blk_col, - tx_size, cpi->common.reduced_tx_set_used); - if (ref_tx_type == rd_info_array->tx_type) { - rd_stats->rate += rd_info_array->rate; - rd_stats->dist += rd_info_array->dist; - rd_stats->sse += rd_info_array->sse; - rd_stats->skip &= rd_info_array->eob == 0; - p->eobs[block] = rd_info_array->eob; - p->txb_entropy_ctx[block] = rd_info_array->txb_entropy_ctx; - return; - } - } - - 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, 0, ref_rdcost, &this_rd_stats); - - av1_merge_rd_stats(rd_stats, &this_rd_stats); - - // Save RD results for possible reuse in future. - if (rd_info_array != NULL) { - rd_info_array->valid = 1; - rd_info_array->entropy_context = cur_joint_ctx; - rd_info_array->rate = this_rd_stats.rate; - rd_info_array->dist = this_rd_stats.dist; - rd_info_array->sse = this_rd_stats.sse; - rd_info_array->eob = p->eobs[block]; - rd_info_array->txb_entropy_ctx = p->txb_entropy_ctx[block]; - if (plane == 0) rd_info_array->tx_type = xd->tx_type_map[tx_type_map_idx]; - } -} - -static float get_dev(float mean, double x2_sum, int num) { - const float e_x2 = (float)(x2_sum / num); - const float diff = e_x2 - mean * mean; - const float dev = (diff > 0) ? sqrtf(diff) : 0; - return dev; -} - -// Feature used by the model to predict tx split: the mean and standard -// deviation values of the block and sub-blocks. -static AOM_INLINE void get_mean_dev_features(const int16_t *data, int stride, - int bw, int bh, float *feature) { - const int16_t *const data_ptr = &data[0]; - const int subh = (bh >= bw) ? (bh >> 1) : bh; - const int subw = (bw >= bh) ? (bw >> 1) : bw; - const int num = bw * bh; - const int sub_num = subw * subh; - int feature_idx = 2; - int total_x_sum = 0; - int64_t total_x2_sum = 0; - int blk_idx = 0; - double mean2_sum = 0.0f; - float dev_sum = 0.0f; - - for (int row = 0; row < bh; row += subh) { - for (int col = 0; col < bw; col += subw) { - int x_sum; - int64_t x2_sum; - // TODO(any): Write a SIMD version. Clear registers. - aom_get_blk_sse_sum(data_ptr + row * stride + col, stride, subw, subh, - &x_sum, &x2_sum); - total_x_sum += x_sum; - total_x2_sum += x2_sum; - - aom_clear_system_state(); - const float mean = (float)x_sum / sub_num; - const float dev = get_dev(mean, (double)x2_sum, sub_num); - feature[feature_idx++] = mean; - feature[feature_idx++] = dev; - mean2_sum += (double)(mean * mean); - dev_sum += dev; - blk_idx++; - } - } - - const float lvl0_mean = (float)total_x_sum / num; - feature[0] = lvl0_mean; - feature[1] = get_dev(lvl0_mean, (double)total_x2_sum, num); - - if (blk_idx > 1) { - // Deviation of means. - feature[feature_idx++] = get_dev(lvl0_mean, mean2_sum, blk_idx); - // Mean of deviations. - feature[feature_idx++] = dev_sum / blk_idx; - } -} - -static int ml_predict_tx_split(MACROBLOCK *x, BLOCK_SIZE bsize, int blk_row, - int blk_col, TX_SIZE tx_size) { - const NN_CONFIG *nn_config = av1_tx_split_nnconfig_map[tx_size]; - if (!nn_config) return -1; - - const int diff_stride = block_size_wide[bsize]; - const int16_t *diff = - x->plane[0].src_diff + 4 * blk_row * diff_stride + 4 * blk_col; - const int bw = tx_size_wide[tx_size]; - const int bh = tx_size_high[tx_size]; - aom_clear_system_state(); - - float features[64] = { 0.0f }; - get_mean_dev_features(diff, diff_stride, bw, bh, features); - - float score = 0.0f; - av1_nn_predict(features, nn_config, 1, &score); - aom_clear_system_state(); - - int int_score = (int)(score * 10000); - return clamp(int_score, -80000, 80000); -} - -typedef struct { - int64_t rd; - int txb_entropy_ctx; - TX_TYPE tx_type; -} TxCandidateInfo; - -static AOM_INLINE void try_tx_block_no_split( - const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, - TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, - const ENTROPY_CONTEXT *ta, const ENTROPY_CONTEXT *tl, - int txfm_partition_ctx, RD_STATS *rd_stats, int64_t ref_best_rd, - FAST_TX_SEARCH_MODE ftxs_mode, TXB_RD_INFO_NODE *rd_info_node, - TxCandidateInfo *no_split) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - struct macroblock_plane *const p = &x->plane[0]; - const int bw = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - - no_split->rd = INT64_MAX; - no_split->txb_entropy_ctx = 0; - no_split->tx_type = TX_TYPES; - - const ENTROPY_CONTEXT *const pta = ta + blk_col; - const ENTROPY_CONTEXT *const ptl = tl + blk_row; - - const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); - TXB_CTX txb_ctx; - get_txb_ctx(plane_bsize, tx_size, 0, pta, ptl, &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->zero_rate = zero_blk_rate; - const int index = av1_get_txb_size_index(plane_bsize, blk_row, blk_col); - mbmi->inter_tx_size[index] = tx_size; - tx_type_rd(cpi, x, tx_size, blk_row, blk_col, 0, block, plane_bsize, &txb_ctx, - rd_stats, ftxs_mode, ref_best_rd, - rd_info_node != NULL ? rd_info_node->rd_info_array : NULL); - assert(rd_stats->rate < INT_MAX); - - if ((RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >= - RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse) || - rd_stats->skip == 1) && - !xd->lossless[mbmi->segment_id]) { -#if CONFIG_RD_DEBUG - av1_update_txb_coeff_cost(rd_stats, 0, tx_size, blk_row, blk_col, - zero_blk_rate - rd_stats->rate); -#endif // CONFIG_RD_DEBUG - rd_stats->rate = zero_blk_rate; - rd_stats->dist = rd_stats->sse; - rd_stats->skip = 1; - set_blk_skip(x, 0, blk_row * bw + blk_col, 1); - p->eobs[block] = 0; - update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); - } else { - set_blk_skip(x, 0, blk_row * bw + blk_col, 0); - rd_stats->skip = 0; - } - - if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) - rd_stats->rate += x->txfm_partition_cost[txfm_partition_ctx][0]; - - no_split->rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); - no_split->txb_entropy_ctx = p->txb_entropy_ctx[block]; - no_split->tx_type = - xd->tx_type_map[blk_row * xd->tx_type_map_stride + blk_col]; -} - -static AOM_INLINE void select_tx_block( - const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, - TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, - ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, - RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd, - int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, - TXB_RD_INFO_NODE *rd_info_node); - -static AOM_INLINE void try_tx_block_split( - const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, - TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, - ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, - int txfm_partition_ctx, int64_t no_split_rd, int64_t ref_best_rd, - FAST_TX_SEARCH_MODE ftxs_mode, TXB_RD_INFO_NODE *rd_info_node, - RD_STATS *split_rd_stats, int64_t *split_rd) { - assert(tx_size < TX_SIZES_ALL); - MACROBLOCKD *const xd = &x->e_mbd; - const int max_blocks_high = max_block_high(xd, plane_bsize, 0); - const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0); - const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; - const int bsw = tx_size_wide_unit[sub_txs]; - const int bsh = tx_size_high_unit[sub_txs]; - const int sub_step = bsw * bsh; - const int nblks = - (tx_size_high_unit[tx_size] / bsh) * (tx_size_wide_unit[tx_size] / bsw); - assert(nblks > 0); - int blk_idx = 0; - int64_t tmp_rd = 0; - *split_rd = INT64_MAX; - split_rd_stats->rate = x->txfm_partition_cost[txfm_partition_ctx][1]; - - for (int r = 0; r < tx_size_high_unit[tx_size]; r += bsh) { - for (int c = 0; c < tx_size_wide_unit[tx_size]; c += bsw, ++blk_idx) { - assert(blk_idx < 4); - const int offsetr = blk_row + r; - const int offsetc = blk_col + c; - if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; - - RD_STATS this_rd_stats; - int this_cost_valid = 1; - select_tx_block( - cpi, x, offsetr, offsetc, block, sub_txs, depth + 1, plane_bsize, ta, - tl, tx_above, tx_left, &this_rd_stats, no_split_rd / nblks, - ref_best_rd - tmp_rd, &this_cost_valid, ftxs_mode, - (rd_info_node != NULL) ? rd_info_node->children[blk_idx] : NULL); - if (!this_cost_valid) return; - av1_merge_rd_stats(split_rd_stats, &this_rd_stats); - tmp_rd = RDCOST(x->rdmult, split_rd_stats->rate, split_rd_stats->dist); - if (no_split_rd < tmp_rd) return; - block += sub_step; - } - } - - *split_rd = tmp_rd; -} - -// Search for the best tx partition/type for a given luma block. -static AOM_INLINE void select_tx_block( - const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, - TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, - ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, - RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd, - int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, - TXB_RD_INFO_NODE *rd_info_node) { - assert(tx_size < TX_SIZES_ALL); - av1_init_rd_stats(rd_stats); - if (ref_best_rd < 0) { - *is_cost_valid = 0; - return; - } - - MACROBLOCKD *const xd = &x->e_mbd; - const int max_blocks_high = max_block_high(xd, plane_bsize, 0); - const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0); - if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide) return; - - const int bw = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row, - mbmi->sb_type, tx_size); - struct macroblock_plane *const p = &x->plane[0]; - - const int try_no_split = - cpi->oxcf.enable_tx64 || txsize_sqr_up_map[tx_size] != TX_64X64; - int try_split = tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH; -#if CONFIG_DIST_8X8 - if (x->using_dist_8x8) - try_split &= tx_size_wide[tx_size] >= 16 && tx_size_high[tx_size] >= 16; -#endif - TxCandidateInfo no_split = { INT64_MAX, 0, TX_TYPES }; - - // TX no split - if (try_no_split) { - try_tx_block_no_split(cpi, x, blk_row, blk_col, block, tx_size, depth, - plane_bsize, ta, tl, ctx, rd_stats, ref_best_rd, - ftxs_mode, rd_info_node, &no_split); - - if (cpi->sf.adaptive_txb_search_level && - (no_split.rd - - (no_split.rd >> (1 + cpi->sf.adaptive_txb_search_level))) > - ref_best_rd) { - *is_cost_valid = 0; - return; - } - - if (cpi->sf.txb_split_cap) { - if (p->eobs[block] == 0) try_split = 0; - } - - if (cpi->sf.adaptive_txb_search_level && - (no_split.rd - - (no_split.rd >> (2 + cpi->sf.adaptive_txb_search_level))) > - prev_level_rd) { - try_split = 0; - } - } - - if (x->e_mbd.bd == 8 && try_split && - !(ref_best_rd == INT64_MAX && no_split.rd == INT64_MAX)) { - const int threshold = cpi->sf.tx_type_search.ml_tx_split_thresh; - if (threshold >= 0) { - const int split_score = - ml_predict_tx_split(x, plane_bsize, blk_row, blk_col, tx_size); - if (split_score < -threshold) try_split = 0; - } - } - - // TX split - int64_t split_rd = INT64_MAX; - RD_STATS split_rd_stats; - av1_init_rd_stats(&split_rd_stats); - if (try_split) { - try_tx_block_split(cpi, x, blk_row, blk_col, block, tx_size, depth, - plane_bsize, ta, tl, tx_above, tx_left, ctx, no_split.rd, - AOMMIN(no_split.rd, ref_best_rd), ftxs_mode, - rd_info_node, &split_rd_stats, &split_rd); - } - - if (no_split.rd < split_rd) { - ENTROPY_CONTEXT *pta = ta + blk_col; - ENTROPY_CONTEXT *ptl = tl + blk_row; - const TX_SIZE tx_size_selected = tx_size; - p->txb_entropy_ctx[block] = no_split.txb_entropy_ctx; - av1_set_txb_context(x, 0, block, tx_size_selected, pta, ptl); - txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size, - tx_size); - for (int idy = 0; idy < tx_size_high_unit[tx_size]; ++idy) { - for (int idx = 0; idx < tx_size_wide_unit[tx_size]; ++idx) { - const int index = - av1_get_txb_size_index(plane_bsize, blk_row + idy, blk_col + idx); - mbmi->inter_tx_size[index] = tx_size_selected; - } - } - mbmi->tx_size = tx_size_selected; - update_txk_array(xd, blk_row, blk_col, tx_size, no_split.tx_type); - set_blk_skip(x, 0, blk_row * bw + blk_col, rd_stats->skip); - } else { - *rd_stats = split_rd_stats; - if (split_rd == INT64_MAX) *is_cost_valid = 0; - } -} - -static int64_t select_tx_size_and_type(const AV1_COMP *cpi, MACROBLOCK *x, - RD_STATS *rd_stats, BLOCK_SIZE bsize, - int64_t ref_best_rd, - TXB_RD_INFO_NODE *rd_info_tree) { - MACROBLOCKD *const xd = &x->e_mbd; - assert(is_inter_block(xd->mi[0])); - assert(bsize < BLOCK_SIZES_ALL); - - // TODO(debargha): enable this as a speed feature where the - // select_inter_block_yrd() function above will use a simplified search - // such as not using full optimize, but the inter_block_yrd() function - // will use more complex search given that the transform partitions have - // already been decided. - - const int fast_tx_search = x->tx_size_search_method > USE_FULL_RD; - int64_t rd_thresh = ref_best_rd; - if (fast_tx_search && rd_thresh < INT64_MAX) { - if (INT64_MAX - rd_thresh > (rd_thresh >> 3)) rd_thresh += (rd_thresh >> 3); - } - assert(rd_thresh > 0); - - const FAST_TX_SEARCH_MODE ftxs_mode = - fast_tx_search ? FTXS_DCT_AND_1D_DCT_ONLY : FTXS_NONE; - const struct macroblockd_plane *const pd = &xd->plane[0]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - assert(plane_bsize < BLOCK_SIZES_ALL); - const int mi_width = mi_size_wide[plane_bsize]; - const int mi_height = mi_size_high[plane_bsize]; - ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; - ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; - TXFM_CONTEXT tx_above[MAX_MIB_SIZE]; - TXFM_CONTEXT tx_left[MAX_MIB_SIZE]; - av1_get_entropy_contexts(bsize, pd, ctxa, ctxl); - memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width); - memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height); - - const int skip_ctx = av1_get_skip_context(xd); - const int s0 = x->skip_cost[skip_ctx][0]; - const int s1 = x->skip_cost[skip_ctx][1]; - const int init_depth = get_search_init_depth(mi_width, mi_height, 1, &cpi->sf, - x->tx_size_search_method); - const TX_SIZE max_tx_size = max_txsize_rect_lookup[plane_bsize]; - const int bh = tx_size_high_unit[max_tx_size]; - const int bw = tx_size_wide_unit[max_tx_size]; - const int step = bw * bh; - int64_t skip_rd = RDCOST(x->rdmult, s1, 0); - int64_t this_rd = RDCOST(x->rdmult, s0, 0); - int block = 0; - - av1_init_rd_stats(rd_stats); - for (int idy = 0; idy < mi_height; idy += bh) { - for (int idx = 0; idx < mi_width; idx += bw) { - const int64_t best_rd_sofar = - (rd_thresh == INT64_MAX) ? INT64_MAX - : (rd_thresh - (AOMMIN(skip_rd, this_rd))); - int is_cost_valid = 1; - RD_STATS pn_rd_stats; - select_tx_block(cpi, x, idy, idx, block, max_tx_size, init_depth, - plane_bsize, ctxa, ctxl, tx_above, tx_left, &pn_rd_stats, - INT64_MAX, best_rd_sofar, &is_cost_valid, ftxs_mode, - rd_info_tree); - if (!is_cost_valid || pn_rd_stats.rate == INT_MAX) { - av1_invalid_rd_stats(rd_stats); - return INT64_MAX; - } - av1_merge_rd_stats(rd_stats, &pn_rd_stats); - skip_rd = RDCOST(x->rdmult, s1, rd_stats->sse); - this_rd = RDCOST(x->rdmult, rd_stats->rate + s0, rd_stats->dist); - block += step; - if (rd_info_tree != NULL) rd_info_tree += 1; - } - } - - if (skip_rd <= this_rd) { - rd_stats->skip = 1; - } else { - rd_stats->skip = 0; - } - - if (rd_stats->rate == INT_MAX) return INT64_MAX; - - // If fast_tx_search is true, only DCT and 1D DCT were tested in - // select_inter_block_yrd() above. Do a better search for tx type with - // tx sizes already decided. - if (fast_tx_search) { - if (!inter_block_yrd(cpi, x, rd_stats, bsize, ref_best_rd, FTXS_NONE)) - return INT64_MAX; - } - - int64_t rd; - if (rd_stats->skip) { - rd = RDCOST(x->rdmult, s1, rd_stats->sse); - } else { - rd = RDCOST(x->rdmult, rd_stats->rate + s0, rd_stats->dist); - if (!xd->lossless[xd->mi[0]->segment_id]) - rd = AOMMIN(rd, RDCOST(x->rdmult, s1, rd_stats->sse)); - } - - return rd; -} - -// Finds rd cost for a y block, given the transform size partitions -static AOM_INLINE void tx_block_yrd( - const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, - TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int depth, - ENTROPY_CONTEXT *above_ctx, ENTROPY_CONTEXT *left_ctx, - TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, int64_t ref_best_rd, - RD_STATS *rd_stats, FAST_TX_SEARCH_MODE ftxs_mode) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int max_blocks_high = max_block_high(xd, plane_bsize, 0); - const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0); - - assert(tx_size < TX_SIZES_ALL); - - if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide) return; - - const TX_SIZE plane_tx_size = mbmi->inter_tx_size[av1_get_txb_size_index( - plane_bsize, blk_row, blk_col)]; - - int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row, - mbmi->sb_type, tx_size); - - av1_init_rd_stats(rd_stats); - if (tx_size == plane_tx_size) { - ENTROPY_CONTEXT *ta = above_ctx + blk_col; - ENTROPY_CONTEXT *tl = left_ctx + blk_row; - const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); - TXB_CTX txb_ctx; - get_txb_ctx(plane_bsize, tx_size, 0, ta, tl, &txb_ctx); - - const int zero_blk_rate = x->coeff_costs[txs_ctx][get_plane_type(0)] - .txb_skip_cost[txb_ctx.txb_skip_ctx][1]; - rd_stats->zero_rate = zero_blk_rate; - tx_type_rd(cpi, x, tx_size, blk_row, blk_col, 0, block, plane_bsize, - &txb_ctx, rd_stats, ftxs_mode, ref_best_rd, NULL); - const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - if (RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >= - RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse) || - rd_stats->skip == 1) { - rd_stats->rate = zero_blk_rate; - rd_stats->dist = rd_stats->sse; - rd_stats->skip = 1; - set_blk_skip(x, 0, blk_row * mi_width + blk_col, 1); - x->plane[0].eobs[block] = 0; - x->plane[0].txb_entropy_ctx[block] = 0; - update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); - } else { - rd_stats->skip = 0; - set_blk_skip(x, 0, blk_row * mi_width + blk_col, 0); - } - if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) - rd_stats->rate += x->txfm_partition_cost[ctx][0]; - av1_set_txb_context(x, 0, block, tx_size, ta, tl); - txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size, - tx_size); - } else { - const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; - const int bsw = tx_size_wide_unit[sub_txs]; - const int bsh = tx_size_high_unit[sub_txs]; - const int step = bsh * bsw; - RD_STATS pn_rd_stats; - int64_t this_rd = 0; - assert(bsw > 0 && bsh > 0); - - for (int row = 0; row < tx_size_high_unit[tx_size]; row += bsh) { - for (int col = 0; col < tx_size_wide_unit[tx_size]; col += bsw) { - const int offsetr = blk_row + row; - const int offsetc = blk_col + col; - - if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; - - av1_init_rd_stats(&pn_rd_stats); - tx_block_yrd(cpi, x, offsetr, offsetc, block, sub_txs, plane_bsize, - depth + 1, above_ctx, left_ctx, tx_above, tx_left, - ref_best_rd - this_rd, &pn_rd_stats, ftxs_mode); - if (pn_rd_stats.rate == INT_MAX) { - av1_invalid_rd_stats(rd_stats); - return; - } - av1_merge_rd_stats(rd_stats, &pn_rd_stats); - this_rd += RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist); - block += step; - } - } - - if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) - rd_stats->rate += x->txfm_partition_cost[ctx][1]; - } -} - -// Return value 0: early termination triggered, no valid rd cost available; -// 1: rd cost values are valid. -static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, - RD_STATS *rd_stats, BLOCK_SIZE bsize, - int64_t ref_best_rd, FAST_TX_SEARCH_MODE ftxs_mode) { - MACROBLOCKD *const xd = &x->e_mbd; - int is_cost_valid = 1; - int64_t this_rd = 0; - - if (ref_best_rd < 0) is_cost_valid = 0; - - av1_init_rd_stats(rd_stats); - - if (is_cost_valid) { - const struct macroblockd_plane *const pd = &xd->plane[0]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - const int mi_width = mi_size_wide[plane_bsize]; - const int mi_height = mi_size_high[plane_bsize]; - const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, 0); - const int bh = tx_size_high_unit[max_tx_size]; - const int bw = tx_size_wide_unit[max_tx_size]; - const int init_depth = get_search_init_depth( - mi_width, mi_height, 1, &cpi->sf, x->tx_size_search_method); - int idx, idy; - int block = 0; - int step = tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; - ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; - ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; - TXFM_CONTEXT tx_above[MAX_MIB_SIZE]; - TXFM_CONTEXT tx_left[MAX_MIB_SIZE]; - RD_STATS pn_rd_stats; - - av1_get_entropy_contexts(bsize, pd, ctxa, ctxl); - memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width); - memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height); - - for (idy = 0; idy < mi_height; idy += bh) { - for (idx = 0; idx < mi_width; idx += bw) { - av1_init_rd_stats(&pn_rd_stats); - tx_block_yrd(cpi, x, idy, idx, block, max_tx_size, plane_bsize, - init_depth, ctxa, ctxl, tx_above, tx_left, - ref_best_rd - this_rd, &pn_rd_stats, ftxs_mode); - if (pn_rd_stats.rate == INT_MAX) { - av1_invalid_rd_stats(rd_stats); - return 0; - } - av1_merge_rd_stats(rd_stats, &pn_rd_stats); - this_rd += - AOMMIN(RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist), - RDCOST(x->rdmult, pn_rd_stats.zero_rate, pn_rd_stats.sse)); - block += step; - } - } - } - - const int skip_ctx = av1_get_skip_context(xd); - const int s0 = x->skip_cost[skip_ctx][0]; - const int s1 = x->skip_cost[skip_ctx][1]; - int64_t skip_rd = RDCOST(x->rdmult, s1, rd_stats->sse); - this_rd = RDCOST(x->rdmult, rd_stats->rate + s0, rd_stats->dist); - if (skip_rd < this_rd) { - this_rd = skip_rd; - rd_stats->rate = 0; - rd_stats->dist = rd_stats->sse; - rd_stats->skip = 1; - } - if (this_rd > ref_best_rd) is_cost_valid = 0; - - if (!is_cost_valid) { - // reset cost value - av1_invalid_rd_stats(rd_stats); - } - return is_cost_valid; -} - -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. - for (int i = cur_record->index_start - 1; i >= 0; i--) { - if (cur_record->hash_vals[i] == hash) return i; - } - for (int i = cur_record->num - 1; i >= cur_record->index_start; i--) { - if (cur_record->hash_vals[i] == hash) return i; - } - int index; - // If not found - add new RD info into the buffer and return its index - if (cur_record->num < TX_SIZE_RD_RECORD_BUFFER_LEN) { - index = (cur_record->index_start + cur_record->num) % - TX_SIZE_RD_RECORD_BUFFER_LEN; - cur_record->num++; - } else { - index = cur_record->index_start; - cur_record->index_start = - (cur_record->index_start + 1) % TX_SIZE_RD_RECORD_BUFFER_LEN; - } - - cur_record->hash_vals[index] = hash; - av1_zero(cur_record->tx_rd_info[index]); - return index; -} - -typedef struct { - int leaf; - int8_t children[4]; -} RD_RECORD_IDX_NODE; - -static const RD_RECORD_IDX_NODE rd_record_tree_8x8[] = { - { 1, { 0 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_8x16[] = { - { 0, { 1, 2, -1, -1 } }, - { 1, { 0, 0, 0, 0 } }, - { 1, { 0, 0, 0, 0 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_16x8[] = { - { 0, { 1, 2, -1, -1 } }, - { 1, { 0 } }, - { 1, { 0 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_16x16[] = { - { 0, { 1, 2, 3, 4 } }, { 1, { 0 } }, { 1, { 0 } }, { 1, { 0 } }, { 1, { 0 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_1_2[] = { - { 0, { 1, 2, -1, -1 } }, - { 0, { 3, 4, 5, 6 } }, - { 0, { 7, 8, 9, 10 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_2_1[] = { - { 0, { 1, 2, -1, -1 } }, - { 0, { 3, 4, 7, 8 } }, - { 0, { 5, 6, 9, 10 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_sqr[] = { - { 0, { 1, 2, 3, 4 } }, { 0, { 5, 6, 9, 10 } }, { 0, { 7, 8, 11, 12 } }, - { 0, { 13, 14, 17, 18 } }, { 0, { 15, 16, 19, 20 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_64x128[] = { - { 0, { 2, 3, 4, 5 } }, { 0, { 6, 7, 8, 9 } }, - { 0, { 10, 11, 14, 15 } }, { 0, { 12, 13, 16, 17 } }, - { 0, { 18, 19, 22, 23 } }, { 0, { 20, 21, 24, 25 } }, - { 0, { 26, 27, 30, 31 } }, { 0, { 28, 29, 32, 33 } }, - { 0, { 34, 35, 38, 39 } }, { 0, { 36, 37, 40, 41 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_128x64[] = { - { 0, { 2, 3, 6, 7 } }, { 0, { 4, 5, 8, 9 } }, - { 0, { 10, 11, 18, 19 } }, { 0, { 12, 13, 20, 21 } }, - { 0, { 14, 15, 22, 23 } }, { 0, { 16, 17, 24, 25 } }, - { 0, { 26, 27, 34, 35 } }, { 0, { 28, 29, 36, 37 } }, - { 0, { 30, 31, 38, 39 } }, { 0, { 32, 33, 40, 41 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_128x128[] = { - { 0, { 4, 5, 8, 9 } }, { 0, { 6, 7, 10, 11 } }, - { 0, { 12, 13, 16, 17 } }, { 0, { 14, 15, 18, 19 } }, - { 0, { 20, 21, 28, 29 } }, { 0, { 22, 23, 30, 31 } }, - { 0, { 24, 25, 32, 33 } }, { 0, { 26, 27, 34, 35 } }, - { 0, { 36, 37, 44, 45 } }, { 0, { 38, 39, 46, 47 } }, - { 0, { 40, 41, 48, 49 } }, { 0, { 42, 43, 50, 51 } }, - { 0, { 52, 53, 60, 61 } }, { 0, { 54, 55, 62, 63 } }, - { 0, { 56, 57, 64, 65 } }, { 0, { 58, 59, 66, 67 } }, - { 0, { 68, 69, 76, 77 } }, { 0, { 70, 71, 78, 79 } }, - { 0, { 72, 73, 80, 81 } }, { 0, { 74, 75, 82, 83 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_1_4[] = { - { 0, { 1, -1, 2, -1 } }, - { 0, { 3, 4, -1, -1 } }, - { 0, { 5, 6, -1, -1 } }, -}; - -static const RD_RECORD_IDX_NODE rd_record_tree_4_1[] = { - { 0, { 1, 2, -1, -1 } }, - { 0, { 3, 4, -1, -1 } }, - { 0, { 5, 6, -1, -1 } }, -}; - -static const RD_RECORD_IDX_NODE *rd_record_tree[BLOCK_SIZES_ALL] = { - NULL, // BLOCK_4X4 - NULL, // BLOCK_4X8 - NULL, // BLOCK_8X4 - rd_record_tree_8x8, // BLOCK_8X8 - rd_record_tree_8x16, // BLOCK_8X16 - rd_record_tree_16x8, // BLOCK_16X8 - rd_record_tree_16x16, // BLOCK_16X16 - rd_record_tree_1_2, // BLOCK_16X32 - rd_record_tree_2_1, // BLOCK_32X16 - rd_record_tree_sqr, // BLOCK_32X32 - rd_record_tree_1_2, // BLOCK_32X64 - rd_record_tree_2_1, // BLOCK_64X32 - rd_record_tree_sqr, // BLOCK_64X64 - rd_record_tree_64x128, // BLOCK_64X128 - rd_record_tree_128x64, // BLOCK_128X64 - rd_record_tree_128x128, // BLOCK_128X128 - NULL, // BLOCK_4X16 - NULL, // BLOCK_16X4 - rd_record_tree_1_4, // BLOCK_8X32 - rd_record_tree_4_1, // BLOCK_32X8 - rd_record_tree_1_4, // BLOCK_16X64 - rd_record_tree_4_1, // BLOCK_64X16 -}; - -static const int rd_record_tree_size[BLOCK_SIZES_ALL] = { - 0, // BLOCK_4X4 - 0, // BLOCK_4X8 - 0, // BLOCK_8X4 - sizeof(rd_record_tree_8x8) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X8 - sizeof(rd_record_tree_8x16) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X16 - sizeof(rd_record_tree_16x8) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X8 - sizeof(rd_record_tree_16x16) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X16 - sizeof(rd_record_tree_1_2) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X32 - sizeof(rd_record_tree_2_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X16 - sizeof(rd_record_tree_sqr) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X32 - sizeof(rd_record_tree_1_2) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X64 - sizeof(rd_record_tree_2_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X32 - sizeof(rd_record_tree_sqr) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X64 - sizeof(rd_record_tree_64x128) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X128 - sizeof(rd_record_tree_128x64) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_128X64 - sizeof(rd_record_tree_128x128) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_128X128 - 0, // BLOCK_4X16 - 0, // BLOCK_16X4 - sizeof(rd_record_tree_1_4) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X32 - sizeof(rd_record_tree_4_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X8 - sizeof(rd_record_tree_1_4) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X64 - sizeof(rd_record_tree_4_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X16 -}; - -static INLINE void init_rd_record_tree(TXB_RD_INFO_NODE *tree, - BLOCK_SIZE bsize) { - const RD_RECORD_IDX_NODE *rd_record = rd_record_tree[bsize]; - const int size = rd_record_tree_size[bsize]; - for (int i = 0; i < size; ++i) { - if (rd_record[i].leaf) { - av1_zero(tree[i].children); - } else { - for (int j = 0; j < 4; ++j) { - const int8_t idx = rd_record[i].children[j]; - tree[i].children[j] = idx > 0 ? &tree[idx] : NULL; - } - } - } -} - -// Go through all TX blocks that could be used in TX size search, compute -// residual hash values for them and find matching RD info that stores previous -// RD search results for these TX blocks. The idea is to prevent repeated -// rate/distortion computations that happen because of the combination of -// partition and TX size search. The resulting RD info records are returned in -// the form of a quadtree for easier access in actual TX size search. -static int find_tx_size_rd_records(MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, - int mi_col, TXB_RD_INFO_NODE *dst_rd_info) { - TXB_RD_RECORD *rd_records_table[4] = { x->txb_rd_record_8X8, - x->txb_rd_record_16X16, - x->txb_rd_record_32X32, - x->txb_rd_record_64X64 }; - const TX_SIZE max_square_tx_size = max_txsize_lookup[bsize]; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - - // Hashing is performed only for square TX sizes larger than TX_4X4 - if (max_square_tx_size < TX_8X8) return 0; - const int diff_stride = bw; - const struct macroblock_plane *const p = &x->plane[0]; - const int16_t *diff = &p->src_diff[0]; - init_rd_record_tree(dst_rd_info, bsize); - // Coordinates of the top-left corner of current block within the superblock - // measured in pixels: - const int mi_row_in_sb = (mi_row % MAX_MIB_SIZE) << MI_SIZE_LOG2; - const int mi_col_in_sb = (mi_col % MAX_MIB_SIZE) << MI_SIZE_LOG2; - int cur_rd_info_idx = 0; - int cur_tx_depth = 0; - TX_SIZE cur_tx_size = max_txsize_rect_lookup[bsize]; - while (cur_tx_depth <= MAX_VARTX_DEPTH) { - const int cur_tx_bw = tx_size_wide[cur_tx_size]; - const int cur_tx_bh = tx_size_high[cur_tx_size]; - if (cur_tx_bw < 8 || cur_tx_bh < 8) break; - const TX_SIZE next_tx_size = sub_tx_size_map[cur_tx_size]; - const int tx_size_idx = cur_tx_size - TX_8X8; - for (int row = 0; row < bh; row += cur_tx_bh) { - for (int col = 0; col < bw; col += cur_tx_bw) { - if (cur_tx_bw != cur_tx_bh) { - // Use dummy nodes for all rectangular transforms within the - // TX size search tree. - dst_rd_info[cur_rd_info_idx].rd_info_array = NULL; - } else { - // Get spatial location of this TX block within the superblock - // (measured in cur_tx_bsize units). - const int row_in_sb = (mi_row_in_sb + row) / cur_tx_bh; - const int col_in_sb = (mi_col_in_sb + col) / cur_tx_bw; - - int16_t hash_data[MAX_SB_SQUARE]; - int16_t *cur_hash_row = hash_data; - const int16_t *cur_diff_row = diff + row * diff_stride + col; - for (int i = 0; i < cur_tx_bh; i++) { - memcpy(cur_hash_row, cur_diff_row, sizeof(*hash_data) * cur_tx_bw); - cur_hash_row += cur_tx_bw; - cur_diff_row += diff_stride; - } - const int hash = av1_get_crc32c_value(&x->mb_rd_record.crc_calculator, - (uint8_t *)hash_data, - 2 * cur_tx_bw * cur_tx_bh); - // Find corresponding RD info based on the hash value. - const int record_idx = - row_in_sb * (MAX_MIB_SIZE >> (tx_size_idx + 1)) + col_in_sb; - TXB_RD_RECORD *records = &rd_records_table[tx_size_idx][record_idx]; - int idx = find_tx_size_rd_info(records, hash); - dst_rd_info[cur_rd_info_idx].rd_info_array = - &records->tx_rd_info[idx]; - } - ++cur_rd_info_idx; - } - } - cur_tx_size = next_tx_size; - ++cur_tx_depth; - } - return 1; -} - -// Search for best transform size and type for luma inter blocks. -static AOM_INLINE void pick_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, - RD_STATS *rd_stats, - BLOCK_SIZE bsize, int mi_row, - int mi_col, int64_t ref_best_rd) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *const xd = &x->e_mbd; - assert(is_inter_block(xd->mi[0])); - - av1_invalid_rd_stats(rd_stats); - - if (cpi->sf.model_based_prune_tx_search_level && ref_best_rd != INT64_MAX) { - int model_rate; - int64_t model_dist; - int model_skip; - model_rd_sb_fn[MODELRD_TYPE_TX_SEARCH_PRUNE]( - cpi, bsize, x, xd, 0, 0, mi_row, mi_col, &model_rate, &model_dist, - &model_skip, NULL, NULL, NULL, NULL); - const int64_t model_rd = RDCOST(x->rdmult, model_rate, model_dist); - // If the modeled rd is a lot worse than the best so far, breakout. - // TODO(debargha, urvang): Improve the model and make the check below - // tighter. - assert(cpi->sf.model_based_prune_tx_search_level >= 0 && - cpi->sf.model_based_prune_tx_search_level <= 2); - static const int prune_factor_by8[] = { 3, 5 }; - if (!model_skip && - ((model_rd * - prune_factor_by8[cpi->sf.model_based_prune_tx_search_level - 1]) >> - 3) > ref_best_rd) - return; - } - - 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[bsize] < xd->tile.mi_row_end) && - mi_col >= xd->tile.mi_col_start && - (mi_col + mi_size_wide[bsize] < xd->tile.mi_col_end); - const int is_mb_rd_hash_enabled = (within_border && cpi->sf.use_mb_rd_hash); - const int n4 = bsize_to_num_blk(bsize); - if (is_mb_rd_hash_enabled) { - hash = get_block_residue_hash(x, bsize); - 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); - 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 && - predict_skip_flag(x, bsize, &dist, cm->reduced_tx_set_used)) { - set_skip_flag(x, rd_stats, bsize, 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); - return; - } -#if CONFIG_SPEED_STATS - ++x->tx_search_count; -#endif // CONFIG_SPEED_STATS - - // Precompute residual hashes and find existing or add new RD records to - // store and reuse rate and distortion values to speed up TX size search. - TXB_RD_INFO_NODE matched_rd_info[4 + 16 + 64]; - int found_rd_info = 0; - if (ref_best_rd != INT64_MAX && within_border && cpi->sf.use_inter_txb_hash) { - found_rd_info = - find_tx_size_rd_records(x, bsize, mi_row, mi_col, matched_rd_info); - } - - int found = 0; - RD_STATS this_rd_stats; - av1_init_rd_stats(&this_rd_stats); - const int64_t rd = - select_tx_size_and_type(cpi, x, &this_rd_stats, bsize, ref_best_rd, - found_rd_info ? matched_rd_info : NULL); - - if (rd < INT64_MAX) { - *rd_stats = this_rd_stats; - found = 1; - } - - // We should always find at least one candidate unless ref_best_rd is less - // than INT64_MAX (in which case, all the calls to select_tx_size_fix_type - // might have failed to find something better) - assert(IMPLIES(!found, ref_best_rd != INT64_MAX)); - if (!found) return; - - // 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); - } -} - -static AOM_INLINE void model_rd_for_sb_with_fullrdy( - const AV1_COMP *const cpi, BLOCK_SIZE bsize, MACROBLOCK *x, MACROBLOCKD *xd, - int plane_from, int plane_to, int mi_row, int mi_col, int *out_rate_sum, - int64_t *out_dist_sum, int *skip_txfm_sb, int64_t *skip_sse_sb, - int *plane_rate, int64_t *plane_sse, int64_t *plane_dist) { - const int ref = xd->mi[0]->ref_frame[0]; - - int64_t rate_sum = 0; - int64_t dist_sum = 0; - int64_t total_sse = 0; - assert(bsize < BLOCK_SIZES_ALL); - - for (int plane = plane_from; plane <= plane_to; ++plane) { - struct macroblock_plane *const p = &x->plane[plane]; - struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); - assert(plane_bsize < BLOCK_SIZES_ALL); - const int bw = block_size_wide[plane_bsize]; - const int bh = block_size_high[plane_bsize]; - int64_t sse; - int rate; - int64_t dist; - - if (x->skip_chroma_rd && plane) continue; - - sse = calculate_sse(xd, p, pd, bw, bh); - - RD_STATS rd_stats; - if (plane == 0) { - pick_tx_size_type_yrd(cpi, x, &rd_stats, bsize, mi_row, mi_col, - INT64_MAX); - if (rd_stats.rate == INT_MAX) { - rate = 0; - dist = sse << 4; - } else { - rate = rd_stats.rate; - dist = rd_stats.dist; - } - } else { - model_rd_with_curvfit(cpi, x, plane_bsize, plane, sse, bw * bh, &rate, - &dist); - } - - if (plane == 0) x->pred_sse[ref] = (unsigned int)AOMMIN(sse, UINT_MAX); - - total_sse += sse; - rate_sum += rate; - dist_sum += dist; - - if (plane_rate) plane_rate[plane] = rate; - if (plane_sse) plane_sse[plane] = sse; - if (plane_dist) plane_dist[plane] = dist; - } - - if (skip_txfm_sb) *skip_txfm_sb = total_sse == 0; - if (skip_sse_sb) *skip_sse_sb = total_sse << 4; - *out_rate_sum = (int)rate_sum; - *out_dist_sum = dist_sum; -} - -static AOM_INLINE void rd_pick_palette_intra_sbuv( - const AV1_COMP *const cpi, MACROBLOCK *x, int dc_mode_cost, - uint8_t *best_palette_color_map, MB_MODE_INFO *const best_mbmi, - int64_t *best_rd, int *rate, int *rate_tokenonly, int64_t *distortion, - int *skippable) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - assert( - av1_allow_palette(cpi->common.allow_screen_content_tools, mbmi->sb_type)); - PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; - const BLOCK_SIZE bsize = mbmi->sb_type; - const SequenceHeader *const seq_params = &cpi->common.seq_params; - int this_rate; - int64_t this_rd; - int colors_u, colors_v, colors; - const int src_stride = x->plane[1].src.stride; - const uint8_t *const src_u = x->plane[1].src.buf; - const uint8_t *const src_v = x->plane[2].src.buf; - uint8_t *const color_map = xd->plane[1].color_index_map; - RD_STATS tokenonly_rd_stats; - int plane_block_width, plane_block_height, rows, cols; - av1_get_block_dimensions(bsize, 1, xd, &plane_block_width, - &plane_block_height, &rows, &cols); - - mbmi->uv_mode = UV_DC_PRED; - - int count_buf[1 << 12]; // Maximum (1 << 12) color levels. - if (seq_params->use_highbitdepth) { - colors_u = av1_count_colors_highbd(src_u, src_stride, rows, cols, - seq_params->bit_depth, count_buf); - colors_v = av1_count_colors_highbd(src_v, src_stride, rows, cols, - seq_params->bit_depth, count_buf); - } else { - colors_u = av1_count_colors(src_u, src_stride, rows, cols, count_buf); - colors_v = av1_count_colors(src_v, src_stride, rows, cols, count_buf); - } - - uint16_t color_cache[2 * PALETTE_MAX_SIZE]; - const int n_cache = av1_get_palette_cache(xd, 1, color_cache); - - colors = colors_u > colors_v ? colors_u : colors_v; - if (colors > 1 && colors <= 64) { - int r, c, n, i, j; - const int max_itr = 50; - int lb_u, ub_u, val_u; - int lb_v, ub_v, val_v; - int *const data = x->palette_buffer->kmeans_data_buf; - int centroids[2 * PALETTE_MAX_SIZE]; - - uint16_t *src_u16 = CONVERT_TO_SHORTPTR(src_u); - uint16_t *src_v16 = CONVERT_TO_SHORTPTR(src_v); - if (seq_params->use_highbitdepth) { - lb_u = src_u16[0]; - ub_u = src_u16[0]; - lb_v = src_v16[0]; - ub_v = src_v16[0]; - } else { - lb_u = src_u[0]; - ub_u = src_u[0]; - lb_v = src_v[0]; - ub_v = src_v[0]; - } - - for (r = 0; r < rows; ++r) { - for (c = 0; c < cols; ++c) { - if (seq_params->use_highbitdepth) { - val_u = src_u16[r * src_stride + c]; - val_v = src_v16[r * src_stride + c]; - data[(r * cols + c) * 2] = val_u; - data[(r * cols + c) * 2 + 1] = val_v; - } else { - val_u = src_u[r * src_stride + c]; - val_v = src_v[r * src_stride + c]; - data[(r * cols + c) * 2] = val_u; - data[(r * cols + c) * 2 + 1] = val_v; - } - if (val_u < lb_u) - lb_u = val_u; - else if (val_u > ub_u) - ub_u = val_u; - if (val_v < lb_v) - lb_v = val_v; - else if (val_v > ub_v) - ub_v = val_v; - } - } - - for (n = colors > PALETTE_MAX_SIZE ? PALETTE_MAX_SIZE : colors; n >= 2; - --n) { - for (i = 0; i < n; ++i) { - centroids[i * 2] = lb_u + (2 * i + 1) * (ub_u - lb_u) / n / 2; - centroids[i * 2 + 1] = lb_v + (2 * i + 1) * (ub_v - lb_v) / n / 2; - } - av1_k_means(data, centroids, color_map, rows * cols, n, 2, max_itr); - optimize_palette_colors(color_cache, n_cache, n, 2, centroids); - // Sort the U channel colors in ascending order. - for (i = 0; i < 2 * (n - 1); i += 2) { - int min_idx = i; - int min_val = centroids[i]; - for (j = i + 2; j < 2 * n; j += 2) - if (centroids[j] < min_val) min_val = centroids[j], min_idx = j; - if (min_idx != i) { - int temp_u = centroids[i], temp_v = centroids[i + 1]; - centroids[i] = centroids[min_idx]; - centroids[i + 1] = centroids[min_idx + 1]; - centroids[min_idx] = temp_u, centroids[min_idx + 1] = temp_v; - } - } - av1_calc_indices(data, centroids, color_map, rows * cols, n, 2); - extend_palette_color_map(color_map, cols, rows, plane_block_width, - plane_block_height); - pmi->palette_size[1] = n; - for (i = 1; i < 3; ++i) { - for (j = 0; j < n; ++j) { - if (seq_params->use_highbitdepth) - pmi->palette_colors[i * PALETTE_MAX_SIZE + j] = clip_pixel_highbd( - (int)centroids[j * 2 + i - 1], seq_params->bit_depth); - else - pmi->palette_colors[i * PALETTE_MAX_SIZE + j] = - clip_pixel((int)centroids[j * 2 + i - 1]); - } - } - - super_block_uvrd(cpi, x, &tokenonly_rd_stats, bsize, *best_rd); - if (tokenonly_rd_stats.rate == INT_MAX) continue; - this_rate = tokenonly_rd_stats.rate + - intra_mode_info_cost_uv(cpi, x, mbmi, bsize, dc_mode_cost); - this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - if (this_rd < *best_rd) { - *best_rd = this_rd; - *best_mbmi = *mbmi; - memcpy(best_palette_color_map, color_map, - plane_block_width * plane_block_height * - sizeof(best_palette_color_map[0])); - *rate = this_rate; - *distortion = tokenonly_rd_stats.dist; - *rate_tokenonly = tokenonly_rd_stats.rate; - *skippable = tokenonly_rd_stats.skip; - } - } - } - if (best_mbmi->palette_mode_info.palette_size[1] > 0) { - memcpy(color_map, best_palette_color_map, - plane_block_width * plane_block_height * - sizeof(best_palette_color_map[0])); - } -} - -// Run RD calculation with given chroma intra prediction angle., and return -// the RD cost. Update the best mode info. if the RD cost is the best so far. -static int64_t pick_intra_angle_routine_sbuv( - const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, - int rate_overhead, int64_t best_rd_in, int *rate, RD_STATS *rd_stats, - int *best_angle_delta, int64_t *best_rd) { - MB_MODE_INFO *mbmi = x->e_mbd.mi[0]; - assert(!is_inter_block(mbmi)); - int this_rate; - int64_t this_rd; - RD_STATS tokenonly_rd_stats; - - if (!super_block_uvrd(cpi, x, &tokenonly_rd_stats, bsize, best_rd_in)) - return INT64_MAX; - this_rate = tokenonly_rd_stats.rate + - intra_mode_info_cost_uv(cpi, x, mbmi, bsize, rate_overhead); - this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - if (this_rd < *best_rd) { - *best_rd = this_rd; - *best_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; - *rate = this_rate; - rd_stats->rate = tokenonly_rd_stats.rate; - rd_stats->dist = tokenonly_rd_stats.dist; - rd_stats->skip = tokenonly_rd_stats.skip; - } - return this_rd; -} - -// With given chroma directional intra prediction mode, pick the best angle -// delta. Return true if a RD cost that is smaller than the input one is found. -static int rd_pick_intra_angle_sbuv(const AV1_COMP *const cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int rate_overhead, - int64_t best_rd, int *rate, - RD_STATS *rd_stats) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - int i, angle_delta, best_angle_delta = 0; - int64_t this_rd, best_rd_in, rd_cost[2 * (MAX_ANGLE_DELTA + 2)]; - - rd_stats->rate = INT_MAX; - rd_stats->skip = 0; - rd_stats->dist = INT64_MAX; - for (i = 0; i < 2 * (MAX_ANGLE_DELTA + 2); ++i) rd_cost[i] = INT64_MAX; - - for (angle_delta = 0; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { - for (i = 0; i < 2; ++i) { - best_rd_in = (best_rd == INT64_MAX) - ? INT64_MAX - : (best_rd + (best_rd >> ((angle_delta == 0) ? 3 : 5))); - mbmi->angle_delta[PLANE_TYPE_UV] = (1 - 2 * i) * angle_delta; - this_rd = pick_intra_angle_routine_sbuv(cpi, x, bsize, rate_overhead, - best_rd_in, rate, rd_stats, - &best_angle_delta, &best_rd); - rd_cost[2 * angle_delta + i] = this_rd; - if (angle_delta == 0) { - if (this_rd == INT64_MAX) return 0; - rd_cost[1] = this_rd; - break; - } - } - } - - assert(best_rd != INT64_MAX); - for (angle_delta = 1; angle_delta <= MAX_ANGLE_DELTA; angle_delta += 2) { - int64_t rd_thresh; - for (i = 0; i < 2; ++i) { - int skip_search = 0; - rd_thresh = best_rd + (best_rd >> 5); - if (rd_cost[2 * (angle_delta + 1) + i] > rd_thresh && - rd_cost[2 * (angle_delta - 1) + i] > rd_thresh) - skip_search = 1; - if (!skip_search) { - mbmi->angle_delta[PLANE_TYPE_UV] = (1 - 2 * i) * angle_delta; - pick_intra_angle_routine_sbuv(cpi, x, bsize, rate_overhead, best_rd, - rate, rd_stats, &best_angle_delta, - &best_rd); - } - } - } - - mbmi->angle_delta[PLANE_TYPE_UV] = best_angle_delta; - return rd_stats->rate != INT_MAX; -} - -#define PLANE_SIGN_TO_JOINT_SIGN(plane, a, b) \ - (plane == CFL_PRED_U ? a * CFL_SIGNS + b - 1 : b * CFL_SIGNS + a - 1) -static int cfl_rd_pick_alpha(MACROBLOCK *const x, const AV1_COMP *const cpi, - TX_SIZE tx_size, int64_t best_rd) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - - const BLOCK_SIZE bsize = mbmi->sb_type; -#if CONFIG_DEBUG - assert(is_cfl_allowed(xd) && cpi->oxcf.enable_cfl_intra); - const int ssx = xd->plane[AOM_PLANE_U].subsampling_x; - const int ssy = xd->plane[AOM_PLANE_U].subsampling_y; - const BLOCK_SIZE plane_bsize = get_plane_block_size(mbmi->sb_type, ssx, ssy); - (void)plane_bsize; - assert(plane_bsize < BLOCK_SIZES_ALL); - if (!xd->lossless[mbmi->segment_id]) { - assert(block_size_wide[plane_bsize] == tx_size_wide[tx_size]); - assert(block_size_high[plane_bsize] == tx_size_high[tx_size]); - } -#endif // CONFIG_DEBUG - - xd->cfl.use_dc_pred_cache = 1; - const int64_t mode_rd = - RDCOST(x->rdmult, - x->intra_uv_mode_cost[CFL_ALLOWED][mbmi->mode][UV_CFL_PRED], 0); - int64_t best_rd_uv[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; - int best_c[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; -#if CONFIG_DEBUG - int best_rate_uv[CFL_JOINT_SIGNS][CFL_PRED_PLANES]; -#endif // CONFIG_DEBUG - - for (int plane = 0; plane < CFL_PRED_PLANES; plane++) { - RD_STATS rd_stats; - av1_init_rd_stats(&rd_stats); - for (int joint_sign = 0; joint_sign < CFL_JOINT_SIGNS; joint_sign++) { - best_rd_uv[joint_sign][plane] = INT64_MAX; - best_c[joint_sign][plane] = 0; - } - // Collect RD stats for an alpha value of zero in this plane. - // Skip i == CFL_SIGN_ZERO as (0, 0) is invalid. - for (int i = CFL_SIGN_NEG; i < CFL_SIGNS; i++) { - const int8_t joint_sign = - PLANE_SIGN_TO_JOINT_SIGN(plane, CFL_SIGN_ZERO, i); - if (i == CFL_SIGN_NEG) { - 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, 0); - if (rd_stats.rate == INT_MAX) break; - } - const int alpha_rate = x->cfl_cost[joint_sign][plane][0]; - best_rd_uv[joint_sign][plane] = - RDCOST(x->rdmult, rd_stats.rate + alpha_rate, rd_stats.dist); -#if CONFIG_DEBUG - best_rate_uv[joint_sign][plane] = rd_stats.rate; -#endif // CONFIG_DEBUG - } - } - - int8_t best_joint_sign = -1; - - for (int plane = 0; plane < CFL_PRED_PLANES; plane++) { - for (int pn_sign = CFL_SIGN_NEG; pn_sign < CFL_SIGNS; pn_sign++) { - int progress = 0; - for (int c = 0; c < CFL_ALPHABET_SIZE; c++) { - int flag = 0; - RD_STATS rd_stats; - if (c > 2 && progress < c) break; - av1_init_rd_stats(&rd_stats); - for (int i = 0; i < CFL_SIGNS; i++) { - const int8_t joint_sign = PLANE_SIGN_TO_JOINT_SIGN(plane, pn_sign, i); - if (i == 0) { - 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, - 0); - if (rd_stats.rate == INT_MAX) break; - } - const int alpha_rate = x->cfl_cost[joint_sign][plane][c]; - int64_t this_rd = - RDCOST(x->rdmult, rd_stats.rate + alpha_rate, rd_stats.dist); - if (this_rd >= best_rd_uv[joint_sign][plane]) continue; - best_rd_uv[joint_sign][plane] = this_rd; - best_c[joint_sign][plane] = c; -#if CONFIG_DEBUG - best_rate_uv[joint_sign][plane] = rd_stats.rate; -#endif // CONFIG_DEBUG - flag = 2; - if (best_rd_uv[joint_sign][!plane] == INT64_MAX) continue; - this_rd += mode_rd + best_rd_uv[joint_sign][!plane]; - if (this_rd >= best_rd) continue; - best_rd = this_rd; - best_joint_sign = joint_sign; - } - progress += flag; - } - } - } - - int best_rate_overhead = INT_MAX; - uint8_t ind = 0; - if (best_joint_sign >= 0) { - const int u = best_c[best_joint_sign][CFL_PRED_U]; - const int v = best_c[best_joint_sign][CFL_PRED_V]; - ind = (u << CFL_ALPHABET_SIZE_LOG2) + v; - best_rate_overhead = x->cfl_cost[best_joint_sign][CFL_PRED_U][u] + - x->cfl_cost[best_joint_sign][CFL_PRED_V][v]; -#if CONFIG_DEBUG - xd->cfl.rate = x->intra_uv_mode_cost[CFL_ALLOWED][mbmi->mode][UV_CFL_PRED] + - best_rate_overhead + - best_rate_uv[best_joint_sign][CFL_PRED_U] + - best_rate_uv[best_joint_sign][CFL_PRED_V]; -#endif // CONFIG_DEBUG - } else { - best_joint_sign = 0; - } - - mbmi->cfl_alpha_idx = ind; - mbmi->cfl_alpha_signs = best_joint_sign; - xd->cfl.use_dc_pred_cache = 0; - xd->cfl.dc_pred_is_cached[0] = 0; - xd->cfl.dc_pred_is_cached[1] = 0; - return best_rate_overhead; -} - -static AOM_INLINE void init_sbuv_mode(MB_MODE_INFO *const mbmi) { - mbmi->uv_mode = UV_DC_PRED; - mbmi->palette_mode_info.palette_size[1] = 0; -} - -static int64_t rd_pick_intra_sbuv_mode(const AV1_COMP *const cpi, MACROBLOCK *x, - int *rate, int *rate_tokenonly, - int64_t *distortion, int *skippable, - BLOCK_SIZE bsize, TX_SIZE max_tx_size) { - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - assert(!is_inter_block(mbmi)); - MB_MODE_INFO best_mbmi = *mbmi; - int64_t best_rd = INT64_MAX, this_rd; - - for (int mode_idx = 0; mode_idx < UV_INTRA_MODES; ++mode_idx) { - int this_rate; - RD_STATS tokenonly_rd_stats; - UV_PREDICTION_MODE mode = uv_rd_search_mode_order[mode_idx]; - const int is_directional_mode = av1_is_directional_mode(get_uv_mode(mode)); - 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; - if (mode == UV_CFL_PRED) { - if (!is_cfl_allowed(xd) || !cpi->oxcf.enable_cfl_intra) continue; - assert(!is_directional_mode); - const TX_SIZE uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); - cfl_alpha_rate = cfl_rd_pick_alpha(x, cpi, uv_tx_size, best_rd); - if (cfl_alpha_rate == INT_MAX) continue; - } - mbmi->angle_delta[PLANE_TYPE_UV] = 0; - if (is_directional_mode && av1_use_angle_delta(mbmi->sb_type) && - cpi->oxcf.enable_angle_delta) { - const int rate_overhead = - x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][mode]; - if (!rd_pick_intra_angle_sbuv(cpi, x, bsize, rate_overhead, best_rd, - &this_rate, &tokenonly_rd_stats)) - continue; - } else { - if (!super_block_uvrd(cpi, x, &tokenonly_rd_stats, bsize, best_rd)) { - continue; - } - } - const int mode_cost = - x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][mode] + - cfl_alpha_rate; - this_rate = tokenonly_rd_stats.rate + - intra_mode_info_cost_uv(cpi, x, mbmi, bsize, mode_cost); - if (mode == UV_CFL_PRED) { - assert(is_cfl_allowed(xd) && cpi->oxcf.enable_cfl_intra); -#if CONFIG_DEBUG - if (!xd->lossless[mbmi->segment_id]) - assert(xd->cfl.rate == tokenonly_rd_stats.rate + mode_cost); -#endif // CONFIG_DEBUG - } - this_rd = RDCOST(x->rdmult, this_rate, tokenonly_rd_stats.dist); - - if (this_rd < best_rd) { - best_mbmi = *mbmi; - best_rd = this_rd; - *rate = this_rate; - *rate_tokenonly = tokenonly_rd_stats.rate; - *distortion = tokenonly_rd_stats.dist; - *skippable = tokenonly_rd_stats.skip; - } - } - - const int try_palette = - cpi->oxcf.enable_palette && - av1_allow_palette(cpi->common.allow_screen_content_tools, mbmi->sb_type); - if (try_palette) { - uint8_t *best_palette_color_map = x->palette_buffer->best_palette_color_map; - rd_pick_palette_intra_sbuv( - cpi, x, - x->intra_uv_mode_cost[is_cfl_allowed(xd)][mbmi->mode][UV_DC_PRED], - best_palette_color_map, &best_mbmi, &best_rd, rate, rate_tokenonly, - distortion, skippable); - } - - *mbmi = best_mbmi; - // Make sure we actually chose a mode - assert(best_rd < INT64_MAX); - return best_rd; -} - -static AOM_INLINE void choose_intra_uv_mode( - const AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize, - TX_SIZE max_tx_size, int *rate_uv, int *rate_uv_tokenonly, int64_t *dist_uv, - int *skip_uv, UV_PREDICTION_MODE *mode_uv) { - const AV1_COMMON *const cm = &cpi->common; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - 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); - // Use an estimated rd for uv_intra based on DC_PRED if the - // appropriate speed flag is set. - init_sbuv_mode(mbmi); - if (x->skip_chroma_rd) { - *rate_uv = 0; - *rate_uv_tokenonly = 0; - *dist_uv = 0; - *skip_uv = 1; - *mode_uv = UV_DC_PRED; - return; - } - xd->cfl.is_chroma_reference = - is_chroma_reference(mi_row, mi_col, bsize, cm->seq_params.subsampling_x, - cm->seq_params.subsampling_y); - bsize = scale_chroma_bsize(bsize, xd->plane[AOM_PLANE_U].subsampling_x, - xd->plane[AOM_PLANE_U].subsampling_y); - // Only store reconstructed luma when there's chroma RDO. When there's no - // chroma RDO, the reconstructed luma will be stored in encode_superblock(). - xd->cfl.store_y = store_cfl_required_rdo(cm, x); - if (xd->cfl.store_y) { - // Restore reconstructed luma values. - av1_encode_intra_block_plane(cpi, x, mbmi->sb_type, AOM_PLANE_Y, - cpi->optimize_seg_arr[mbmi->segment_id], - mi_row, mi_col); - xd->cfl.store_y = 0; - } - rd_pick_intra_sbuv_mode(cpi, x, rate_uv, rate_uv_tokenonly, dist_uv, skip_uv, - bsize, max_tx_size); - *mode_uv = mbmi->uv_mode; -} - static int cost_mv_ref(const MACROBLOCK *const x, PREDICTION_MODE mode, int16_t mode_context) { if (is_inter_compound_mode(mode)) { @@ -6865,233 +732,10 @@ static int cost_mv_ref(const MACROBLOCK *const x, PREDICTION_MODE mode, } } -static INLINE int get_interinter_compound_mask_rate( - const MACROBLOCK *const x, const MB_MODE_INFO *const mbmi) { - const COMPOUND_TYPE compound_type = mbmi->interinter_comp.type; - // This function will be called only for COMPOUND_WEDGE and COMPOUND_DIFFWTD - if (compound_type == COMPOUND_WEDGE) { - return get_interinter_wedge_bits(mbmi->sb_type) > 0 - ? av1_cost_literal(1) + - x->wedge_idx_cost[mbmi->sb_type] - [mbmi->interinter_comp.wedge_index] - : 0; - } else { - assert(compound_type == COMPOUND_DIFFWTD); - return av1_cost_literal(1); - } -} - -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 || - (mv->col >> 3) < mv_limits->col_min || - (mv->col >> 3) > mv_limits->col_max; -} - static INLINE PREDICTION_MODE get_single_mode(PREDICTION_MODE this_mode, - int ref_idx, int is_comp_pred) { - PREDICTION_MODE single_mode; - if (is_comp_pred) { - single_mode = - ref_idx ? compound_ref1_mode(this_mode) : compound_ref0_mode(this_mode); - } else { - single_mode = this_mode; - } - return single_mode; -} - -static AOM_INLINE void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int_mv *cur_mv, - int mi_row, int mi_col, - const uint8_t *mask, int mask_stride, - int *rate_mv) { - const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - const int plane = 0; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - // This function should only ever be called for compound modes - assert(has_second_ref(mbmi)); - const int_mv init_mv[2] = { cur_mv[0], cur_mv[1] }; - const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] }; - int_mv ref_mv[2]; - int ite, ref; - - WarpTypesAllowed warp_types[2]; - for (ref = 0; ref < 2; ++ref) { - const WarpedMotionParams *const wm = - &xd->global_motion[xd->mi[0]->ref_frame[ref]]; - const int is_global = is_global_mv_block(xd->mi[0], wm->wmtype); - warp_types[ref].global_warp_allowed = is_global; - warp_types[ref].local_warp_allowed = mbmi->motion_mode == WARPED_CAUSAL; - } - - // Get the prediction block from the 'other' reference frame. - const int_interpfilters interp_filters = - av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - - (void)warp_types; - - InterPredParams inter_pred_params; - - av1_init_inter_params(&inter_pred_params, pw, ph, mi_col * MI_SIZE, - mi_row * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, - &cm->sf_identity, interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - - // Do joint motion search in compound mode to get more accurate mv. - struct buf_2d backup_yv12[2][MAX_MB_PLANE]; - int last_besterr[2] = { INT_MAX, INT_MAX }; - const YV12_BUFFER_CONFIG *const scaled_ref_frame[2] = { - av1_get_scaled_ref_frame(cpi, refs[0]), - av1_get_scaled_ref_frame(cpi, refs[1]) - }; - - // Prediction buffer from second frame. - DECLARE_ALIGNED(16, uint8_t, second_pred16[MAX_SB_SQUARE * sizeof(uint16_t)]); - uint8_t *second_pred = get_buf_by_bd(xd, second_pred16); - - MV *const best_mv = &x->best_mv.as_mv; - const int search_range = SEARCH_RANGE_8P; - const int sadpb = x->sadperbit16; - // Allow joint search multiple times iteratively for each reference frame - // and break out of the search loop if it couldn't find a better mv. - for (ite = 0; ite < 4; ite++) { - struct buf_2d ref_yv12[2]; - int bestsme = INT_MAX; - MvLimits tmp_mv_limits = x->mv_limits; - int id = ite % 2; // Even iterations search in the first reference frame, - // odd iterations search in the second. The predictor - // found for the 'other' reference frame is factored in. - if (ite >= 2 && cur_mv[!id].as_int == init_mv[!id].as_int) { - if (cur_mv[id].as_int == init_mv[id].as_int) { - break; - } else { - int_mv cur_int_mv, init_int_mv; - cur_int_mv.as_mv.col = cur_mv[id].as_mv.col >> 3; - cur_int_mv.as_mv.row = cur_mv[id].as_mv.row >> 3; - init_int_mv.as_mv.row = init_mv[id].as_mv.row >> 3; - init_int_mv.as_mv.col = init_mv[id].as_mv.col >> 3; - if (cur_int_mv.as_int == init_int_mv.as_int) { - break; - } - } - } - for (ref = 0; ref < 2; ++ref) { - ref_mv[ref] = av1_get_ref_mv(x, ref); - // 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. - if (scaled_ref_frame[ref]) { - int i; - for (i = 0; i < num_planes; i++) - backup_yv12[ref][i] = xd->plane[i].pre[ref]; - av1_setup_pre_planes(xd, ref, scaled_ref_frame[ref], mi_row, mi_col, - NULL, num_planes); - } - } - - assert(IMPLIES(scaled_ref_frame[0] != NULL, - cm->width == scaled_ref_frame[0]->y_crop_width && - cm->height == scaled_ref_frame[0]->y_crop_height)); - assert(IMPLIES(scaled_ref_frame[1] != NULL, - cm->width == scaled_ref_frame[1]->y_crop_width && - cm->height == scaled_ref_frame[1]->y_crop_height)); - - // Initialize based on (possibly scaled) prediction buffers. - ref_yv12[0] = xd->plane[plane].pre[0]; - ref_yv12[1] = xd->plane[plane].pre[1]; - - // Since we have scaled the reference frames to match the size of the - // current frame we must use a unit scaling factor during mode selection. - av1_build_inter_predictor(ref_yv12[!id].buf, ref_yv12[!id].stride, - second_pred, pw, &cur_mv[!id].as_mv, - mi_col * MI_SIZE, mi_row * MI_SIZE, - &inter_pred_params); - - const int order_idx = id != 0; - av1_dist_wtd_comp_weight_assign( - cm, mbmi, order_idx, &xd->jcp_param.fwd_offset, - &xd->jcp_param.bck_offset, &xd->jcp_param.use_dist_wtd_comp_avg, 1); - - // Do full-pixel compound motion search on the current reference frame. - if (id) xd->plane[plane].pre[0] = ref_yv12[id]; - av1_set_mv_search_range(&x->mv_limits, &ref_mv[id].as_mv); - - // Use the mv result from the single mode as mv predictor. - *best_mv = cur_mv[id].as_mv; - - best_mv->col >>= 3; - best_mv->row >>= 3; - - // Small-range full-pixel motion search. - bestsme = av1_refining_search_8p_c(x, sadpb, search_range, - &cpi->fn_ptr[bsize], mask, mask_stride, - id, &ref_mv[id].as_mv, second_pred); - if (bestsme < INT_MAX) { - if (mask) - bestsme = av1_get_mvpred_mask_var(x, best_mv, &ref_mv[id].as_mv, - second_pred, mask, mask_stride, id, - &cpi->fn_ptr[bsize], 1); - else - bestsme = av1_get_mvpred_av_var(x, best_mv, &ref_mv[id].as_mv, - second_pred, &cpi->fn_ptr[bsize], 1); - } - - x->mv_limits = tmp_mv_limits; - - // Restore the pointer to the first (possibly scaled) prediction buffer. - if (id) xd->plane[plane].pre[0] = ref_yv12[0]; - - for (ref = 0; ref < 2; ++ref) { - if (scaled_ref_frame[ref]) { - // Swap back the original buffers for subpel motion search. - for (int i = 0; i < num_planes; i++) { - xd->plane[i].pre[ref] = backup_yv12[ref][i]; - } - // Re-initialize based on unscaled prediction buffers. - ref_yv12[ref] = xd->plane[plane].pre[ref]; - } - } - - // Do sub-pixel compound motion search on the current reference frame. - if (id) xd->plane[plane].pre[0] = ref_yv12[id]; - - if (cpi->common.cur_frame_force_integer_mv) { - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - } - if (bestsme < INT_MAX && cpi->common.cur_frame_force_integer_mv == 0) { - int dis; /* TODO: use dis in distortion calculation later. */ - unsigned int sse; - bestsme = cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &ref_mv[id].as_mv, - cpi->common.allow_high_precision_mv, x->errorperbit, - &cpi->fn_ptr[bsize], 0, cpi->sf.mv.subpel_iters_per_step, NULL, - x->nmv_vec_cost, x->mv_cost_stack, &dis, &sse, second_pred, mask, - mask_stride, id, pw, ph, cpi->sf.use_accurate_subpel_search, 1); - } - - // Restore the pointer to the first prediction buffer. - if (id) xd->plane[plane].pre[0] = ref_yv12[0]; - if (bestsme < last_besterr[id]) { - cur_mv[id].as_mv = *best_mv; - last_besterr[id] = bestsme; - } else { - break; - } - } - - *rate_mv = 0; - - for (ref = 0; ref < 2; ++ref) { - const int_mv curr_ref_mv = av1_get_ref_mv(x, ref); - *rate_mv += - av1_mv_bit_cost(&cur_mv[ref].as_mv, &curr_ref_mv.as_mv, x->nmv_vec_cost, - x->mv_cost_stack, MV_COST_WEIGHT); - } + int ref_idx) { + return ref_idx ? compound_ref1_mode(this_mode) + : compound_ref0_mode(this_mode); } static AOM_INLINE void estimate_ref_frame_costs( @@ -7255,13 +899,14 @@ static AOM_INLINE void store_coding_context( // Take a snapshot of the coding context so it can be // restored if we decide to encode this way - ctx->rd_stats.skip = x->skip; + ctx->rd_stats.skip = x->force_skip; ctx->skippable = skippable; #if CONFIG_INTERNAL_STATS ctx->best_mode_index = mode_index; #endif // CONFIG_INTERNAL_STATS ctx->mic = *xd->mi[0]; - ctx->mbmi_ext = *x->mbmi_ext; + av1_copy_mbmi_ext_to_mbmi_ext_frame(&ctx->mbmi_ext_best, x->mbmi_ext, + av1_ref_frame_type(xd->mi[0]->ref_frame)); ctx->single_pred_diff = (int)comp_pred_diff[SINGLE_REFERENCE]; ctx->comp_pred_diff = (int)comp_pred_diff[COMPOUND_REFERENCE]; ctx->hybrid_pred_diff = (int)comp_pred_diff[REFERENCE_MODE_SELECT]; @@ -7269,8 +914,7 @@ static AOM_INLINE void store_coding_context( static AOM_INLINE void setup_buffer_ref_mvs_inter( const AV1_COMP *const cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame, - BLOCK_SIZE block_size, int mi_row, int mi_col, - struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) { + BLOCK_SIZE block_size, struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) { const AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); const YV12_BUFFER_CONFIG *scaled_ref_frame = @@ -7286,17 +930,16 @@ static AOM_INLINE void setup_buffer_ref_mvs_inter( if (scaled_ref_frame) { // Setup pred block based on scaled reference, because av1_mv_pred() doesn't // support scaling. - av1_setup_pred_block(xd, yv12_mb[ref_frame], scaled_ref_frame, mi_row, - mi_col, NULL, NULL, num_planes); - } else { - av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf, + av1_setup_pred_block(xd, yv12_mb[ref_frame], scaled_ref_frame, NULL, NULL, num_planes); + } else { + av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, sf, sf, num_planes); } // Gets an initial list of candidate vectors from neighbours and orders them av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs, - mi_row, mi_col, mbmi_ext->mode_context); + mbmi_ext->mode_context); // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs. av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame); @@ -7310,417 +953,7 @@ static AOM_INLINE void setup_buffer_ref_mvs_inter( if (scaled_ref_frame) { // We had temporarily setup pred block based on scaled reference above. Go // back to unscaled reference now, for subsequent use. - av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, mi_row, mi_col, sf, sf, - num_planes); - } -} - -static AOM_INLINE void single_motion_search(const AV1_COMP *const cpi, - MACROBLOCK *x, BLOCK_SIZE bsize, - int mi_row, int mi_col, int ref_idx, - int *rate_mv) { - MACROBLOCKD *xd = &x->e_mbd; - const AV1_COMMON *cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - MB_MODE_INFO *mbmi = xd->mi[0]; - struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } }; - int bestsme = INT_MAX; - const int ref = mbmi->ref_frame[ref_idx]; - MvLimits tmp_mv_limits = x->mv_limits; - const YV12_BUFFER_CONFIG *scaled_ref_frame = - av1_get_scaled_ref_frame(cpi, ref); - - if (scaled_ref_frame) { - // Swap out the reference frame for a version that's been scaled to - // match the resolution of the current frame, allowing the existing - // full-pixel motion search code to be used without additional - // modifications. - for (int i = 0; i < num_planes; i++) { - backup_yv12[i] = xd->plane[i].pre[ref_idx]; - } - av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, - num_planes); - } - - // Work out the size of the first step in the mv step search. - // 0 here is maximum length first step. 1 is AOMMAX >> 1 etc. - int step_param; - if (cpi->sf.mv.auto_mv_step_size && cm->show_frame) { - // Take the weighted average of the step_params based on the last frame's - // max mv magnitude and that based on the best ref mvs of the current - // block for the given reference. - step_param = - (av1_init_search_range(x->max_mv_context[ref]) + cpi->mv_step_param) / - 2; - } else { - step_param = cpi->mv_step_param; - } - - if (cpi->sf.adaptive_motion_search && bsize < cm->seq_params.sb_size) { - int boffset = - 2 * (mi_size_wide_log2[cm->seq_params.sb_size] - - AOMMIN(mi_size_high_log2[bsize], mi_size_wide_log2[bsize])); - step_param = AOMMAX(step_param, boffset); - } - - if (cpi->sf.adaptive_motion_search) { - int bwl = mi_size_wide_log2[bsize]; - int bhl = mi_size_high_log2[bsize]; - int tlevel = x->pred_mv_sad[ref] >> (bwl + bhl + 4); - - if (tlevel < 5) { - step_param += 2; - step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 1); - } - - // prev_mv_sad is not setup for dynamically scaled frames. - if (cpi->oxcf.resize_mode != RESIZE_RANDOM) { - int i; - for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) { - if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) { - x->pred_mv[ref].row = 0; - x->pred_mv[ref].col = 0; - x->best_mv.as_int = INVALID_MV; - - if (scaled_ref_frame) { - // Swap back the original buffers before returning. - for (int j = 0; j < num_planes; ++j) - xd->plane[j].pre[ref_idx] = backup_yv12[j]; - } - return; - } - } - } - } - - const MV ref_mv = av1_get_ref_mv(x, ref_idx).as_mv; - // Note: MV limits are modified here. Always restore the original values - // after full-pixel motion search. - av1_set_mv_search_range(&x->mv_limits, &ref_mv); - - MV mvp_full; - if (mbmi->motion_mode != SIMPLE_TRANSLATION) - mvp_full = mbmi->mv[0].as_mv; - else - mvp_full = ref_mv; - - mvp_full.col >>= 3; - mvp_full.row >>= 3; - - const int sadpb = x->sadperbit16; - int cost_list[5]; - x->best_mv.as_int = x->second_best_mv.as_int = INVALID_MV; - switch (mbmi->motion_mode) { - case SIMPLE_TRANSLATION: - 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, &cpi->ss_cfg[SS_CFG_SRC], - 0); - 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, &cpi->ss_cfg[SS_CFG_SRC]); - break; - default: assert(0 && "Invalid motion mode!\n"); - } - - if (scaled_ref_frame) { - // Swap back the original buffers for subpel motion search. - for (int i = 0; i < num_planes; i++) { - xd->plane[i].pre[ref_idx] = backup_yv12[i]; - } - } - - x->mv_limits = tmp_mv_limits; - - if (cpi->common.cur_frame_force_integer_mv) { - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - } - const int use_fractional_mv = - bestsme < INT_MAX && cpi->common.cur_frame_force_integer_mv == 0; - if (use_fractional_mv) { - int dis; /* TODO: use dis in distortion calculation later. */ - switch (mbmi->motion_mode) { - case SIMPLE_TRANSLATION: - if (cpi->sf.use_accurate_subpel_search) { - const int try_second = x->second_best_mv.as_int != INVALID_MV && - x->second_best_mv.as_int != x->best_mv.as_int; - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - const int best_mv_var = 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, &dis, &x->pred_sse[ref], NULL, - NULL, 0, 0, pw, ph, cpi->sf.use_accurate_subpel_search, 1); - - if (try_second) { - const int minc = - AOMMAX(x->mv_limits.col_min * 8, ref_mv.col - MV_MAX); - const int maxc = - AOMMIN(x->mv_limits.col_max * 8, ref_mv.col + MV_MAX); - const int minr = - AOMMAX(x->mv_limits.row_min * 8, ref_mv.row - MV_MAX); - const int maxr = - AOMMIN(x->mv_limits.row_max * 8, ref_mv.row + MV_MAX); - MV best_mv = x->best_mv.as_mv; - - x->best_mv = x->second_best_mv; - if (x->best_mv.as_mv.row * 8 <= maxr && - x->best_mv.as_mv.row * 8 >= minr && - x->best_mv.as_mv.col * 8 <= maxc && - x->best_mv.as_mv.col * 8 >= minc) { - const int this_var = 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, &dis, &x->pred_sse[ref], NULL, NULL, 0, 0, - pw, ph, cpi->sf.use_accurate_subpel_search, 0); - if (this_var < best_mv_var) best_mv = x->best_mv.as_mv; - } - x->best_mv.as_mv = best_mv; - } - } 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, &dis, &x->pred_sse[ref], NULL, - NULL, 0, 0, 0, 0, 0, 1); - } - break; - case OBMC_CAUSAL: - av1_find_best_obmc_sub_pixel_tree_up( - x, cm, mi_row, mi_col, &x->best_mv.as_mv, &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, - x->nmv_vec_cost, x->mv_cost_stack, &dis, &x->pred_sse[ref], 0, - cpi->sf.use_accurate_subpel_search); - break; - default: assert(0 && "Invalid motion mode!\n"); - } - } - *rate_mv = av1_mv_bit_cost(&x->best_mv.as_mv, &ref_mv, x->nmv_vec_cost, - x->mv_cost_stack, MV_COST_WEIGHT); - - if (cpi->sf.adaptive_motion_search && mbmi->motion_mode == SIMPLE_TRANSLATION) - x->pred_mv[ref] = x->best_mv.as_mv; -} - -static INLINE void restore_dst_buf(MACROBLOCKD *xd, const BUFFER_SET dst, - const int num_planes) { - for (int i = 0; i < num_planes; i++) { - xd->plane[i].dst.buf = dst.plane[i]; - xd->plane[i].dst.stride = dst.stride[i]; - } -} - -static AOM_INLINE void build_second_inter_pred(const AV1_COMP *cpi, - MACROBLOCK *x, BLOCK_SIZE bsize, - const MV *other_mv, int mi_row, - int mi_col, int ref_idx, - uint8_t *second_pred) { - const AV1_COMMON *const cm = &cpi->common; - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - struct macroblockd_plane *const pd = &xd->plane[0]; - const int p_col = ((mi_col * MI_SIZE) >> pd->subsampling_x); - const int p_row = ((mi_row * MI_SIZE) >> pd->subsampling_y); - - // This function should only ever be called for compound modes - assert(has_second_ref(mbmi)); - - const int plane = 0; - struct buf_2d ref_yv12 = xd->plane[plane].pre[!ref_idx]; - - struct scale_factors sf; - av1_setup_scale_factors_for_frame(&sf, ref_yv12.width, ref_yv12.height, - cm->width, cm->height); - - InterPredParams inter_pred_params; - - av1_init_inter_params(&inter_pred_params, pw, ph, p_col, p_row, - pd->subsampling_x, pd->subsampling_y, xd->bd, - is_cur_buf_hbd(xd), 0, &sf, mbmi->interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - - // Get the prediction block from the 'other' reference frame. - av1_build_inter_predictor(ref_yv12.buf, ref_yv12.stride, second_pred, pw, - other_mv, mi_col * MI_SIZE, mi_row * MI_SIZE, - &inter_pred_params); - - av1_dist_wtd_comp_weight_assign(cm, mbmi, 0, &xd->jcp_param.fwd_offset, - &xd->jcp_param.bck_offset, - &xd->jcp_param.use_dist_wtd_comp_avg, 1); -} - -// Search for the best mv for one component of a compound, -// given that the other component is fixed. -static AOM_INLINE void compound_single_motion_search( - const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, MV *this_mv, - int mi_row, int mi_col, const uint8_t *second_pred, const uint8_t *mask, - int mask_stride, int *rate_mv, int ref_idx) { - const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - const int ref = mbmi->ref_frame[ref_idx]; - const int_mv ref_mv = av1_get_ref_mv(x, ref_idx); - struct macroblockd_plane *const pd = &xd->plane[0]; - - struct buf_2d backup_yv12[MAX_MB_PLANE]; - const YV12_BUFFER_CONFIG *const scaled_ref_frame = - av1_get_scaled_ref_frame(cpi, ref); - - // Check that this is either an interinter or an interintra block - assert(has_second_ref(mbmi) || (ref_idx == 0 && is_interintra_mode(mbmi))); - - // Store the first prediction buffer. - struct buf_2d orig_yv12; - if (ref_idx) { - orig_yv12 = pd->pre[0]; - pd->pre[0] = pd->pre[ref_idx]; - } - - 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 - // full-pixel motion search code to be used without additional - // modifications. - for (i = 0; i < num_planes; i++) backup_yv12[i] = xd->plane[i].pre[ref_idx]; - av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL, - num_planes); - } - - int bestsme = INT_MAX; - int sadpb = x->sadperbit16; - MV *const best_mv = &x->best_mv.as_mv; - int search_range = SEARCH_RANGE_8P; - - MvLimits tmp_mv_limits = x->mv_limits; - - // Do compound motion search on the current reference frame. - av1_set_mv_search_range(&x->mv_limits, &ref_mv.as_mv); - - // Use the mv result from the single mode as mv predictor. - *best_mv = *this_mv; - - best_mv->col >>= 3; - best_mv->row >>= 3; - - // Small-range full-pixel motion search. - bestsme = av1_refining_search_8p_c(x, sadpb, search_range, - &cpi->fn_ptr[bsize], mask, mask_stride, - ref_idx, &ref_mv.as_mv, second_pred); - if (bestsme < INT_MAX) { - if (mask) - bestsme = - av1_get_mvpred_mask_var(x, best_mv, &ref_mv.as_mv, second_pred, mask, - mask_stride, ref_idx, &cpi->fn_ptr[bsize], 1); - else - bestsme = av1_get_mvpred_av_var(x, best_mv, &ref_mv.as_mv, second_pred, - &cpi->fn_ptr[bsize], 1); - } - - x->mv_limits = tmp_mv_limits; - - if (scaled_ref_frame) { - // Swap back the original buffers for subpel motion search. - for (int i = 0; i < num_planes; i++) { - xd->plane[i].pre[ref_idx] = backup_yv12[i]; - } - } - - if (cpi->common.cur_frame_force_integer_mv) { - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - } - const int use_fractional_mv = - bestsme < INT_MAX && cpi->common.cur_frame_force_integer_mv == 0; - if (use_fractional_mv) { - int dis; /* TODO: use dis in distortion calculation later. */ - unsigned int sse; - bestsme = cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &ref_mv.as_mv, - cpi->common.allow_high_precision_mv, x->errorperbit, - &cpi->fn_ptr[bsize], 0, cpi->sf.mv.subpel_iters_per_step, NULL, - x->nmv_vec_cost, x->mv_cost_stack, &dis, &sse, second_pred, mask, - mask_stride, ref_idx, pw, ph, cpi->sf.use_accurate_subpel_search, 1); - } - - // Restore the pointer to the first unscaled prediction buffer. - if (ref_idx) pd->pre[0] = orig_yv12; - - if (bestsme < INT_MAX) *this_mv = *best_mv; - - *rate_mv = 0; - - *rate_mv += av1_mv_bit_cost(this_mv, &ref_mv.as_mv, x->nmv_vec_cost, - x->mv_cost_stack, MV_COST_WEIGHT); -} - -// Wrapper for compound_single_motion_search, for the common case -// where the second prediction is also an inter mode. -static AOM_INLINE void compound_single_motion_search_interinter( - const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int_mv *cur_mv, - int mi_row, int mi_col, const uint8_t *mask, int mask_stride, int *rate_mv, - int ref_idx) { - MACROBLOCKD *xd = &x->e_mbd; - // This function should only ever be called for compound modes - assert(has_second_ref(xd->mi[0])); - - // Prediction buffer from second frame. - DECLARE_ALIGNED(16, uint16_t, second_pred_alloc_16[MAX_SB_SQUARE]); - uint8_t *second_pred; - if (is_cur_buf_hbd(xd)) - second_pred = CONVERT_TO_BYTEPTR(second_pred_alloc_16); - else - second_pred = (uint8_t *)second_pred_alloc_16; - - MV *this_mv = &cur_mv[ref_idx].as_mv; - const MV *other_mv = &cur_mv[!ref_idx].as_mv; - - build_second_inter_pred(cpi, x, bsize, other_mv, mi_row, mi_col, ref_idx, - second_pred); - - compound_single_motion_search(cpi, x, bsize, this_mv, mi_row, mi_col, - second_pred, mask, mask_stride, rate_mv, - ref_idx); -} - -static AOM_INLINE void do_masked_motion_search_indexed( - const AV1_COMP *const cpi, MACROBLOCK *x, const int_mv *const cur_mv, - const INTERINTER_COMPOUND_DATA *const comp_data, BLOCK_SIZE bsize, - int mi_row, int mi_col, int_mv *tmp_mv, int *rate_mv, int which) { - // NOTE: which values: 0 - 0 only, 1 - 1 only, 2 - both - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - BLOCK_SIZE sb_type = mbmi->sb_type; - const uint8_t *mask; - const int mask_stride = block_size_wide[bsize]; - - mask = av1_get_compound_type_mask(comp_data, sb_type); - - tmp_mv[0].as_int = cur_mv[0].as_int; - tmp_mv[1].as_int = cur_mv[1].as_int; - if (which == 0 || which == 1) { - compound_single_motion_search_interinter(cpi, x, bsize, tmp_mv, mi_row, - mi_col, mask, mask_stride, rate_mv, - which); - } else if (which == 2) { - joint_motion_search(cpi, x, bsize, tmp_mv, mi_row, mi_col, mask, - mask_stride, rate_mv); + av1_setup_pred_block(xd, yv12_mb[ref_frame], yv12, sf, sf, num_planes); } } @@ -7729,573 +962,14 @@ static AOM_INLINE void do_masked_motion_search_indexed( // TODO(jingning): this mv clamping function should be block size dependent. static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) { - clamp_mv(mv, xd->mb_to_left_edge - LEFT_TOP_MARGIN, - xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, - xd->mb_to_top_edge - LEFT_TOP_MARGIN, - xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN); + const SubpelMvLimits mv_limits = { xd->mb_to_left_edge - LEFT_TOP_MARGIN, + xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN, + xd->mb_to_top_edge - LEFT_TOP_MARGIN, + xd->mb_to_bottom_edge + + RIGHT_BOTTOM_MARGIN }; + clamp_mv(mv, &mv_limits); } -static int8_t estimate_wedge_sign(const AV1_COMP *cpi, const MACROBLOCK *x, - const BLOCK_SIZE bsize, const uint8_t *pred0, - int stride0, const uint8_t *pred1, - int stride1) { - static const BLOCK_SIZE split_qtr[BLOCK_SIZES_ALL] = { - // 4X4 - BLOCK_INVALID, - // 4X8, 8X4, 8X8 - BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X4, - // 8X16, 16X8, 16X16 - BLOCK_4X8, BLOCK_8X4, BLOCK_8X8, - // 16X32, 32X16, 32X32 - BLOCK_8X16, BLOCK_16X8, BLOCK_16X16, - // 32X64, 64X32, 64X64 - BLOCK_16X32, BLOCK_32X16, BLOCK_32X32, - // 64x128, 128x64, 128x128 - BLOCK_32X64, BLOCK_64X32, BLOCK_64X64, - // 4X16, 16X4, 8X32 - BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X16, - // 32X8, 16X64, 64X16 - BLOCK_16X4, BLOCK_8X32, BLOCK_32X8 - }; - const struct macroblock_plane *const p = &x->plane[0]; - const uint8_t *src = p->src.buf; - int src_stride = p->src.stride; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const int bw_by2 = bw >> 1; - const int bh_by2 = bh >> 1; - uint32_t esq[2][2]; - int64_t tl, br; - - const BLOCK_SIZE f_index = split_qtr[bsize]; - assert(f_index != BLOCK_INVALID); - - if (is_cur_buf_hbd(&x->e_mbd)) { - pred0 = CONVERT_TO_BYTEPTR(pred0); - pred1 = CONVERT_TO_BYTEPTR(pred1); - } - - // Residual variance computation over relevant quandrants in order to - // find TL + BR, TL = sum(1st,2nd,3rd) quadrants of (pred0 - pred1), - // BR = sum(2nd,3rd,4th) quadrants of (pred1 - pred0) - // The 2nd and 3rd quadrants cancel out in TL + BR - // Hence TL + BR = 1st quadrant of (pred0-pred1) + 4th of (pred1-pred0) - // TODO(nithya): Sign estimation assumes 45 degrees (1st and 4th quadrants) - // for all codebooks; experiment with other quadrant combinations for - // 0, 90 and 135 degrees also. - cpi->fn_ptr[f_index].vf(src, src_stride, pred0, stride0, &esq[0][0]); - cpi->fn_ptr[f_index].vf(src + bh_by2 * src_stride + bw_by2, src_stride, - pred0 + bh_by2 * stride0 + bw_by2, stride0, - &esq[0][1]); - cpi->fn_ptr[f_index].vf(src, src_stride, pred1, stride1, &esq[1][0]); - cpi->fn_ptr[f_index].vf(src + bh_by2 * src_stride + bw_by2, src_stride, - pred1 + bh_by2 * stride1 + bw_by2, stride0, - &esq[1][1]); - - tl = ((int64_t)esq[0][0]) - ((int64_t)esq[1][0]); - br = ((int64_t)esq[1][1]) - ((int64_t)esq[0][1]); - return (tl + br > 0); -} - -// Choose the best wedge index and sign -static int64_t pick_wedge(const AV1_COMP *const cpi, const MACROBLOCK *const x, - const BLOCK_SIZE bsize, const uint8_t *const p0, - const int16_t *const residual1, - const int16_t *const diff10, - int8_t *const best_wedge_sign, - int8_t *const best_wedge_index) { - const MACROBLOCKD *const xd = &x->e_mbd; - const struct buf_2d *const src = &x->plane[0].src; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const int N = bw * bh; - assert(N >= 64); - int rate; - int64_t dist; - int64_t rd, best_rd = INT64_MAX; - int8_t wedge_index; - int8_t wedge_sign; - int8_t wedge_types = (1 << get_wedge_bits_lookup(bsize)); - const uint8_t *mask; - uint64_t sse; - const int hbd = is_cur_buf_hbd(xd); - const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; - - DECLARE_ALIGNED(32, int16_t, residual0[MAX_SB_SQUARE]); // src - pred0 -#if CONFIG_AV1_HIGHBITDEPTH - if (hbd) { - aom_highbd_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, - CONVERT_TO_BYTEPTR(p0), bw, xd->bd); - } else { - aom_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, p0, bw); - } -#else - (void)hbd; - aom_subtract_block(bh, bw, residual0, bw, src->buf, src->stride, p0, bw); -#endif - - int64_t sign_limit = ((int64_t)aom_sum_squares_i16(residual0, N) - - (int64_t)aom_sum_squares_i16(residual1, N)) * - (1 << WEDGE_WEIGHT_BITS) / 2; - int16_t *ds = residual0; - - av1_wedge_compute_delta_squares(ds, residual0, residual1, N); - - for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) { - mask = av1_get_contiguous_soft_mask(wedge_index, 0, bsize); - - wedge_sign = av1_wedge_sign_from_residuals(ds, mask, N, sign_limit); - - mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); - sse = av1_wedge_sse_from_residuals(residual1, diff10, mask, N); - sse = ROUND_POWER_OF_TWO(sse, bd_round); - - model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, - &rate, &dist); - // int rate2; - // int64_t dist2; - // model_rd_with_curvfit(cpi, x, bsize, 0, sse, N, &rate2, &dist2); - // printf("sse %"PRId64": leagacy: %d %"PRId64", curvfit %d %"PRId64"\n", - // sse, rate, dist, rate2, dist2); dist = dist2; - // rate = rate2; - - rate += x->wedge_idx_cost[bsize][wedge_index]; - rd = RDCOST(x->rdmult, rate, dist); - - if (rd < best_rd) { - *best_wedge_index = wedge_index; - *best_wedge_sign = wedge_sign; - best_rd = rd; - } - } - - return best_rd - - RDCOST(x->rdmult, x->wedge_idx_cost[bsize][*best_wedge_index], 0); -} - -// Choose the best wedge index the specified sign -static int64_t pick_wedge_fixed_sign(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - const BLOCK_SIZE bsize, - const int16_t *const residual1, - const int16_t *const diff10, - const int8_t wedge_sign, - int8_t *const best_wedge_index) { - const MACROBLOCKD *const xd = &x->e_mbd; - - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const int N = bw * bh; - assert(N >= 64); - int rate; - int64_t dist; - int64_t rd, best_rd = INT64_MAX; - int8_t wedge_index; - int8_t wedge_types = (1 << get_wedge_bits_lookup(bsize)); - const uint8_t *mask; - uint64_t sse; - const int hbd = is_cur_buf_hbd(xd); - const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; - for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) { - mask = av1_get_contiguous_soft_mask(wedge_index, wedge_sign, bsize); - sse = av1_wedge_sse_from_residuals(residual1, diff10, mask, N); - sse = ROUND_POWER_OF_TWO(sse, bd_round); - - model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, - &rate, &dist); - rate += x->wedge_idx_cost[bsize][wedge_index]; - rd = RDCOST(x->rdmult, rate, dist); - - if (rd < best_rd) { - *best_wedge_index = wedge_index; - best_rd = rd; - } - } - return best_rd - - RDCOST(x->rdmult, x->wedge_idx_cost[bsize][*best_wedge_index], 0); -} - -static int64_t pick_interinter_wedge( - const AV1_COMP *const cpi, MACROBLOCK *const x, const BLOCK_SIZE bsize, - const uint8_t *const p0, const uint8_t *const p1, - const int16_t *const residual1, const int16_t *const diff10) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int bw = block_size_wide[bsize]; - - int64_t rd; - int8_t wedge_index = -1; - int8_t wedge_sign = 0; - - assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize)); - assert(cpi->common.seq_params.enable_masked_compound); - - if (cpi->sf.fast_wedge_sign_estimate) { - wedge_sign = estimate_wedge_sign(cpi, x, bsize, p0, bw, p1, bw); - rd = pick_wedge_fixed_sign(cpi, x, bsize, residual1, diff10, wedge_sign, - &wedge_index); - } else { - rd = pick_wedge(cpi, x, bsize, p0, residual1, diff10, &wedge_sign, - &wedge_index); - } - - mbmi->interinter_comp.wedge_sign = wedge_sign; - mbmi->interinter_comp.wedge_index = wedge_index; - return rd; -} - -static int64_t pick_interinter_seg(const AV1_COMP *const cpi, - MACROBLOCK *const x, const BLOCK_SIZE bsize, - const uint8_t *const p0, - const uint8_t *const p1, - const int16_t *const residual1, - const int16_t *const diff10) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - const int N = 1 << num_pels_log2_lookup[bsize]; - int rate; - int64_t dist; - DIFFWTD_MASK_TYPE cur_mask_type; - int64_t best_rd = INT64_MAX; - DIFFWTD_MASK_TYPE best_mask_type = 0; - const int hbd = is_cur_buf_hbd(xd); - const int bd_round = hbd ? (xd->bd - 8) * 2 : 0; - DECLARE_ALIGNED(16, uint8_t, seg_mask[2 * MAX_SB_SQUARE]); - uint8_t *tmp_mask[2] = { xd->seg_mask, seg_mask }; - // try each mask type and its inverse - for (cur_mask_type = 0; cur_mask_type < DIFFWTD_MASK_TYPES; cur_mask_type++) { - // build mask and inverse - if (hbd) - av1_build_compound_diffwtd_mask_highbd( - tmp_mask[cur_mask_type], cur_mask_type, CONVERT_TO_BYTEPTR(p0), bw, - CONVERT_TO_BYTEPTR(p1), bw, bh, bw, xd->bd); - else - av1_build_compound_diffwtd_mask(tmp_mask[cur_mask_type], cur_mask_type, - p0, bw, p1, bw, bh, bw); - - // compute rd for mask - uint64_t sse = av1_wedge_sse_from_residuals(residual1, diff10, - tmp_mask[cur_mask_type], N); - sse = ROUND_POWER_OF_TWO(sse, bd_round); - - model_rd_sse_fn[MODELRD_TYPE_MASKED_COMPOUND](cpi, x, bsize, 0, sse, N, - &rate, &dist); - const int64_t rd0 = RDCOST(x->rdmult, rate, dist); - - if (rd0 < best_rd) { - best_mask_type = cur_mask_type; - best_rd = rd0; - } - } - mbmi->interinter_comp.mask_type = best_mask_type; - if (best_mask_type == DIFFWTD_38_INV) { - memcpy(xd->seg_mask, seg_mask, N * 2); - } - return best_rd; -} - -static int64_t pick_interintra_wedge(const AV1_COMP *const cpi, - const MACROBLOCK *const x, - const BLOCK_SIZE bsize, - const uint8_t *const p0, - const uint8_t *const p1) { - const MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(is_interintra_wedge_used(bsize)); - assert(cpi->common.seq_params.enable_interintra_compound); - - const struct buf_2d *const src = &x->plane[0].src; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - DECLARE_ALIGNED(32, int16_t, residual1[MAX_SB_SQUARE]); // src - pred1 - DECLARE_ALIGNED(32, int16_t, diff10[MAX_SB_SQUARE]); // pred1 - pred0 -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, - CONVERT_TO_BYTEPTR(p1), bw, xd->bd); - aom_highbd_subtract_block(bh, bw, diff10, bw, CONVERT_TO_BYTEPTR(p1), bw, - CONVERT_TO_BYTEPTR(p0), bw, xd->bd); - } else { - aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, p1, bw); - aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw); - } -#else - aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, p1, bw); - aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw); -#endif - int8_t wedge_index = -1; - int64_t rd = - pick_wedge_fixed_sign(cpi, x, bsize, residual1, diff10, 0, &wedge_index); - - mbmi->interintra_wedge_index = wedge_index; - return rd; -} - -static int interinter_compound_motion_search(const AV1_COMP *const cpi, - MACROBLOCK *x, - const int_mv *const cur_mv, - const BLOCK_SIZE bsize, - const PREDICTION_MODE this_mode, - int mi_row, int mi_col) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - int_mv tmp_mv[2]; - int tmp_rate_mv = 0; - mbmi->interinter_comp.seg_mask = xd->seg_mask; - const INTERINTER_COMPOUND_DATA *compound_data = &mbmi->interinter_comp; - - if (this_mode == NEW_NEWMV) { - do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize, - mi_row, mi_col, tmp_mv, &tmp_rate_mv, 2); - mbmi->mv[0].as_int = tmp_mv[0].as_int; - mbmi->mv[1].as_int = tmp_mv[1].as_int; - } else if (this_mode >= NEAREST_NEWMV && this_mode <= NEW_NEARMV) { - // which = 1 if this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV - // which = 0 if this_mode == NEW_NEARESTMV || this_mode == NEW_NEARMV - int which = (NEWMV == compound_ref1_mode(this_mode)); - do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize, - mi_row, mi_col, tmp_mv, &tmp_rate_mv, - which); - mbmi->mv[which].as_int = tmp_mv[which].as_int; - } - return tmp_rate_mv; -} - -static AOM_INLINE void get_inter_predictors_masked_compound( - MACROBLOCK *x, const BLOCK_SIZE bsize, int mi_row, int mi_col, - uint8_t **preds0, uint8_t **preds1, int16_t *residual1, int16_t *diff10, - int *strides) { - MACROBLOCKD *xd = &x->e_mbd; - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - // get inter predictors to use for masked compound modes - av1_build_inter_predictors_for_planes_single_buf(xd, bsize, 0, 0, mi_row, - mi_col, 0, preds0, strides); - av1_build_inter_predictors_for_planes_single_buf(xd, bsize, 0, 0, mi_row, - mi_col, 1, preds1, strides); - const struct buf_2d *const src = &x->plane[0].src; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, - CONVERT_TO_BYTEPTR(*preds1), bw, xd->bd); - aom_highbd_subtract_block(bh, bw, diff10, bw, CONVERT_TO_BYTEPTR(*preds1), - bw, CONVERT_TO_BYTEPTR(*preds0), bw, xd->bd); - } else { - aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, *preds1, - bw); - aom_subtract_block(bh, bw, diff10, bw, *preds1, bw, *preds0, bw); - } -#else - aom_subtract_block(bh, bw, residual1, bw, src->buf, src->stride, *preds1, bw); - aom_subtract_block(bh, bw, diff10, bw, *preds1, bw, *preds0, bw); -#endif -} - -// Takes a backup of rate, distortion and model_rd for future reuse -static INLINE void backup_stats(COMPOUND_TYPE cur_type, int32_t *comp_rate, - int64_t *comp_dist, int64_t *comp_model_rd, - RD_STATS *rd_stats, int64_t est_rd) { - comp_rate[cur_type] = rd_stats->rate; - comp_dist[cur_type] = rd_stats->dist; - comp_model_rd[cur_type] = est_rd; -} - -static int64_t masked_compound_type_rd( - const AV1_COMP *const cpi, MACROBLOCK *x, const int_mv *const cur_mv, - const BLOCK_SIZE bsize, const PREDICTION_MODE this_mode, int *rs2, - 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 rd_thresh, - 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; - // This function will be called only for COMPOUND_WEDGE and COMPOUND_DIFFWTD - assert(compound_type == COMPOUND_WEDGE || compound_type == COMPOUND_DIFFWTD); - int rate_sum, tmp_skip_txfm_sb; - int64_t dist_sum, tmp_skip_sse_sb; - pick_interinter_mask_type pick_interinter_mask[2] = { pick_interinter_wedge, - pick_interinter_seg }; - - // TODO(any): Save pred and mask calculation as well into records. However - // this may increase memory requirements as compound segment mask needs to be - // stored in each record. - if (*calc_pred_masked_compound) { - get_inter_predictors_masked_compound(x, bsize, mi_row, mi_col, preds0, - preds1, residual1, diff10, strides); - *calc_pred_masked_compound = 0; - } - if (cpi->sf.prune_wedge_pred_diff_based && compound_type == COMPOUND_WEDGE) { - unsigned int sse; - if (is_cur_buf_hbd(xd)) - (void)cpi->fn_ptr[bsize].vf(CONVERT_TO_BYTEPTR(*preds0), *strides, - CONVERT_TO_BYTEPTR(*preds1), *strides, &sse); - else - (void)cpi->fn_ptr[bsize].vf(*preds0, *strides, *preds1, *strides, &sse); - 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)) { - *comp_model_rd_cur = INT64_MAX; - return INT64_MAX; - } - } - // Function pointer to pick the appropriate mask - // compound_type == COMPOUND_WEDGE, calls pick_interinter_wedge() - // compound_type == COMPOUND_DIFFWTD, calls pick_interinter_seg() - best_rd_cur = pick_interinter_mask[compound_type - COMPOUND_WEDGE]( - cpi, x, bsize, *preds0, *preds1, residual1, diff10); - *rs2 += get_interinter_compound_mask_rate(x, mbmi); - best_rd_cur += RDCOST(x->rdmult, *rs2 + rate_mv, 0); - - // Although the true rate_mv might be different after motion search, but it - // 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 > rd_thresh) { - *comp_model_rd_cur = INT64_MAX; - return INT64_MAX; - } - - // Compute cost if matching record not found, else, reuse data - if (comp_rate[compound_type] == INT_MAX) { - // Check whether new MV search for wedge is to be done - int wedge_newmv_search = have_newmv_in_inter_mode(this_mode) && - (compound_type == COMPOUND_WEDGE) && - (!cpi->sf.disable_interinter_wedge_newmv_search); - int diffwtd_newmv_search = cpi->sf.enable_interinter_diffwtd_newmv_search && - compound_type == COMPOUND_DIFFWTD && - have_newmv_in_inter_mode(this_mode); - - // Search for new MV if needed and build predictor - if (wedge_newmv_search) { - *out_rate_mv = interinter_compound_motion_search( - 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); - } else if (diffwtd_newmv_search) { - *out_rate_mv = interinter_compound_motion_search( - cpi, x, cur_mv, bsize, this_mode, mi_row, mi_col); - // we need to update the mask according to the new motion vector - CompoundTypeRdBuffers tmp_buf; - int64_t tmp_rd = INT64_MAX; - alloc_compound_type_rd_buffers_no_check(&tmp_buf); - - uint8_t *tmp_preds0[1] = { tmp_buf.pred0 }; - uint8_t *tmp_preds1[1] = { tmp_buf.pred1 }; - - get_inter_predictors_masked_compound(x, bsize, mi_row, mi_col, tmp_preds0, - tmp_preds1, tmp_buf.residual1, - tmp_buf.diff10, strides); - - tmp_rd = pick_interinter_mask[compound_type - COMPOUND_WEDGE]( - cpi, x, bsize, *tmp_preds0, *tmp_preds1, tmp_buf.residual1, - tmp_buf.diff10); - // we can reuse rs2 here - tmp_rd += RDCOST(x->rdmult, *rs2 + *out_rate_mv, 0); - - if (tmp_rd >= best_rd_cur) { - // restore the motion vector - 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); - } else { - // build the final prediciton using the updated mv - av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, tmp_preds0, - strides, tmp_preds1, strides); - } - av1_release_compound_type_rd_buffers(&tmp_buf); - } else { - *out_rate_mv = rate_mv; - av1_build_wedge_inter_predictor_from_buf(xd, bsize, 0, 0, preds0, strides, - preds1, strides); - } - // Get the RD cost from model RD - 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; - // Override with best if current is worse than best for new MV - if (wedge_newmv_search) { - 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; - } - } - 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; - } - // Compute RD cost for the current type - RD_STATS rd_stats; - const int64_t tmp_mode_rd = RDCOST(x->rdmult, *rs2 + *out_rate_mv, 0); - const int64_t tmp_rd_thresh = rd_thresh - tmp_mode_rd; - rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &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 - backup_stats(compound_type, comp_rate, comp_dist, comp_model_rd, - &rd_stats, *comp_model_rd_cur); - } - } else { - // Reuse data as matching record is found - assert(comp_dist[compound_type] != INT64_MAX); - // 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; -} - -typedef struct { - // OBMC secondary prediction buffers and respective strides - uint8_t *above_pred_buf[MAX_MB_PLANE]; - int above_pred_stride[MAX_MB_PLANE]; - uint8_t *left_pred_buf[MAX_MB_PLANE]; - int left_pred_stride[MAX_MB_PLANE]; - int_mv (*single_newmv)[REF_FRAMES]; - // Pointer to array of motion vectors to use for each ref and their rates - // Should point to first of 2 arrays in 2D array - int (*single_newmv_rate)[REF_FRAMES]; - int (*single_newmv_valid)[REF_FRAMES]; - // Pointer to array of predicted rate-distortion - // Should point to first of 2 arrays in 2D array - int64_t (*modelled_rd)[MAX_REF_MV_SEARCH][REF_FRAMES]; - InterpFilter single_filter[MB_MODE_COUNT][REF_FRAMES]; - int ref_frame_cost; - int single_comp_cost; - int64_t (*simple_rd)[MAX_REF_MV_SEARCH][REF_FRAMES]; - int skip_motion_mode; - INTERINTRA_MODE *inter_intra_mode; - int single_ref_first_pass; - SimpleRDState *simple_rd_state; -} HandleInterModeArgs; - /* If the current mode shares the same mv with other modes with higher cost, * skip this mode. */ static int skip_repeated_mv(const AV1_COMMON *const cm, @@ -8358,10 +1032,11 @@ static INLINE int clamp_and_check_mv(int_mv *out_mv, int_mv in_mv, const MACROBLOCK *x) { const MACROBLOCKD *const xd = &x->e_mbd; *out_mv = in_mv; - lower_mv_precision(&out_mv->as_mv, cm->allow_high_precision_mv, - cm->cur_frame_force_integer_mv); + lower_mv_precision(&out_mv->as_mv, cm->features.allow_high_precision_mv, + cm->features.cur_frame_force_integer_mv); clamp_mv2(&out_mv->as_mv, xd); - return !mv_check_bounds(&x->mv_limits, &out_mv->as_mv); + return av1_is_fullmv_in_range(&x->mv_limits, + get_fullmv_from_mv(&out_mv->as_mv)); } // To use single newmv directly for compound modes, need to clamp the mv to the @@ -8370,17 +1045,16 @@ static INLINE int clamp_and_check_mv(int_mv *out_mv, int_mv in_mv, static INLINE void clamp_mv_in_range(MACROBLOCK *const x, int_mv *mv, int ref_idx) { const int_mv ref_mv = av1_get_ref_mv(x, ref_idx); - int minc, maxc, minr, maxr; - set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, - &ref_mv.as_mv); - clamp_mv(&mv->as_mv, minc, maxc, minr, maxr); + SubpelMvLimits mv_limits; + + av1_set_subpel_mv_search_range(&mv_limits, &x->mv_limits, &ref_mv.as_mv); + clamp_mv(&mv->as_mv, &mv_limits); } static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, const BLOCK_SIZE bsize, int_mv *cur_mv, - const int mi_row, const int mi_col, - int *const rate_mv, - HandleInterModeArgs *const args) { + int *const rate_mv, HandleInterModeArgs *const args, + inter_mode_info *mode_info) { const MACROBLOCKD *const xd = &x->e_mbd; const MB_MODE_INFO *const mbmi = xd->mi[0]; const int is_comp_pred = has_second_ref(mbmi); @@ -8388,9 +1062,6 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1] }; const int ref_mv_idx = mbmi->ref_mv_idx; - int i; - - (void)args; if (is_comp_pred) { const int valid_mv0 = args->single_newmv_valid[ref_mv_idx][refs[0]]; @@ -8407,13 +1078,12 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, } // aomenc1 - if (cpi->sf.comp_inter_joint_search_thresh <= bsize || !valid_mv0 || - !valid_mv1) { - joint_motion_search(cpi, x, bsize, cur_mv, mi_row, mi_col, NULL, 0, - rate_mv); + if (cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize || + !valid_mv0 || !valid_mv1) { + av1_joint_motion_search(cpi, x, bsize, cur_mv, NULL, 0, rate_mv); } else { *rate_mv = 0; - for (i = 0; i < 2; ++i) { + for (int i = 0; i < 2; ++i) { const int_mv ref_mv = av1_get_ref_mv(x, i); *rate_mv += av1_mv_bit_cost(&cur_mv[i].as_mv, &ref_mv.as_mv, x->nmv_vec_cost, @@ -8427,9 +1097,10 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, } // aomenc2 - if (cpi->sf.comp_inter_joint_search_thresh <= bsize || !valid_mv1) { - compound_single_motion_search_interinter(cpi, x, bsize, cur_mv, mi_row, - mi_col, NULL, 0, rate_mv, 1); + if (cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize || + !valid_mv1) { + av1_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv, + NULL, 0, rate_mv, 1); } else { const int_mv ref_mv = av1_get_ref_mv(x, 1); *rate_mv = @@ -8444,9 +1115,10 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, } // aomenc3 - if (cpi->sf.comp_inter_joint_search_thresh <= bsize || !valid_mv0) { - compound_single_motion_search_interinter(cpi, x, bsize, cur_mv, mi_row, - mi_col, NULL, 0, rate_mv, 0); + if (cpi->sf.inter_sf.comp_inter_joint_search_thresh <= bsize || + !valid_mv0) { + av1_compound_single_motion_search_interinter(cpi, x, bsize, cur_mv, + NULL, 0, rate_mv, 0); } else { const int_mv ref_mv = av1_get_ref_mv(x, 0); *rate_mv = @@ -8455,1152 +1127,56 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, } } } else { - single_motion_search(cpi, x, bsize, mi_row, mi_col, 0, rate_mv); - if (x->best_mv.as_int == INVALID_MV) return INT64_MAX; + // Single ref case. + const int ref_idx = 0; + int search_range = INT_MAX; - args->single_newmv[ref_mv_idx][refs[0]] = x->best_mv; + if (cpi->sf.mv_sf.reduce_search_range && mbmi->ref_mv_idx > 0) { + const MV ref_mv = av1_get_ref_mv(x, ref_idx).as_mv; + int min_mv_diff = INT_MAX; + int best_match = -1; + MV prev_ref_mv[2] = { { 0 } }; + for (int idx = 0; idx < mbmi->ref_mv_idx; ++idx) { + prev_ref_mv[idx] = av1_get_ref_mv_from_stack(ref_idx, mbmi->ref_frame, + idx, x->mbmi_ext) + .as_mv; + const int ref_mv_diff = AOMMAX(abs(ref_mv.row - prev_ref_mv[idx].row), + abs(ref_mv.col - prev_ref_mv[idx].col)); + + if (min_mv_diff > ref_mv_diff) { + min_mv_diff = ref_mv_diff; + best_match = idx; + } + } + + if (min_mv_diff < (16 << 3)) { + if (args->single_newmv_valid[best_match][refs[0]]) { + search_range = min_mv_diff; + search_range += + AOMMAX(abs(args->single_newmv[best_match][refs[0]].as_mv.row - + prev_ref_mv[best_match].row), + abs(args->single_newmv[best_match][refs[0]].as_mv.col - + prev_ref_mv[best_match].col)); + // Get full pixel search range. + search_range = (search_range + 4) >> 3; + } + } + } + + int_mv best_mv; + av1_single_motion_search(cpi, x, bsize, ref_idx, rate_mv, search_range, + mode_info, &best_mv); + if (best_mv.as_int == INVALID_MV) return INT64_MAX; + + args->single_newmv[ref_mv_idx][refs[0]] = best_mv; args->single_newmv_rate[ref_mv_idx][refs[0]] = *rate_mv; args->single_newmv_valid[ref_mv_idx][refs[0]] = 1; - - cur_mv[0].as_int = x->best_mv.as_int; + cur_mv[0].as_int = best_mv.as_int; } return 0; } -static INLINE void swap_dst_buf(MACROBLOCKD *xd, const BUFFER_SET *dst_bufs[2], - int num_planes) { - const BUFFER_SET *buf0 = dst_bufs[0]; - dst_bufs[0] = dst_bufs[1]; - dst_bufs[1] = buf0; - restore_dst_buf(xd, *dst_bufs[0], num_planes); -} - -static INLINE int get_switchable_rate(MACROBLOCK *const x, - const int_interpfilters filters, - const int ctx[2]) { - int inter_filter_cost; - const InterpFilter filter0 = filters.as_filters.y_filter; - const InterpFilter filter1 = filters.as_filters.x_filter; - inter_filter_cost = x->switchable_interp_costs[ctx[0]][filter0]; - inter_filter_cost += x->switchable_interp_costs[ctx[1]][filter1]; - return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost; -} - -// Build inter predictor and calculate model rd -// for a given plane. -static INLINE void interp_model_rd_eval( - MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize, - int mi_row, int mi_col, const BUFFER_SET *const orig_dst, int plane_from, - int plane_to, RD_STATS *rd_stats, int is_skip_build_pred) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *const xd = &x->e_mbd; - RD_STATS tmp_rd_stats; - av1_init_rd_stats(&tmp_rd_stats); - - // Skip inter predictor if the predictor is already avilable. - if (!is_skip_build_pred) - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, - plane_from, plane_to); - - model_rd_sb_fn[MODELRD_TYPE_INTERP_FILTER]( - cpi, bsize, x, xd, plane_from, plane_to, mi_row, mi_col, - &tmp_rd_stats.rate, &tmp_rd_stats.dist, &tmp_rd_stats.skip, - &tmp_rd_stats.sse, NULL, NULL, NULL); - - av1_merge_rd_stats(rd_stats, &tmp_rd_stats); -} - -// calculate the rdcost of given interpolation_filter -static INLINE int64_t interpolation_filter_rd( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - const BUFFER_SET *const orig_dst, int64_t *const rd, - RD_STATS *rd_stats_luma, RD_STATS *rd_stats, int *const switchable_rate, - const BUFFER_SET *dst_bufs[2], int filter_idx, const int switchable_ctx[2], - const int skip_pred) { - const AV1_COMMON *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]; - RD_STATS this_rd_stats_luma, this_rd_stats; - - // Initialize rd_stats structures to default values. - av1_init_rd_stats(&this_rd_stats_luma); - this_rd_stats = *rd_stats_luma; - const int_interpfilters last_best = mbmi->interp_filters; - mbmi->interp_filters = filter_sets[filter_idx]; - const int tmp_rs = - get_switchable_rate(x, mbmi->interp_filters, switchable_ctx); - - int64_t min_rd = RDCOST(x->rdmult, tmp_rs, 0); - if (min_rd > *rd) { - mbmi->interp_filters = last_best; - return 0; - } - - (void)tile_data; - - assert(skip_pred != 2); - assert((rd_stats_luma->rate >= 0) && (rd_stats->rate >= 0)); - assert((rd_stats_luma->dist >= 0) && (rd_stats->dist >= 0)); - assert((rd_stats_luma->sse >= 0) && (rd_stats->sse >= 0)); - assert((rd_stats_luma->skip == 0) || (rd_stats_luma->skip == 1)); - assert((rd_stats->skip == 0) || (rd_stats->skip == 1)); - assert((skip_pred >= 0) && (skip_pred <= cpi->default_interp_skip_flags)); - - // When skip pred is equal to default_interp_skip_flags, - // skip both luma and chroma MC. - // For mono-chrome images: - // num_planes = 1 and cpi->default_interp_skip_flags = 1, - // skip_pred = 1: skip both luma and chroma - // skip_pred = 0: Evaluate luma and as num_planes=1, - // skip chroma evaluation - int tmp_skip_pred = (skip_pred == cpi->default_interp_skip_flags) - ? INTERP_SKIP_LUMA_SKIP_CHROMA - : skip_pred; - - switch (tmp_skip_pred) { - case INTERP_EVAL_LUMA_EVAL_CHROMA: - // skip_pred = 0: Evaluate both luma and chroma. - // Luma MC - interp_model_rd_eval(x, cpi, bsize, mi_row, mi_col, orig_dst, AOM_PLANE_Y, - AOM_PLANE_Y, &this_rd_stats_luma, 0); - this_rd_stats = this_rd_stats_luma; -#if CONFIG_COLLECT_RD_STATS == 3 - RD_STATS rd_stats_y; - pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, mi_row, mi_col, - INT64_MAX); - PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); -#endif // CONFIG_COLLECT_RD_STATS == 3 - AOM_FALLTHROUGH_INTENDED; - case INTERP_SKIP_LUMA_EVAL_CHROMA: - // skip_pred = 1: skip luma evaluation (retain previous best luma stats) - // and do chroma evaluation. - for (int plane = 1; plane < num_planes; ++plane) { - int64_t tmp_rd = - RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); - if (tmp_rd >= *rd) { - mbmi->interp_filters = last_best; - return 0; - } - interp_model_rd_eval(x, cpi, bsize, mi_row, mi_col, orig_dst, plane, - plane, &this_rd_stats, 0); - } - break; - case INTERP_SKIP_LUMA_SKIP_CHROMA: - // both luma and chroma evaluation is skipped - this_rd_stats = *rd_stats; - break; - case INTERP_EVAL_INVALID: - default: assert(0); return 0; - } - int64_t tmp_rd = - RDCOST(x->rdmult, tmp_rs + this_rd_stats.rate, this_rd_stats.dist); - - if (tmp_rd < *rd) { - *rd = tmp_rd; - *switchable_rate = tmp_rs; - if (skip_pred != cpi->default_interp_skip_flags) { - if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) { - // Overwrite the data as current filter is the best one - *rd_stats_luma = this_rd_stats_luma; - *rd_stats = this_rd_stats; - // As luma MC data is computed, no need to recompute after the search - x->recalc_luma_mc_data = 0; - } else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) { - // As luma MC data is not computed, update of luma data can be skipped - *rd_stats = this_rd_stats; - // As luma MC data is not recomputed and current filter is the best, - // indicate the possibility of recomputing MC data - // If current buffer contains valid MC data, toggle to indicate that - // luma MC data needs to be recomputed - x->recalc_luma_mc_data ^= 1; - } - swap_dst_buf(xd, dst_bufs, num_planes); - } - return 1; - } - mbmi->interp_filters = last_best; - return 0; -} - -static INLINE INTERP_PRED_TYPE is_pred_filter_search_allowed( - const AV1_COMP *const cpi, MACROBLOCKD *xd, BLOCK_SIZE bsize, int mi_row, - int mi_col, int_interpfilters *af, int_interpfilters *lf) { - const AV1_COMMON *cm = &cpi->common; - const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; - const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; - const int bsl = mi_size_wide_log2[bsize]; - int is_horiz_eq = 0, is_vert_eq = 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; - - if (af->as_filters.x_filter != INTERP_INVALID) - is_horiz_eq = af->as_filters.x_filter == lf->as_filters.x_filter; - if (af->as_filters.y_filter != INTERP_INVALID) - is_vert_eq = af->as_filters.y_filter == lf->as_filters.y_filter; - - INTERP_PRED_TYPE pred_filter_type = (is_vert_eq << 1) + is_horiz_eq; - int pred_filter_enable = - cpi->sf.cb_pred_filter_search - ? (((mi_row + mi_col) >> bsl) + - get_chessboard_index(cm->current_frame.frame_number)) & - 0x1 - : 0; - pred_filter_enable &= is_horiz_eq || is_vert_eq; - // pred_filter_search = 0: pred_filter is disabled - // pred_filter_search = 1: pred_filter is enabled and only horz pred matching - // pred_filter_search = 2: pred_filter is enabled and only vert pred matching - // pred_filter_search = 3: pred_filter is enabled and - // both vert, horz pred matching - return pred_filter_enable * pred_filter_type; -} - -static DUAL_FILTER_TYPE find_best_interp_rd_facade( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, - RD_STATS *rd_stats, int *const switchable_rate, - const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], - const int skip_pred, uint16_t allow_interp_mask, int is_w4_or_h4) { - int tmp_skip_pred = skip_pred; - DUAL_FILTER_TYPE best_filt_type = REG_REG; - - // If no filter are set to be evaluated, return from function - if (allow_interp_mask == 0x0) return best_filt_type; - // For block width or height is 4, skip the pred evaluation of SHARP_SHARP - tmp_skip_pred = is_w4_or_h4 ? cpi->default_interp_skip_flags : skip_pred; - - // Loop over the all filter types and evaluate for only allowed filter types - for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) { - const int is_filter_allowed = - get_interp_filter_allowed_mask(allow_interp_mask, filt_type); - if (is_filter_allowed) - if (interpolation_filter_rd(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, rd_stats_y, rd_stats, - switchable_rate, dst_bufs, filt_type, - switchable_ctx, tmp_skip_pred)) - best_filt_type = filt_type; - tmp_skip_pred = skip_pred; - } - return best_filt_type; -} - -static INLINE void pred_dual_interp_filter_rd( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, - RD_STATS *rd_stats, int *const switchable_rate, - const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], - const int skip_pred, INTERP_PRED_TYPE pred_filt_type, int_interpfilters *af, - int_interpfilters *lf) { - (void)lf; - assert(pred_filt_type > INTERP_HORZ_NEQ_VERT_NEQ); - assert(pred_filt_type < INTERP_PRED_TYPE_ALL); - uint16_t allowed_interp_mask = 0; - - if (pred_filt_type == INTERP_HORZ_EQ_VERT_NEQ) { - // pred_filter_search = 1: Only horizontal filter is matching - allowed_interp_mask = - av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.x_filter]; - } else if (pred_filt_type == INTERP_HORZ_NEQ_VERT_EQ) { - // pred_filter_search = 2: Only vertical filter is matching - allowed_interp_mask = - av1_interp_dual_filt_mask[pred_filt_type - 1][af->as_filters.y_filter]; - } else { - // pred_filter_search = 3: Both horizontal and vertical filter are matching - int filt_type = - af->as_filters.x_filter + af->as_filters.y_filter * SWITCHABLE_FILTERS; - set_interp_filter_allowed_mask(&allowed_interp_mask, filt_type); - } - // REG_REG is already been evaluated in the beginning - reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); - find_best_interp_rd_facade(x, cpi, tile_data, bsize, mi_row, mi_col, orig_dst, - rd, rd_stats_y, rd_stats, switchable_rate, - dst_bufs, switchable_ctx, skip_pred, - allowed_interp_mask, 0); -} -// Evaluate dual filter type -// a) Using above, left block interp filter -// b) Find the best horizontal filter and -// then evaluate corresponding vertical filters. -static INLINE void fast_dual_interp_filter_rd( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, - RD_STATS *rd_stats, int *const switchable_rate, - const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], - const int skip_hor, const int skip_ver) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; - int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); - int_interpfilters lf = af; - - if (!have_newmv_in_inter_mode(mbmi->mode)) - pred_filter_type = - is_pred_filter_search_allowed(cpi, xd, bsize, mi_row, mi_col, &af, &lf); - - if (pred_filter_type) { - pred_dual_interp_filter_rd( - x, cpi, tile_data, bsize, mi_row, mi_col, orig_dst, rd, rd_stats_y, - rd_stats, switchable_rate, dst_bufs, switchable_ctx, - (skip_hor & skip_ver), pred_filter_type, &af, &lf); - } else { - const int bw = block_size_wide[bsize]; - const int bh = block_size_high[bsize]; - int best_dual_mode = 0; - int skip_pred = bw <= 4 ? cpi->default_interp_skip_flags : skip_hor; - // TODO(any): Make use of find_best_interp_rd_facade() - // if speed impact is negligible - for (int i = (SWITCHABLE_FILTERS - 1); i >= 1; --i) { - if (interpolation_filter_rd(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, rd_stats_y, rd_stats, - switchable_rate, dst_bufs, i, switchable_ctx, - skip_pred)) { - best_dual_mode = i; - } - skip_pred = skip_hor; - } - // From best of horizontal EIGHTTAP_REGULAR modes, check vertical modes - skip_pred = bh <= 4 ? cpi->default_interp_skip_flags : skip_ver; - for (int i = (best_dual_mode + (SWITCHABLE_FILTERS * 2)); - i >= (best_dual_mode + SWITCHABLE_FILTERS); i -= SWITCHABLE_FILTERS) { - interpolation_filter_rd( - x, cpi, tile_data, bsize, mi_row, mi_col, orig_dst, rd, rd_stats_y, - rd_stats, switchable_rate, dst_bufs, i, switchable_ctx, skip_pred); - skip_pred = skip_ver; - } - } -} - -// Find the best interp filter if dual_interp_filter = 0 -static INLINE void find_best_non_dual_interp_filter( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - const BUFFER_SET *const orig_dst, int64_t *const rd, RD_STATS *rd_stats_y, - RD_STATS *rd_stats, int *const switchable_rate, - const BUFFER_SET *dst_bufs[2], const int switchable_ctx[2], - const int skip_ver, const int skip_hor) { - int8_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.as_int == filter_sets[0].as_int); - if ((skip_hor & skip_ver) != cpi->default_interp_skip_flags) { - INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ; - int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID); - int_interpfilters lf = af; - - pred_filter_type = - is_pred_filter_search_allowed(cpi, xd, bsize, mi_row, mi_col, &af, &lf); - if (pred_filter_type) { - assert(af.as_filters.x_filter != INTERP_INVALID); - int filter_idx = SWITCHABLE * af.as_filters.x_filter; - // This assert tells that (filter_x == filter_y) for non-dual filter case - assert(filter_sets[filter_idx].as_filters.x_filter == - filter_sets[filter_idx].as_filters.y_filter); - if (cpi->sf.adaptive_interp_filter_search && - !(get_interp_filter_allowed_mask(cpi->sf.interp_filter_search_mask, - filter_idx))) { - return; - } - if (filter_idx) { - interpolation_filter_rd(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, rd_stats_y, rd_stats, - switchable_rate, dst_bufs, filter_idx, - switchable_ctx, (skip_hor & skip_ver)); - } - return; - } - } - // Reuse regular filter's modeled rd data for sharp filter for following - // cases - // 1) When bsize is 4x4 - // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical - // direction is full-pel - // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal - // direction is full-pel - // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction - // alone is full-pel - - if ((bsize == BLOCK_4X4) || - (block_size_wide[bsize] == 4 && - skip_ver == cpi->default_interp_skip_flags) || - (block_size_high[bsize] == 4 && - skip_hor == cpi->default_interp_skip_flags)) { - int skip_pred = skip_hor & skip_ver; - uint16_t allowed_interp_mask = 0; - - // REG_REG filter type is evaluated beforehand, hence skip it - set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP); - set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH); - if (cpi->sf.adaptive_interp_filter_search) - allowed_interp_mask &= cpi->sf.interp_filter_search_mask; - - find_best_interp_rd_facade(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, rd_stats_y, rd_stats, - switchable_rate, dst_bufs, switchable_ctx, - skip_pred, allowed_interp_mask, 1); - } else { - int skip_pred = (skip_hor & skip_ver); - for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE; - i += (SWITCHABLE_FILTERS + 1)) { - // This assert tells that (filter_x == filter_y) for non-dual filter case - assert(filter_sets[i].as_filters.x_filter == - filter_sets[i].as_filters.y_filter); - if (cpi->sf.adaptive_interp_filter_search && - !(get_interp_filter_allowed_mask(cpi->sf.interp_filter_search_mask, - i))) { - continue; - } - interpolation_filter_rd( - x, cpi, tile_data, bsize, mi_row, mi_col, orig_dst, rd, rd_stats_y, - rd_stats, switchable_rate, dst_bufs, i, switchable_ctx, skip_pred); - // In first iteration, smooth filter is evaluated. If smooth filter - // (which is less sharper) is the winner among regular and smooth filters, - // sharp filter evaluation is skipped - // TODO(any): Refine this gating based on modelled rd only (i.e., by not - // accounting switchable filter rate) - if (cpi->sf.skip_sharp_interp_filter_search && - skip_pred != cpi->default_interp_skip_flags) { - if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int) - break; - } - } - } -} - -// check if there is saved result match with this search -static INLINE int is_interp_filter_match(const INTERPOLATION_FILTER_STATS *st, - MB_MODE_INFO *const mi) { - for (int i = 0; i < 2; ++i) { - if ((st->ref_frames[i] != mi->ref_frame[i]) || - (st->mv[i].as_int != mi->mv[i].as_int)) { - return 0; - } - } - if (has_second_ref(mi) && st->comp_type != mi->interinter_comp.type) return 0; - return 1; -} - -// Checks if characteristics of search match -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, - 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 - if (st->filter.as_int != mi->interp_filters.as_int) return 0; - - const MACROBLOCKD *const xd = &x->e_mbd; - // Match MV and reference indices - for (int i = 0; i < 2; ++i) { - if ((st->ref_frames[i] != mi->ref_frame[i]) || - (st->mv[i].as_int != mi->mv[i].as_int)) { - return 0; - } - const WarpedMotionParams *const wm = &xd->global_motion[mi->ref_frame[i]]; - if (is_global_mv_block(mi, wm->wmtype) != st->is_global[i]) return 0; - } - - // Store the stats for COMPOUND_AVERAGE and COMPOUND_DISTWTD - for (int comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; - comp_type++) { - comp_rate[comp_type] = st->rate[comp_type]; - comp_dist[comp_type] = st->dist[comp_type]; - comp_model_rd[comp_type] = st->comp_model_rd[comp_type]; - } - - // 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)) || - (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); - } - return 1; -} - -static INLINE int find_interp_filter_in_stats(MACROBLOCK *x, - MB_MODE_INFO *const mbmi) { - const int comp_idx = mbmi->compound_idx; - const int offset = x->interp_filter_stats_idx[comp_idx]; - for (int j = 0; j < offset; ++j) { - const INTERPOLATION_FILTER_STATS *st = &x->interp_filter_stats[comp_idx][j]; - if (is_interp_filter_match(st, mbmi)) { - mbmi->interp_filters = st->filters; - return j; - } - } - return -1; // no match result found -} -// 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 AV1_COMP *const cpi, - const MACROBLOCK *x, - const MB_MODE_INFO *const mbmi, - 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(cpi, x, &x->comp_rd_stats[j], mbmi, comp_rate, - comp_dist, comp_model_rd)) { - return 1; - } - } - return 0; // no match result found -} - -static INLINE void save_interp_filter_search_stat(MACROBLOCK *x, - MB_MODE_INFO *const mbmi, - int64_t rd, - 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) { - INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters, - { mbmi->mv[0], mbmi->mv[1] }, - { mbmi->ref_frame[0], - mbmi->ref_frame[1] }, - mbmi->interinter_comp.type, - rd, - pred_sse }; - x->interp_filter_stats[comp_idx][offset] = stat; - x->interp_filter_stats_idx[comp_idx]++; - } -} - -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; - rd_stats->filter = mbmi->interp_filters; - rd_stats->ref_mv_idx = mbmi->ref_mv_idx; - const MACROBLOCKD *const xd = &x->e_mbd; - for (int i = 0; i < 2; ++i) { - const WarpedMotionParams *const wm = - &xd->global_motion[mbmi->ref_frame[i]]; - rd_stats->is_global[i] = is_global_mv_block(mbmi, wm->wmtype); - } - ++x->comp_rd_stats_idx; - } -} - -static INLINE int find_interp_filter_match(MACROBLOCK *const x, - const AV1_COMP *const cpi, - const InterpFilter assign_filter, - const int need_search) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - int match_found_idx = -1; - if (cpi->sf.skip_repeat_interpolation_filter_search && need_search) - match_found_idx = find_interp_filter_in_stats(x, mbmi); - - if (!need_search || match_found_idx == -1) - set_default_interp_filters(mbmi, assign_filter); - return match_found_idx; -} - -static INLINE void calc_interp_skip_pred_flag(MACROBLOCK *const x, - const AV1_COMP *const cpi, - int *skip_hor, int *skip_ver) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int num_planes = av1_num_planes(cm); - const int is_compound = has_second_ref(mbmi); - assert(is_intrabc_block(mbmi) == 0); - for (int ref = 0; ref < 1 + is_compound; ++ref) { - const struct scale_factors *const sf = - get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]); - // TODO(any): Refine skip flag calculation considering scaling - if (av1_is_scaled(sf)) { - *skip_hor = 0; - *skip_ver = 0; - break; - } - const MV mv = mbmi->mv[ref].as_mv; - int skip_hor_plane = 0; - int skip_ver_plane = 0; - for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1)); - ++plane_idx) { - struct macroblockd_plane *const pd = &xd->plane[plane_idx]; - const int bw = pd->width; - const int bh = pd->height; - const MV mv_q4 = clamp_mv_to_umv_border_sb( - xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); - const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; - const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; - skip_hor_plane |= ((sub_x == 0) << plane_idx); - skip_ver_plane |= ((sub_y == 0) << plane_idx); - } - *skip_hor &= skip_hor_plane; - *skip_ver &= skip_ver_plane; - // It is not valid that "luma MV is sub-pel, whereas chroma MV is not" - assert(*skip_hor != 2); - assert(*skip_ver != 2); - } - // When compond prediction type is compound segment wedge, luma MC and chroma - // MC need to go hand in hand as mask generated during luma MC is reuired for - // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during - // vertical filter decision may be incorrect as temporary MC evaluation - // overwrites the mask. Make skip_ver as 0 for this case so that mask is - // populated during luma MC - if (is_compound && mbmi->compound_idx == 1 && - mbmi->interinter_comp.type == COMPOUND_DIFFWTD) { - assert(mbmi->comp_group_idx == 1); - if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0; - } -} - -static int64_t interpolation_filter_search( - MACROBLOCK *const x, const AV1_COMP *const cpi, - const TileDataEnc *tile_data, BLOCK_SIZE bsize, int mi_row, int mi_col, - 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 *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; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int need_search = av1_is_interp_needed(xd) && - av1_is_interp_search_needed(xd) && - !cpi->sf.skip_interp_filter_search; - const int ref_frame = xd->mi[0]->ref_frame[0]; - RD_STATS rd_stats_luma, rd_stats; - - // Initialization of rd_stats structures with default values - av1_init_rd_stats(&rd_stats_luma); - av1_init_rd_stats(&rd_stats); - - (void)single_filter; - int match_found_idx = -1; - const InterpFilter assign_filter = cm->interp_filter; - - match_found_idx = - find_interp_filter_match(x, cpi, assign_filter, need_search); - - if (match_found_idx != -1) { - const int comp_idx = mbmi->compound_idx; - *rd = x->interp_filter_stats[comp_idx][match_found_idx].rd; - x->pred_sse[ref_frame] = - x->interp_filter_stats[comp_idx][match_found_idx].pred_sse; - return 0; - } - - int switchable_ctx[2]; - switchable_ctx[0] = av1_get_pred_context_switchable_interp(xd, 0); - switchable_ctx[1] = av1_get_pred_context_switchable_interp(xd, 1); - *switchable_rate = - get_switchable_rate(x, mbmi->interp_filters, switchable_ctx); - - // Do MC evaluation for default filter_type. - // Luma MC - interp_model_rd_eval(x, cpi, bsize, mi_row, mi_col, orig_dst, AOM_PLANE_Y, - AOM_PLANE_Y, &rd_stats_luma, *skip_build_pred); - -#if CONFIG_COLLECT_RD_STATS == 3 - RD_STATS rd_stats_y; - pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, mi_row, mi_col, INT64_MAX); - PrintPredictionUnitStats(cpi, tile_data, x, &rd_stats_y, bsize); -#endif // CONFIG_COLLECT_RD_STATS == 3 - // Chroma MC - if (num_planes > 1) - interp_model_rd_eval(x, cpi, bsize, mi_row, mi_col, orig_dst, AOM_PLANE_U, - AOM_PLANE_V, &rd_stats, *skip_build_pred); - *skip_build_pred = 1; - - av1_merge_rd_stats(&rd_stats, &rd_stats_luma); - - assert(rd_stats.rate >= 0); - - *rd = RDCOST(x->rdmult, *switchable_rate + rd_stats.rate, rd_stats.dist); - x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); - - if (assign_filter != SWITCHABLE || match_found_idx != -1) { - return 0; - } - if (!need_search) { - int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - assert(mbmi->interp_filters.as_int == filters.as_int); - (void)filters; - return 0; - } - if (args->modelled_rd != NULL) { - if (has_second_ref(mbmi)) { - const int ref_mv_idx = mbmi->ref_mv_idx; - MV_REFERENCE_FRAME *refs = mbmi->ref_frame; - const int mode0 = compound_ref0_mode(mbmi->mode); - const int mode1 = compound_ref1_mode(mbmi->mode); - const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]], - args->modelled_rd[mode1][ref_mv_idx][refs[1]]); - if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) { - return INT64_MAX; - } - } - } - - x->recalc_luma_mc_data = 0; - // skip_flag=xx (in binary form) - // Setting 0th flag corresonds to skipping luma MC and setting 1st bt - // corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip - // luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only" - // Skip_flag=2 is not a valid case - // skip_flag=3 corresponds to "Skip both luma and chroma MC" - int skip_hor = cpi->default_interp_skip_flags; - int skip_ver = cpi->default_interp_skip_flags; - calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver); - - // do interp_filter search - restore_dst_buf(xd, *tmp_dst, num_planes); - const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst }; - // Evaluate dual interp filters - if (cm->seq_params.enable_dual_filter) { - if (cpi->sf.use_fast_interpolation_filter_search) { - fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, &rd_stats_luma, &rd_stats, - switchable_rate, dst_bufs, switchable_ctx, - skip_hor, skip_ver); - } else { - // Use full interpolation filter search - uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK; - // REG_REG filter type is evaluated beforehand, so loop is repeated over - // REG_SMOOTH to SHARP_SHARP for full interpolation filter search - reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG); - find_best_interp_rd_facade(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, &rd_stats_luma, &rd_stats, - switchable_rate, dst_bufs, switchable_ctx, - (skip_hor & skip_ver), allowed_interp_mask, 0); - } - } else { - // Evaluate non-dual interp filters - find_best_non_dual_interp_filter(x, cpi, tile_data, bsize, mi_row, mi_col, - orig_dst, rd, &rd_stats_luma, &rd_stats, - switchable_rate, dst_bufs, switchable_ctx, - skip_ver, skip_hor); - } - swap_dst_buf(xd, dst_bufs, num_planes); - // Recompute final MC data if required - if (x->recalc_luma_mc_data == 1) { - // Recomputing final luma MC data is required only if the same was skipped - // in either of the directions Condition below is necessary, but not - // sufficient - assert((skip_hor == 1) || (skip_ver == 1)); - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - } - x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4); - - // save search results - if (cpi->sf.skip_repeat_interpolation_filter_search) { - assert(match_found_idx == -1); - save_interp_filter_search_stat(x, mbmi, *rd, x->pred_sse[ref_frame]); - } - return 0; -} - -static int txfm_search(const AV1_COMP *cpi, const TileDataEnc *tile_data, - MACROBLOCK *x, BLOCK_SIZE bsize, int mi_row, int mi_col, - RD_STATS *rd_stats, RD_STATS *rd_stats_y, - RD_STATS *rd_stats_uv, int mode_rate, - int64_t ref_best_rd) { - /* - * This function combines y and uv planes' transform search processes - * together, when the prediction is generated. It first does subtraction to - * obtain the prediction error. Then it calls - * pick_tx_size_type_yrd/super_block_yrd and super_block_uvrd sequentially and - * handles the early terminations happening in those functions. At the end, it - * computes the rd_stats/_y/_uv accordingly. - */ - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - const int ref_frame_1 = mbmi->ref_frame[1]; - const int64_t mode_rd = RDCOST(x->rdmult, mode_rate, 0); - const int64_t rd_thresh = - ref_best_rd == INT64_MAX ? INT64_MAX : ref_best_rd - mode_rd; - const int skip_ctx = av1_get_skip_context(xd); - const int skip_flag_cost[2] = { x->skip_cost[skip_ctx][0], - x->skip_cost[skip_ctx][1] }; - const int64_t min_header_rate = - mode_rate + AOMMIN(skip_flag_cost[0], skip_flag_cost[1]); - // Account for minimum skip and non_skip rd. - // Eventually either one of them will be added to mode_rate - const int64_t min_header_rd_possible = RDCOST(x->rdmult, min_header_rate, 0); - (void)tile_data; - - if (min_header_rd_possible > ref_best_rd) { - av1_invalid_rd_stats(rd_stats_y); - return 0; - } - - av1_init_rd_stats(rd_stats); - av1_init_rd_stats(rd_stats_y); - rd_stats->rate = mode_rate; - - // cost and distortion - av1_subtract_plane(x, bsize, 0); - if (x->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id]) { - pick_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, mi_row, mi_col, rd_thresh); -#if CONFIG_COLLECT_RD_STATS == 2 - PrintPredictionUnitStats(cpi, tile_data, x, rd_stats_y, bsize); -#endif // CONFIG_COLLECT_RD_STATS == 2 - } else { - super_block_yrd(cpi, x, rd_stats_y, bsize, rd_thresh); - memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size)); - for (int i = 0; i < xd->n4_h * xd->n4_w; ++i) - set_blk_skip(x, 0, i, rd_stats_y->skip); - } - - if (rd_stats_y->rate == INT_MAX) { - // TODO(angiebird): check if we need this - // restore_dst_buf(xd, *orig_dst, num_planes); - mbmi->ref_frame[1] = ref_frame_1; - return 0; - } - - av1_merge_rd_stats(rd_stats, rd_stats_y); - - const int64_t non_skip_rdcosty = - RDCOST(x->rdmult, rd_stats->rate + skip_flag_cost[0], rd_stats->dist); - const int64_t skip_rdcosty = - RDCOST(x->rdmult, mode_rate + skip_flag_cost[1], rd_stats->sse); - const int64_t min_rdcosty = AOMMIN(non_skip_rdcosty, skip_rdcosty); - if (min_rdcosty > ref_best_rd) { - const int64_t tokenonly_rdy = - AOMMIN(RDCOST(x->rdmult, rd_stats_y->rate, rd_stats_y->dist), - RDCOST(x->rdmult, 0, rd_stats_y->sse)); - // Invalidate rd_stats_y to skip the rest of the motion modes search - if (tokenonly_rdy - (tokenonly_rdy >> cpi->sf.prune_motion_mode_level) > - rd_thresh) - av1_invalid_rd_stats(rd_stats_y); - mbmi->ref_frame[1] = ref_frame_1; - return 0; - } - - 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_chroma_rd); - if (!is_cost_valid_uv) { - mbmi->ref_frame[1] = ref_frame_1; - return 0; - } - av1_merge_rd_stats(rd_stats, rd_stats_uv); - } - - if (rd_stats->skip) { - rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate; - rd_stats_y->rate = 0; - rd_stats_uv->rate = 0; - rd_stats->dist = rd_stats->sse; - rd_stats_y->dist = rd_stats_y->sse; - rd_stats_uv->dist = rd_stats_uv->sse; - rd_stats->rate += skip_flag_cost[1]; - mbmi->skip = 1; - // here mbmi->skip temporarily plays a role as what this_skip2 does - - const int64_t tmprd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); - if (tmprd > ref_best_rd) { - mbmi->ref_frame[1] = ref_frame_1; - return 0; - } - } else if (!xd->lossless[mbmi->segment_id] && - (RDCOST(x->rdmult, - rd_stats_y->rate + rd_stats_uv->rate + skip_flag_cost[0], - rd_stats->dist) >= - RDCOST(x->rdmult, skip_flag_cost[1], rd_stats->sse))) { - rd_stats->rate -= rd_stats_uv->rate + rd_stats_y->rate; - rd_stats->rate += skip_flag_cost[1]; - rd_stats->dist = rd_stats->sse; - rd_stats_y->dist = rd_stats_y->sse; - rd_stats_uv->dist = rd_stats_uv->sse; - rd_stats_y->rate = 0; - rd_stats_uv->rate = 0; - mbmi->skip = 1; - } else { - rd_stats->rate += skip_flag_cost[0]; - mbmi->skip = 0; - } - - return 1; -} - -static INLINE bool enable_wedge_search(MACROBLOCK *const x, - const AV1_COMP *const cpi) { - // Enable wedge search if source variance and edge strength are above - // the thresholds. - return x->source_variance > cpi->sf.disable_wedge_search_var_thresh && - x->edge_strength > cpi->sf.disable_wedge_search_edge_thresh; -} - -static INLINE bool enable_wedge_interinter_search(MACROBLOCK *const x, - const AV1_COMP *const cpi) { - return enable_wedge_search(x, cpi) && cpi->oxcf.enable_interinter_wedge; -} - -static INLINE bool enable_wedge_interintra_search(MACROBLOCK *const x, - const AV1_COMP *const cpi) { - return enable_wedge_search(x, cpi) && cpi->oxcf.enable_interintra_wedge && - !cpi->sf.disable_wedge_interintra_search; -} - -static int handle_inter_intra_mode(const AV1_COMP *const cpi, - MACROBLOCK *const x, BLOCK_SIZE bsize, - int mi_row, int mi_col, MB_MODE_INFO *mbmi, - HandleInterModeArgs *args, - int64_t ref_best_rd, int *rate_mv, - int *tmp_rate2, const BUFFER_SET *orig_dst) { - const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - MACROBLOCKD *xd = &x->e_mbd; - - INTERINTRA_MODE best_interintra_mode = II_DC_PRED; - int64_t rd = INT64_MAX; - int64_t best_interintra_rd = INT64_MAX; - int rmode, rate_sum; - int64_t dist_sum; - int tmp_rate_mv = 0; - int tmp_skip_txfm_sb; - int bw = block_size_wide[bsize]; - int64_t tmp_skip_sse_sb; - DECLARE_ALIGNED(16, uint8_t, tmp_buf_[2 * MAX_INTERINTRA_SB_SQUARE]); - DECLARE_ALIGNED(16, uint8_t, intrapred_[2 * MAX_INTERINTRA_SB_SQUARE]); - uint8_t *tmp_buf = get_buf_by_bd(xd, tmp_buf_); - uint8_t *intrapred = get_buf_by_bd(xd, intrapred_); - const int *const interintra_mode_cost = - x->interintra_mode_cost[size_group_lookup[bsize]]; - const int_mv mv0 = mbmi->mv[0]; - const int is_wedge_used = is_interintra_wedge_used(bsize); - int rwedge = is_wedge_used ? x->wedge_interintra_cost[bsize][0] : 0; - mbmi->ref_frame[1] = NONE_FRAME; - xd->plane[0].dst.buf = tmp_buf; - xd->plane[0].dst.stride = bw; - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - - restore_dst_buf(xd, *orig_dst, num_planes); - mbmi->ref_frame[1] = INTRA_FRAME; - best_interintra_mode = args->inter_intra_mode[mbmi->ref_frame[0]]; - - 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 || cpi->sf.disable_smooth_intra) && - (INTERINTRA_MODE)j == II_SMOOTH_PRED) - continue; - mbmi->interintra_mode = (INTERINTRA_MODE)j; - rmode = interintra_mode_cost[mbmi->interintra_mode]; - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, - intrapred, bw); - av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); - model_rd_sb_fn[MODELRD_TYPE_INTERINTRA]( - 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, tmp_rate_mv + rate_sum + rmode, dist_sum); - if (rd < best_interintra_rd) { - best_interintra_rd = rd; - best_interintra_mode = mbmi->interintra_mode; - } - } - args->inter_intra_mode[mbmi->ref_frame[0]] = best_interintra_mode; - } - 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) { - mbmi->interintra_mode = best_interintra_mode; - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, - intrapred, bw); - av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); - } - - RD_STATS rd_stats; - const int64_t rd_thresh = get_rd_thresh_from_best_rd( - ref_best_rd, (1 << INTER_INTRA_RD_THRESH_SHIFT), - INTER_INTRA_RD_THRESH_SCALE); - const int64_t mode_rd = RDCOST(x->rdmult, *rate_mv + rmode + rwedge, 0); - const int64_t tmp_rd_thresh = rd_thresh - mode_rd; - rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &rd_stats); - if (rd != INT64_MAX) { - rd = RDCOST(x->rdmult, *rate_mv + rmode + rd_stats.rate + rwedge, - rd_stats.dist); - } - best_interintra_rd = rd; - if (ref_best_rd < INT64_MAX && - ((((best_interintra_rd >> INTER_INTRA_RD_THRESH_SHIFT) * - INTER_INTRA_RD_THRESH_SCALE) > ref_best_rd) || - (best_interintra_rd == INT64_MAX))) { - return -1; - } - } - if (is_wedge_used) { - int64_t best_interintra_rd_nowedge = rd; - int64_t best_interintra_rd_wedge = INT64_MAX; - int_mv tmp_mv; - if (enable_wedge_interintra_search(x, cpi)) { - mbmi->use_wedge_interintra = 1; - - rwedge = av1_cost_literal(get_interintra_wedge_bits(bsize)) + - x->wedge_interintra_cost[bsize][1]; - - 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; - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, - intrapred, bw); - best_interintra_rd_wedge = - pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); - - int j = 0; - for (j = 0; j < INTERINTRA_MODES; ++j) { - mbmi->interintra_mode = (INTERINTRA_MODE)j; - rmode = interintra_mode_cost[mbmi->interintra_mode]; - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, - orig_dst, intrapred, bw); - av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); - model_rd_sb_fn[MODELRD_TYPE_INTERINTRA]( - 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, tmp_rate_mv + rate_sum + rmode, dist_sum); - if (rd < best_interintra_rd) { - best_interintra_rd_wedge = rd; - best_interintra_mode = mbmi->interintra_mode; - } - } - args->inter_intra_mode[mbmi->ref_frame[0]] = best_interintra_mode; - mbmi->interintra_mode = best_interintra_mode; - - if (best_interintra_mode != II_SMOOTH_PRED) { - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, - orig_dst, intrapred, bw); - } - } else { - mbmi->interintra_mode = best_interintra_mode; - av1_build_intra_predictors_for_interintra(cm, xd, bsize, 0, orig_dst, - intrapred, bw); - best_interintra_rd_wedge = - pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); - } - } else { - best_interintra_rd_wedge = - pick_interintra_wedge(cpi, x, bsize, intrapred_, tmp_buf_); - } - - rmode = interintra_mode_cost[mbmi->interintra_mode]; - best_interintra_rd_wedge += - RDCOST(x->rdmult, rmode + *rate_mv + rwedge, 0); - rd = INT64_MAX; - // Refine motion vector. - if (have_newmv_in_inter_mode(mbmi->mode)) { - // get negative of mask - const uint8_t *mask = av1_get_contiguous_soft_mask( - mbmi->interintra_wedge_index, 1, bsize); - tmp_mv = mbmi->mv[0]; - compound_single_motion_search(cpi, x, bsize, &tmp_mv.as_mv, mi_row, - mi_col, intrapred, mask, bw, &tmp_rate_mv, - 0); - if (mbmi->mv[0].as_int != tmp_mv.as_int) { - mbmi->mv[0].as_int = tmp_mv.as_int; - 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_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, tmp_rate_mv + rmode + rate_sum + rwedge, - dist_sum); - } - } - if (rd >= best_interintra_rd_wedge) { - tmp_mv.as_int = mv0.as_int; - tmp_rate_mv = *rate_mv; - av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw); - } - // Evaluate closer to true rd - RD_STATS rd_stats; - const int64_t mode_rd = - RDCOST(x->rdmult, rmode + tmp_rate_mv + rwedge, 0); - const int64_t tmp_rd_thresh = best_interintra_rd_nowedge - mode_rd; - rd = estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &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 || - cpi->sf.disable_smooth_interintra || - best_interintra_rd_nowedge == INT64_MAX) && - best_interintra_rd_wedge == INT64_MAX) - return -1; - if (best_interintra_rd_wedge < best_interintra_rd_nowedge) { - mbmi->use_wedge_interintra = 1; - mbmi->mv[0].as_int = tmp_mv.as_int; - *tmp_rate2 += tmp_rate_mv - *rate_mv; - *rate_mv = tmp_rate_mv; - } else { - mbmi->use_wedge_interintra = 0; - mbmi->mv[0].as_int = mv0.as_int; - av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, - AOM_PLANE_Y, AOM_PLANE_Y); - } - } else { - if (!cpi->oxcf.enable_smooth_interintra || - cpi->sf.disable_smooth_interintra) - return -1; - mbmi->use_wedge_interintra = 0; - } - } 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); - } - return 0; -} - // If number of valid neighbours is 1, // 1) ROTZOOM parameters can be obtained reliably (2 parameters from // one neighbouring MV) @@ -9613,7 +1189,7 @@ static int check_if_optimal_warp(const AV1_COMP *cpi, WarpedMotionParams *wm_params, int num_proj_ref) { int is_valid_warp = 1; - if (cpi->sf.prune_warp_using_wmtype) { + if (cpi->sf.inter_sf.prune_warp_using_wmtype) { TransformationType wmtype = get_wmtype(wm_params); if (num_proj_ref == 1) { if (wmtype != ROTZOOM) is_valid_warp = 0; @@ -9624,62 +1200,36 @@ static int check_if_optimal_warp(const AV1_COMP *cpi, return is_valid_warp; } -struct obmc_check_mv_field_ctxt { - MB_MODE_INFO *current_mi; - int mv_field_check_result; -}; - -static INLINE void obmc_check_identical_mv(MACROBLOCKD *xd, int rel_mi_col, - uint8_t nb_mi_width, - MB_MODE_INFO *nb_mi, void *fun_ctxt, - const int num_planes) { - (void)xd; - (void)rel_mi_col; - (void)nb_mi_width; - (void)num_planes; - struct obmc_check_mv_field_ctxt *ctxt = - (struct obmc_check_mv_field_ctxt *)fun_ctxt; - const MB_MODE_INFO *current_mi = ctxt->current_mi; - - if (ctxt->mv_field_check_result == 0) return; - - if (nb_mi->ref_frame[0] != current_mi->ref_frame[0] || - nb_mi->mv[0].as_int != current_mi->mv[0].as_int || - nb_mi->interp_filters.as_int != current_mi->interp_filters.as_int) { - ctxt->mv_field_check_result = 0; +static INLINE void update_mode_start_end_index(const AV1_COMP *const cpi, + int *mode_index_start, + int *mode_index_end, + int last_motion_mode_allowed, + int interintra_allowed, + int eval_motion_mode) { + *mode_index_start = (int)SIMPLE_TRANSLATION; + *mode_index_end = (int)last_motion_mode_allowed + interintra_allowed; + if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) { + if (!eval_motion_mode) { + *mode_index_end = (int)SIMPLE_TRANSLATION; + } else { + // Set the start index appropriately to process motion modes other than + // simple translation + *mode_index_start = 1; + } } } -// Check if the neighbors' motions used by obmc have same parameters as for -// the current block. If all the parameters are identical, obmc will produce -// the same prediction as from regular bmc, therefore we can skip the -// overlapping operations for less complexity. The parameters checked include -// reference frame, motion vector, and interpolation filter. -static int check_identical_obmc_mv_field(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col) { - const BLOCK_SIZE bsize = xd->mi[0]->sb_type; - struct obmc_check_mv_field_ctxt mv_field_check_ctxt = { xd->mi[0], 1 }; - - foreach_overlappable_nb_above(cm, xd, mi_col, - max_neighbor_obmc[mi_size_wide_log2[bsize]], - obmc_check_identical_mv, &mv_field_check_ctxt); - foreach_overlappable_nb_left(cm, xd, mi_row, - max_neighbor_obmc[mi_size_high_log2[bsize]], - obmc_check_identical_mv, &mv_field_check_ctxt); - - return mv_field_check_ctxt.mv_field_check_result; -} - // 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( const AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *const 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 *const args, int64_t ref_best_rd, const int *refs, - int *rate_mv, const BUFFER_SET *orig_dst, int64_t *best_est_rd, - int do_tx_search, InterModesInfo *inter_modes_info) { + RD_STATS *rd_stats_uv, int *disable_skip, HandleInterModeArgs *const args, + int64_t ref_best_rd, int64_t *ref_skip_rd, int *rate_mv, + const BUFFER_SET *orig_dst, int64_t *best_est_rd, int do_tx_search, + InterModesInfo *inter_modes_info, int eval_motion_mode) { const AV1_COMMON *const cm = &cpi->common; + const FeatureFlags *const features = &cm->features; const int num_planes = av1_num_planes(cm); MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = xd->mi[0]; @@ -9703,13 +1253,13 @@ static int64_t motion_mode_rd( aom_clear_system_state(); mbmi->num_proj_ref = 1; // assume num_proj_ref >=1 MOTION_MODE last_motion_mode_allowed = SIMPLE_TRANSLATION; - if (cm->switchable_motion_mode) { - last_motion_mode_allowed = motion_mode_allowed(xd->global_motion, xd, mbmi, - cm->allow_warped_motion); + if (features->switchable_motion_mode) { + last_motion_mode_allowed = motion_mode_allowed( + xd->global_motion, xd, mbmi, features->allow_warped_motion); } + if (last_motion_mode_allowed == WARPED_CAUSAL) { - mbmi->num_proj_ref = - av1_findSamples(cm, xd, mi_row, mi_col, pts0, pts_inref0); + mbmi->num_proj_ref = av1_findSamples(cm, xd, pts0, pts_inref0); } const int total_samples = mbmi->num_proj_ref; if (total_samples == 0) { @@ -9719,20 +1269,22 @@ static int64_t motion_mode_rd( const MB_MODE_INFO base_mbmi = *mbmi; MB_MODE_INFO best_mbmi; SimpleRDState *const simple_states = &args->simple_rd_state[mbmi->ref_mv_idx]; + const int interp_filter = features->interp_filter; const int switchable_rate = - av1_is_interp_needed(xd) ? av1_get_switchable_rate(cm, x, xd) : 0; + av1_is_interp_needed(xd) ? av1_get_switchable_rate(x, xd, interp_filter) + : 0; int64_t best_rd = INT64_MAX; int best_rate_mv = rate_mv0; - const int identical_obmc_mv_field_detected = - (cpi->sf.skip_obmc_in_uniform_mv_field || - cpi->sf.skip_wm_in_uniform_mv_field) - ? check_identical_obmc_mv_field(cm, xd, mi_row, mi_col) - : 0; - for (int mode_index = (int)SIMPLE_TRANSLATION; - mode_index <= (int)last_motion_mode_allowed + interintra_allowed; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + int mode_index_start, mode_index_end; + update_mode_start_end_index(cpi, &mode_index_start, &mode_index_end, + last_motion_mode_allowed, interintra_allowed, + eval_motion_mode); + for (int mode_index = mode_index_start; mode_index <= mode_index_end; mode_index++) { if (args->skip_motion_mode && mode_index) continue; - if (cpi->sf.prune_single_motion_modes_by_simple_trans && + if (cpi->sf.inter_sf.prune_single_motion_modes_by_simple_trans && args->single_ref_first_pass && mode_index) break; int tmp_rate2 = rate2_nocoeff; @@ -9748,28 +1300,19 @@ static int64_t motion_mode_rd( } const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); - const int prune_obmc = - cpi->sf.prune_obmc_using_stats && - (cpi->obmc_probs[update_type][bsize] < cpi->obmc_probs_thresh); - if ((cpi->oxcf.enable_obmc == 0 || cpi->sf.use_fast_nonrd_pick_mode || - prune_obmc) && + const int prune_obmc = cpi->frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + if ((cpi->oxcf.enable_obmc == 0 || cpi->sf.inter_sf.disable_obmc || + cpi->sf.rt_sf.use_nonrd_pick_mode || prune_obmc) && mbmi->motion_mode == OBMC_CAUSAL) continue; - if (identical_obmc_mv_field_detected) { - if (cpi->sf.skip_obmc_in_uniform_mv_field && - mbmi->motion_mode == OBMC_CAUSAL) - continue; - if (cpi->sf.skip_wm_in_uniform_mv_field && - mbmi->motion_mode == WARPED_CAUSAL) - continue; - } - if (mbmi->motion_mode == SIMPLE_TRANSLATION && !is_interintra_mode) { // 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 && !is_comp_pred) { + if (cpi->sf.inter_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); @@ -9781,9 +1324,9 @@ static int64_t motion_mode_rd( 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); + sizeof(x->blk_skip[0]) * xd->height * xd->width); av1_copy_array(best_tx_type_map, simple_states->tx_type_map, - xd->n4_h * xd->n4_w); + xd->height * xd->width); best_xskip = simple_states->skip; best_disable_skip = simple_states->disable_skip; best_mbmi = *mbmi; @@ -9796,23 +1339,23 @@ static int64_t motion_mode_rd( const uint32_t cur_mv = mbmi->mv[0].as_int; assert(!is_comp_pred); if (have_newmv_in_inter_mode(this_mode)) { - single_motion_search(cpi, x, bsize, mi_row, mi_col, 0, &tmp_rate_mv); - mbmi->mv[0].as_int = x->best_mv.as_int; + av1_single_motion_search(cpi, x, bsize, 0, &tmp_rate_mv, INT_MAX, NULL, + &mbmi->mv[0]); tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv; } - if (mbmi->mv[0].as_int != cur_mv) { + if ((mbmi->mv[0].as_int != cur_mv) || eval_motion_mode) { av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, 0, av1_num_planes(cm) - 1); } av1_build_obmc_inter_prediction( - cm, xd, mi_row, mi_col, args->above_pred_buf, args->above_pred_stride, + cm, xd, args->above_pred_buf, args->above_pred_stride, args->left_pred_buf, args->left_pred_stride); } else if (mbmi->motion_mode == WARPED_CAUSAL) { int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE]; mbmi->motion_mode = WARPED_CAUSAL; mbmi->wm_params.wmtype = DEFAULT_WMTYPE; - mbmi->interp_filters = av1_broadcast_interp_filter( - av1_unswitchable_filter(cm->interp_filter)); + mbmi->interp_filters = + av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter)); memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0)); memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0)); @@ -9832,26 +1375,28 @@ static int64_t motion_mode_rd( const WarpedMotionParams wm_params0 = mbmi->wm_params; const int num_proj_ref0 = mbmi->num_proj_ref; - if (cpi->sf.prune_warp_using_wmtype) { + if (cpi->sf.inter_sf.prune_warp_using_wmtype) { TransformationType wmtype = get_wmtype(&mbmi->wm_params); if (wmtype < ROTZOOM) continue; } + const int_mv ref_mv = av1_get_ref_mv(x, 0); + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, + &ref_mv.as_mv, NULL); + // Refine MV in a small range. - av1_refine_warped_mv(cpi, x, bsize, mi_row, mi_col, pts0, pts_inref0, + av1_refine_warped_mv(xd, cm, &ms_params, bsize, pts0, pts_inref0, total_samples); // Keep the refined MV and WM parameters. if (mv0.as_int != mbmi->mv[0].as_int) { - const int ref = refs[0]; - const int_mv ref_mv = av1_get_ref_mv(x, 0); tmp_rate_mv = av1_mv_bit_cost(&mbmi->mv[0].as_mv, &ref_mv.as_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT); - - if (cpi->sf.adaptive_motion_search) - x->pred_mv[ref] = mbmi->mv[0].as_mv; - + if (cpi->sf.mv_sf.adaptive_motion_search) { + x->pred_mv[mbmi->ref_frame[0]] = mbmi->mv[0].as_mv; + } tmp_rate2 = rate2_nocoeff - rate_mv0 + tmp_rate_mv; } else { // Restore the old MV and WM parameters. @@ -9870,13 +1415,39 @@ static int64_t motion_mode_rd( continue; } } else if (is_interintra_mode) { - 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); + const int ret = + av1_handle_inter_intra_mode(cpi, x, bsize, mbmi, args, ref_best_rd, + &tmp_rate_mv, &tmp_rate2, orig_dst); if (ret < 0) continue; } - x->skip = 0; + // If we are searching newmv and the mv is the same as refmv, skip the + // current mode + if (this_mode == NEW_NEWMV) { + const int_mv ref_mv_0 = av1_get_ref_mv(x, 0); + const int_mv ref_mv_1 = av1_get_ref_mv(x, 1); + if (mbmi->mv[0].as_int == ref_mv_0.as_int || + mbmi->mv[1].as_int == ref_mv_1.as_int) { + continue; + } + } else if (this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV) { + const int_mv ref_mv_1 = av1_get_ref_mv(x, 1); + if (mbmi->mv[1].as_int == ref_mv_1.as_int) { + continue; + } + } else if (this_mode == NEW_NEARESTMV || this_mode == NEW_NEARMV) { + const int_mv ref_mv_0 = av1_get_ref_mv(x, 0); + if (mbmi->mv[0].as_int == ref_mv_0.as_int) { + continue; + } + } else if (this_mode == NEWMV) { + const int_mv ref_mv_0 = av1_get_ref_mv(x, 0); + if (mbmi->mv[0].as_int == ref_mv_0.as_int) { + continue; + } + } + + x->force_skip = 0; rd_stats->dist = 0; rd_stats->sse = 0; rd_stats->skip = 1; @@ -9885,18 +1456,6 @@ static int64_t motion_mode_rd( if (interintra_allowed) { rd_stats->rate += x->interintra_cost[size_group_lookup[bsize]] [mbmi->ref_frame[1] == INTRA_FRAME]; - if (mbmi->ref_frame[1] == INTRA_FRAME) { - rd_stats->rate += x->interintra_mode_cost[size_group_lookup[bsize]] - [mbmi->interintra_mode]; - if (is_interintra_wedge_used(bsize)) { - rd_stats->rate += - x->wedge_interintra_cost[bsize][mbmi->use_wedge_interintra]; - if (mbmi->use_wedge_interintra) { - rd_stats->rate += - av1_cost_literal(get_interintra_wedge_bits(bsize)); - } - } - } } if ((last_motion_mode_allowed > SIMPLE_TRANSLATION) && (mbmi->ref_frame[1] != INTRA_FRAME)) { @@ -9909,20 +1468,25 @@ static int64_t motion_mode_rd( if (!do_tx_search) { int64_t curr_sse = -1; + int64_t sse_y = -1; int est_residue_cost = 0; int64_t est_dist = 0; int64_t est_rd = 0; - if (cpi->sf.inter_mode_rd_model_estimation == 1) { - curr_sse = get_sse(cpi, x); + if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) { + curr_sse = get_sse(cpi, x, &sse_y); + // Scale luma SSE as per bit depth so as to be consistent with + // model_rd_sb_fn and compound type rd + sse_y = ROUND_POWER_OF_TWO(sse_y, (xd->bd - 8) * 2); const int has_est_rd = get_est_rate_dist(tile_data, bsize, curr_sse, &est_residue_cost, &est_dist); (void)has_est_rd; assert(has_est_rd); - } else if (cpi->sf.inter_mode_rd_model_estimation == 2 || - cpi->sf.use_nonrd_pick_mode) { + } else if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 2 || + cpi->sf.rt_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); + cpi, bsize, x, xd, 0, num_planes - 1, &est_residue_cost, &est_dist, + NULL, &curr_sse, NULL, NULL, NULL); + sse_y = x->pred_sse[xd->mi[0]->ref_frame[0]]; } est_rd = RDCOST(x->rdmult, rd_stats->rate + est_residue_cost, est_dist); if (est_rd * 0.80 > *best_est_rd) { @@ -9933,7 +1497,13 @@ static int64_t motion_mode_rd( rd_stats->rate += est_residue_cost; rd_stats->dist = est_dist; rd_stats->rdcost = est_rd; - *best_est_rd = AOMMIN(*best_est_rd, rd_stats->rdcost); + if (rd_stats->rdcost < *best_est_rd) { + *best_est_rd = rd_stats->rdcost; + assert(sse_y >= 0); + ref_skip_rd[1] = cpi->sf.inter_sf.txfm_rd_gate_level + ? RDCOST(x->rdmult, mode_rate, (sse_y << 4)) + : INT64_MAX; + } if (cm->current_frame.reference_mode == SINGLE_REFERENCE) { if (!is_comp_pred) { assert(curr_sse >= 0); @@ -9947,11 +1517,28 @@ static int64_t motion_mode_rd( rd_stats->rdcost, rd_stats, rd_stats_y, rd_stats_uv, mbmi); } + mbmi->skip = 0; } 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)) { + int64_t skip_rd = INT64_MAX; + int64_t skip_rdy = INT64_MAX; + if (cpi->sf.inter_sf.txfm_rd_gate_level) { + // Check if the mode is good enough based on skip RD + int64_t sse_y = INT64_MAX; + int64_t curr_sse = get_sse(cpi, x, &sse_y); + // Scale luma SSE as per bit depth so as to be consistent with + // model_rd_sb_fn and compound type rd + sse_y = ROUND_POWER_OF_TWO(sse_y, (xd->bd - 8) * 2); + skip_rd = RDCOST(x->rdmult, rd_stats->rate, curr_sse); + skip_rdy = RDCOST(x->rdmult, rd_stats->rate, (sse_y << 4)); + int eval_txfm = check_txfm_eval(x, bsize, ref_skip_rd[0], skip_rd, + cpi->sf.inter_sf.txfm_rd_gate_level, 0); + if (!eval_txfm) continue; + } + + if (!av1_txfm_search(cpi, x, bsize, rd_stats, rd_stats_y, rd_stats_uv, + rd_stats->rate, ref_best_rd)) { if (rd_stats_y->rate == INT_MAX && mode_index == 0) { - if (cpi->sf.prune_single_motion_modes_by_simple_trans && + if (cpi->sf.inter_sf.prune_single_motion_modes_by_simple_trans && !is_comp_pred) { simple_states->early_skipped = 1; } @@ -9961,9 +1548,13 @@ static int64_t motion_mode_rd( } const int64_t curr_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); - ref_best_rd = AOMMIN(ref_best_rd, curr_rd); + if (curr_rd < ref_best_rd) { + ref_best_rd = curr_rd; + ref_skip_rd[0] = skip_rd; + ref_skip_rd[1] = skip_rdy; + } *disable_skip = 0; - if (cpi->sf.inter_mode_rd_model_estimation == 1) { + if (cpi->sf.inter_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, @@ -9974,8 +1565,8 @@ static int64_t motion_mode_rd( if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) { if (is_nontrans_global_motion(xd, xd->mi[0])) { - mbmi->interp_filters = av1_broadcast_interp_filter( - av1_unswitchable_filter(cm->interp_filter)); + mbmi->interp_filters = + av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter)); } } @@ -9988,10 +1579,10 @@ static int64_t motion_mode_rd( simple_states->rd_stats_y = *rd_stats_y; simple_states->rd_stats_uv = *rd_stats_uv; memcpy(simple_states->blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); + sizeof(x->blk_skip[0]) * xd->height * xd->width); av1_copy_array(simple_states->tx_type_map, xd->tx_type_map, - xd->n4_h * xd->n4_w); - simple_states->skip = x->skip; + xd->height * xd->width); + simple_states->skip = mbmi->skip; simple_states->disable_skip = *disable_skip; } } @@ -10003,11 +1594,13 @@ static int64_t motion_mode_rd( best_rate_mv = tmp_rate_mv; if (num_planes > 1) best_rd_stats_uv = *rd_stats_uv; memcpy(best_blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); - av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->n4_h * xd->n4_w); - best_xskip = x->skip; + sizeof(x->blk_skip[0]) * xd->height * xd->width); + av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->height * xd->width); + best_xskip = mbmi->skip; best_disable_skip = *disable_skip; - if (best_xskip) break; + // TODO(anyone): evaluate the quality and speed trade-off of the early + // termination logic below. + // if (best_xskip) break; } } mbmi->ref_frame[1] = ref_frame_1; @@ -10022,9 +1615,9 @@ static int64_t motion_mode_rd( *rd_stats_y = best_rd_stats_y; if (num_planes > 1) *rd_stats_uv = best_rd_stats_uv; memcpy(x->blk_skip, best_blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); - av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->n4_h * xd->n4_w); - x->skip = best_xskip; + sizeof(x->blk_skip[0]) * xd->height * xd->width); + av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width); + x->force_skip = best_xskip; *disable_skip = best_disable_skip; restore_dst_buf(xd, *orig_dst, num_planes); @@ -10032,12 +1625,14 @@ static int64_t motion_mode_rd( } static int64_t skip_mode_rd(RD_STATS *rd_stats, const AV1_COMP *const cpi, - MACROBLOCK *const x, BLOCK_SIZE bsize, int mi_row, - int mi_col, const BUFFER_SET *const orig_dst) { + MACROBLOCK *const x, BLOCK_SIZE bsize, + const BUFFER_SET *const orig_dst) { + assert(bsize < BLOCK_SIZES_ALL); const AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); MACROBLOCKD *const xd = &x->e_mbd; - assert(bsize < BLOCK_SIZES_ALL); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize, 0, av1_num_planes(cm) - 1); @@ -10050,7 +1645,7 @@ static int64_t skip_mode_rd(RD_STATS *rd_stats, const AV1_COMP *const cpi, const int bw = block_size_wide[plane_bsize]; const int bh = block_size_high[plane_bsize]; - av1_subtract_plane(x, bsize, plane); + av1_subtract_plane(x, plane_bsize, plane); int64_t sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh) << 4; total_sse += sse; } @@ -10063,17 +1658,58 @@ static int64_t skip_mode_rd(RD_STATS *rd_stats, const AV1_COMP *const cpi, return 0; } -static INLINE void get_this_mv(int_mv *this_mv, PREDICTION_MODE this_mode, - int ref_idx, int ref_mv_idx, - const MV_REFERENCE_FRAME *ref_frame, - const MB_MODE_INFO_EXT *mbmi_ext) { - const int is_comp_pred = ref_frame[1] > INTRA_FRAME; - const PREDICTION_MODE single_mode = - get_single_mode(this_mode, ref_idx, is_comp_pred); +// Check NEARESTMV, NEARMV, GLOBALMV ref mvs for duplicate and skip the relevant +// mode +static INLINE int check_repeat_ref_mv(const MB_MODE_INFO_EXT *mbmi_ext, + int ref_idx, + const MV_REFERENCE_FRAME *ref_frame, + PREDICTION_MODE single_mode) { + const uint8_t ref_frame_type = av1_ref_frame_type(ref_frame); + const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type]; + assert(single_mode != NEWMV); + if (single_mode == NEARESTMV) { + return 0; + } else if (single_mode == NEARMV) { + // when ref_mv_count = 0, NEARESTMV and NEARMV are same as GLOBALMV + // when ref_mv_count = 1, NEARMV is same as GLOBALMV + if (ref_mv_count < 2) return 1; + } else if (single_mode == GLOBALMV) { + // when ref_mv_count == 0, GLOBALMV is same as NEARESTMV + if (ref_mv_count == 0) return 1; + // when ref_mv_count == 1, NEARMV is same as GLOBALMV + else if (ref_mv_count == 1) + return 0; + + int stack_size = AOMMIN(USABLE_REF_MV_STACK_SIZE, ref_mv_count); + // Check GLOBALMV is matching with any mv in ref_mv_stack + for (int ref_mv_idx = 0; ref_mv_idx < stack_size; ref_mv_idx++) { + int_mv this_mv; + + if (ref_idx == 0) + this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + else + this_mv = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv; + + if (this_mv.as_int == mbmi_ext->global_mvs[ref_frame[ref_idx]].as_int) + return 1; + } + } + return 0; +} + +static INLINE int get_this_mv(int_mv *this_mv, PREDICTION_MODE this_mode, + int ref_idx, int ref_mv_idx, + int skip_repeated_ref_mv, + const MV_REFERENCE_FRAME *ref_frame, + const MB_MODE_INFO_EXT *mbmi_ext) { + const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx); assert(is_inter_singleref_mode(single_mode)); if (single_mode == NEWMV) { this_mv->as_int = INVALID_MV; } else if (single_mode == GLOBALMV) { + if (skip_repeated_ref_mv && + check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, single_mode)) + return 0; *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]]; } else { assert(single_mode == NEARMV || single_mode == NEARESTMV); @@ -10089,26 +1725,38 @@ static INLINE void get_this_mv(int_mv *this_mv, PREDICTION_MODE this_mode, mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_offset].comp_mv; } } else { + if (skip_repeated_ref_mv && + check_repeat_ref_mv(mbmi_ext, ref_idx, ref_frame, single_mode)) + return 0; *this_mv = mbmi_ext->global_mvs[ref_frame[ref_idx]]; } } + return 1; } // This function update the non-new mv for the current prediction mode static INLINE int build_cur_mv(int_mv *cur_mv, PREDICTION_MODE this_mode, - const AV1_COMMON *cm, const MACROBLOCK *x) { + const AV1_COMMON *cm, const MACROBLOCK *x, + int skip_repeated_ref_mv) { const MACROBLOCKD *xd = &x->e_mbd; const MB_MODE_INFO *mbmi = xd->mi[0]; const int is_comp_pred = has_second_ref(mbmi); + int ret = 1; for (int i = 0; i < is_comp_pred + 1; ++i) { int_mv this_mv; - get_this_mv(&this_mv, this_mode, i, mbmi->ref_mv_idx, mbmi->ref_frame, - x->mbmi_ext); - const PREDICTION_MODE single_mode = - get_single_mode(this_mode, i, is_comp_pred); + this_mv.as_int = INVALID_MV; + ret = get_this_mv(&this_mv, this_mode, i, mbmi->ref_mv_idx, + skip_repeated_ref_mv, mbmi->ref_frame, x->mbmi_ext); + if (!ret) return 0; + const PREDICTION_MODE single_mode = get_single_mode(this_mode, i); if (single_mode == NEWMV) { - cur_mv[i] = this_mv; + const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); + cur_mv[i] = + (i == 0) ? x->mbmi_ext->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx] + .this_mv + : x->mbmi_ext->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx] + .comp_mv; } else { ret &= clamp_and_check_mv(cur_mv + i, this_mv, cm, x); } @@ -10145,354 +1793,11 @@ static INLINE int get_drl_cost(const MB_MODE_INFO *mbmi, return cost; } -// Calculates the cost for compound type mask -static INLINE void calc_masked_type_cost(MACROBLOCK *x, BLOCK_SIZE bsize, - int comp_group_idx_ctx, - int comp_index_ctx, - int masked_compound_used, - int *masked_type_cost) { - av1_zero_array(masked_type_cost, COMPOUND_TYPES); - // Account for group index cost when wedge and/or diffwtd prediction are - // enabled - if (masked_compound_used) { - // Compound group index of average and distwtd is 0 - // Compound group index of wedge and diffwtd is 1 - masked_type_cost[COMPOUND_AVERAGE] += - x->comp_group_idx_cost[comp_group_idx_ctx][0]; - masked_type_cost[COMPOUND_DISTWTD] += masked_type_cost[COMPOUND_AVERAGE]; - masked_type_cost[COMPOUND_WEDGE] += - x->comp_group_idx_cost[comp_group_idx_ctx][1]; - masked_type_cost[COMPOUND_DIFFWTD] += masked_type_cost[COMPOUND_WEDGE]; - } - - // Compute the cost to signal compound index/type - masked_type_cost[COMPOUND_AVERAGE] += x->comp_idx_cost[comp_index_ctx][1]; - masked_type_cost[COMPOUND_DISTWTD] += x->comp_idx_cost[comp_index_ctx][0]; - masked_type_cost[COMPOUND_WEDGE] += x->compound_type_cost[bsize][0]; - masked_type_cost[COMPOUND_DIFFWTD] += x->compound_type_cost[bsize][1]; -} - -// Updates mbmi structure with the relevant compound type info -static INLINE void update_mbmi_for_compound_type(MB_MODE_INFO *mbmi, - COMPOUND_TYPE cur_type) { - mbmi->interinter_comp.type = cur_type; - mbmi->comp_group_idx = (cur_type >= COMPOUND_WEDGE); - mbmi->compound_idx = (cur_type != COMPOUND_DISTWTD); -} - -// Updates rd cost and relevant compound type data for the best compound type -static INLINE void update_best_info(const MB_MODE_INFO *const mbmi, int64_t *rd, - BEST_COMP_TYPE_STATS *best_type_stats, - int64_t best_rd_cur, - int64_t comp_model_rd_cur, int rs2) { - *rd = best_rd_cur; - best_type_stats->comp_best_model_rd = comp_model_rd_cur; - best_type_stats->best_compound_data = mbmi->interinter_comp; - best_type_stats->best_compmode_interinter_cost = rs2; -} - -// Updates best_mv for masked compound types -static INLINE void update_mask_best_mv(const MB_MODE_INFO *const mbmi, - int_mv *best_mv, int_mv *cur_mv, - const COMPOUND_TYPE cur_type, - int *best_tmp_rate_mv, int tmp_rate_mv, - const SPEED_FEATURES *const sf) { - if (cur_type == COMPOUND_WEDGE || - (sf->enable_interinter_diffwtd_newmv_search && - cur_type == COMPOUND_DIFFWTD)) { - *best_tmp_rate_mv = tmp_rate_mv; - best_mv[0].as_int = mbmi->mv[0].as_int; - best_mv[1].as_int = mbmi->mv[1].as_int; - } else { - best_mv[0].as_int = cur_mv[0].as_int; - best_mv[1].as_int = cur_mv[1].as_int; - } -} - -// Computes the valid compound_types to be evaluated -static INLINE int compute_valid_comp_types( - MACROBLOCK *x, const AV1_COMP *const cpi, int *try_average_and_distwtd_comp, - int32_t *comp_rate, BLOCK_SIZE bsize, int masked_compound_used, - int mode_search_mask, COMPOUND_TYPE *valid_comp_types) { - const AV1_COMMON *cm = &cpi->common; - int valid_type_count = 0; - int comp_type, valid_check; - int8_t enable_masked_type[MASKED_COMPOUND_TYPES] = { 0, 0 }; - - 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); - *try_average_and_distwtd_comp = try_average_comp && try_distwtd_comp && - comp_rate[COMPOUND_AVERAGE] == INT_MAX && - comp_rate[COMPOUND_DISTWTD] == INT_MAX; - - // Check if COMPOUND_AVERAGE and COMPOUND_DISTWTD are valid cases - for (comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; - comp_type++) { - valid_check = - (comp_type == COMPOUND_AVERAGE) ? try_average_comp : try_distwtd_comp; - if (!*try_average_and_distwtd_comp && valid_check && - is_interinter_compound_used(comp_type, bsize)) - valid_comp_types[valid_type_count++] = comp_type; - } - // Check if COMPOUND_WEDGE and COMPOUND_DIFFWTD are valid cases - if (masked_compound_used) { - // enable_masked_type[0] corresponds to COMPOUND_WEDGE - // enable_masked_type[1] corresponds to COMPOUND_DIFFWTD - enable_masked_type[0] = enable_wedge_interinter_search(x, cpi); - enable_masked_type[1] = cpi->oxcf.enable_diff_wtd_comp; - for (comp_type = COMPOUND_WEDGE; comp_type <= COMPOUND_DIFFWTD; - comp_type++) { - if ((mode_search_mask & (1 << comp_type)) && - is_interinter_compound_used(comp_type, bsize) && - enable_masked_type[comp_type - COMPOUND_WEDGE]) - valid_comp_types[valid_type_count++] = comp_type; - } - } - return valid_type_count; -} - -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, - const CompoundTypeRdBuffers *buffers, int *rate_mv, int64_t *rd, - RD_STATS *rd_stats, int64_t ref_best_rd, int *is_luma_interp_done, - int64_t rd_thresh) { - const AV1_COMMON *cm = &cpi->common; - MACROBLOCKD *xd = &x->e_mbd; - MB_MODE_INFO *mbmi = xd->mi[0]; - const PREDICTION_MODE this_mode = mbmi->mode; - const int bw = block_size_wide[bsize]; - int rs2; - int_mv best_mv[2]; - int best_tmp_rate_mv = *rate_mv; - BEST_COMP_TYPE_STATS best_type_stats; - // Initializing BEST_COMP_TYPE_STATS - best_type_stats.best_compound_data.type = COMPOUND_AVERAGE; - best_type_stats.best_compmode_interinter_cost = 0; - best_type_stats.comp_best_model_rd = INT64_MAX; - - uint8_t *preds0[1] = { buffers->pred0 }; - uint8_t *preds1[1] = { buffers->pred1 }; - int strides[1] = { bw }; - int tmp_rate_mv; - const int num_pix = 1 << num_pels_log2_lookup[bsize]; - const int mask_len = 2 * num_pix * sizeof(uint8_t); - COMPOUND_TYPE cur_type; - // Local array to store the mask cost for different compound types - int masked_type_cost[COMPOUND_TYPES]; - - int calc_pred_masked_compound = 1; - 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; - - // Local array to store the valid compound types to be evaluated in the core - // loop - COMPOUND_TYPE valid_comp_types[COMPOUND_TYPES] = { - COMPOUND_AVERAGE, COMPOUND_DISTWTD, COMPOUND_WEDGE, COMPOUND_DIFFWTD - }; - int valid_type_count = 0; - int try_average_and_distwtd_comp = 0; - // compute_valid_comp_types() returns the number of valid compound types to be - // evaluated and populates the same in the local array valid_comp_types[]. - // It also sets the flag 'try_average_and_distwtd_comp' - valid_type_count = compute_valid_comp_types( - x, cpi, &try_average_and_distwtd_comp, comp_rate, bsize, - masked_compound_used, mode_search_mask, valid_comp_types); - - // The following context indices are independent of compound type - const int comp_group_idx_ctx = get_comp_group_idx_context(xd); - const int comp_index_ctx = get_comp_index_context(cm, xd); - - // Populates masked_type_cost local array for the 4 compound types - calc_masked_type_cost(x, bsize, comp_group_idx_ctx, comp_index_ctx, - masked_compound_used, masked_type_cost); - - int64_t comp_model_rd_cur = INT64_MAX; - int64_t best_rd_cur = 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. - if (try_average_and_distwtd_comp) { - int est_rate[2]; - int64_t est_dist[2], est_rd[2]; - COMPOUND_TYPE best_type; - - // Calculate model_rd for COMPOUND_AVERAGE and COMPOUND_DISTWTD - for (int comp_type = COMPOUND_AVERAGE; comp_type <= COMPOUND_DISTWTD; - comp_type++) { - update_mbmi_for_compound_type(mbmi, comp_type); - 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[comp_type], - &est_dist[comp_type], NULL, NULL, NULL, NULL, NULL); - est_rate[comp_type] += masked_type_cost[comp_type]; - est_rd[comp_type] = RDCOST(x->rdmult, est_rate[comp_type] + *rate_mv, - est_dist[comp_type]); - if (comp_type == COMPOUND_AVERAGE) { - *is_luma_interp_done = 1; - restore_dst_buf(xd, *tmp_dst, 1); - } - } - // Choose the better of the two based on modeled cost and call - // estimate_yrd_for_sb() for that one. - best_type = (est_rd[COMPOUND_AVERAGE] <= est_rd[COMPOUND_DISTWTD]) - ? COMPOUND_AVERAGE - : COMPOUND_DISTWTD; - update_mbmi_for_compound_type(mbmi, best_type); - if (best_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *orig_dst, 1); - rs2 = masked_type_cost[best_type]; - RD_STATS est_rd_stats; - const int64_t mode_rd = RDCOST(x->rdmult, rs2 + *rate_mv, 0); - const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh) - mode_rd; - const int64_t est_rd_ = - estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &est_rd_stats); - - 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 - backup_stats(best_type, comp_rate, comp_dist, comp_model_rd, - &est_rd_stats, est_rd[best_type]); - comp_model_rd_cur = est_rd[best_type]; - } - if (best_type == COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); - // Update stats for best compound type - if (best_rd_cur < *rd) { - update_best_info(mbmi, rd, &best_type_stats, best_rd_cur, - comp_model_rd_cur, rs2); - } - } - - // If COMPOUND_AVERAGE is not valid, use the spare buffer - if (valid_comp_types[0] != COMPOUND_AVERAGE) restore_dst_buf(xd, *tmp_dst, 1); - - // Loop over valid compound types - for (int i = 0; i < valid_type_count; i++) { - cur_type = valid_comp_types[i]; - comp_model_rd_cur = INT64_MAX; - tmp_rate_mv = *rate_mv; - best_rd_cur = INT64_MAX; - - // Case COMPOUND_AVERAGE and COMPOUND_DISTWTD - if (cur_type < COMPOUND_WEDGE) { - update_mbmi_for_compound_type(mbmi, cur_type); - rs2 = masked_type_cost[cur_type]; - 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; - - // Compute RD cost for the current type - RD_STATS est_rd_stats; - const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh) - mode_rd; - const int64_t est_rd = - estimate_yrd_for_sb(cpi, bsize, x, tmp_rd_thresh, &est_rd_stats); - 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); - - // Backup rate and distortion for future reuse - backup_stats(cur_type, comp_rate, comp_dist, comp_model_rd, - &est_rd_stats, 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 { - // Handle masked compound types - update_mbmi_for_compound_type(mbmi, cur_type); - rs2 = masked_type_cost[cur_type]; - // Evaluate COMPOUND_WEDGE / COMPOUND_DIFFWTD if approximated cost is - // within threshold - int64_t approx_rd = ((*rd / cpi->max_comp_type_rd_threshold_div) * - cpi->max_comp_type_rd_threshold_mul); - - if (approx_rd < ref_best_rd) { - const int64_t tmp_rd_thresh = AOMMIN(*rd, rd_thresh); - best_rd_cur = masked_compound_type_rd( - 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, tmp_rd_thresh, - &calc_pred_masked_compound, comp_rate, comp_dist, comp_model_rd, - best_type_stats.comp_best_model_rd, &comp_model_rd_cur); - } - } - // Update stats for best compound type - if (best_rd_cur < *rd) { - update_best_info(mbmi, rd, &best_type_stats, best_rd_cur, - comp_model_rd_cur, rs2); - if (masked_compound_used && cur_type >= COMPOUND_WEDGE) { - memcpy(buffers->tmp_best_mask_buf, xd->seg_mask, mask_len); - if (have_newmv_in_inter_mode(this_mode)) - update_mask_best_mv(mbmi, best_mv, cur_mv, cur_type, - &best_tmp_rate_mv, tmp_rate_mv, &cpi->sf); - } - } - // reset to original mvs for next iteration - mbmi->mv[0].as_int = cur_mv[0].as_int; - mbmi->mv[1].as_int = cur_mv[1].as_int; - } - if (mbmi->interinter_comp.type != best_type_stats.best_compound_data.type) { - mbmi->comp_group_idx = - (best_type_stats.best_compound_data.type < COMPOUND_WEDGE) ? 0 : 1; - mbmi->compound_idx = - !(best_type_stats.best_compound_data.type == COMPOUND_DISTWTD); - mbmi->interinter_comp = best_type_stats.best_compound_data; - memcpy(xd->seg_mask, buffers->tmp_best_mask_buf, mask_len); - } - if (have_newmv_in_inter_mode(this_mode)) { - mbmi->mv[0].as_int = best_mv[0].as_int; - mbmi->mv[1].as_int = best_mv[1].as_int; - if (mbmi->interinter_comp.type == COMPOUND_WEDGE) { - rd_stats->rate += best_tmp_rate_mv - *rate_mv; - *rate_mv = best_tmp_rate_mv; - } - } - restore_dst_buf(xd, *orig_dst, 1); - if (!match_found) - save_comp_rd_search_stat(x, mbmi, comp_rate, comp_dist, comp_model_rd, - cur_mv); - return best_type_stats.best_compmode_interinter_cost; -} - static INLINE int is_single_newmv_valid(const HandleInterModeArgs *const args, const MB_MODE_INFO *const mbmi, PREDICTION_MODE this_mode) { for (int ref_idx = 0; ref_idx < 2; ++ref_idx) { - const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx, 1); + const PREDICTION_MODE single_mode = get_single_mode(this_mode, ref_idx); const MV_REFERENCE_FRAME ref = mbmi->ref_frame[ref_idx]; if (single_mode == NEWMV && args->single_newmv_valid[mbmi->ref_mv_idx][ref] == 0) { @@ -10529,7 +1834,7 @@ static bool ref_mv_idx_early_breakout(const AV1_COMP *const cpi, MACROBLOCK *x, const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; const int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); const int is_comp_pred = has_second_ref(mbmi); - if (sf->reduce_inter_modes && ref_mv_idx > 0) { + if (sf->inter_sf.reduce_inter_modes && ref_mv_idx > 0) { if (mbmi->ref_frame[0] == LAST2_FRAME || mbmi->ref_frame[0] == LAST3_FRAME || mbmi->ref_frame[1] == LAST2_FRAME || @@ -10541,7 +1846,7 @@ static bool ref_mv_idx_early_breakout(const AV1_COMP *const cpi, MACROBLOCK *x, } } // TODO(any): Experiment with reduce_inter_modes for compound prediction - if (sf->reduce_inter_modes >= 2 && !is_comp_pred && + if (sf->inter_sf.reduce_inter_modes >= 2 && !is_comp_pred && have_newmv_in_inter_mode(mbmi->mode)) { if (mbmi->ref_frame[0] != cpi->nearest_past_ref && mbmi->ref_frame[0] != cpi->nearest_future_ref) { @@ -10553,7 +1858,7 @@ static bool ref_mv_idx_early_breakout(const AV1_COMP *const cpi, MACROBLOCK *x, } } } - if (sf->prune_single_motion_modes_by_simple_trans && !is_comp_pred && + if (sf->inter_sf.prune_single_motion_modes_by_simple_trans && !is_comp_pred && args->single_ref_first_pass == 0) { if (args->simple_rd_state[ref_mv_idx].early_skipped) { return true; @@ -10574,18 +1879,11 @@ static bool ref_mv_idx_early_breakout(const AV1_COMP *const cpi, MACROBLOCK *x, return false; } -typedef struct { - int64_t rd; - int drl_cost; - int rate_mv; - int_mv mv; -} inter_mode_info; - // Compute the estimated RD cost for the motion vector with simple translation. static int64_t simple_translation_pred_rd( AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, HandleInterModeArgs *args, int ref_mv_idx, inter_mode_info *mode_info, - int64_t ref_best_rd, BLOCK_SIZE bsize, int mi_row, int mi_col) { + int64_t ref_best_rd, BLOCK_SIZE bsize) { MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = xd->mi[0]; MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; @@ -10620,7 +1918,7 @@ static int64_t simple_translation_pred_rd( mode_info[ref_mv_idx].drl_cost = drl_cost; int_mv cur_mv[2]; - if (!build_cur_mv(cur_mv, mbmi->mode, cm, x)) { + if (!build_cur_mv(cur_mv, mbmi->mode, cm, x, 0)) { return INT64_MAX; } assert(have_nearmv_in_inter_mode(mbmi->mode)); @@ -10642,15 +1940,16 @@ static int64_t simple_translation_pred_rd( mbmi->comp_group_idx = 0; mbmi->compound_idx = 1; } - set_default_interp_filters(mbmi, cm->interp_filter); + set_default_interp_filters(mbmi, cm->features.interp_filter); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst, bsize, AOM_PLANE_Y, AOM_PLANE_Y); int est_rate; int64_t est_dist; - model_rd_sb_fn[MODELRD_CURVFIT](cpi, bsize, x, xd, 0, 0, mi_row, mi_col, - &est_rate, &est_dist, NULL, NULL, NULL, NULL, - NULL); + model_rd_sb_fn[MODELRD_CURVFIT](cpi, bsize, x, xd, 0, 0, &est_rate, &est_dist, + NULL, NULL, NULL, NULL, NULL); return RDCOST(x->rdmult, rd_stats->rate + est_rate, est_dist); } @@ -10671,8 +1970,7 @@ static int ref_mv_idx_to_search(AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, HandleInterModeArgs *const args, int64_t ref_best_rd, inter_mode_info *mode_info, - BLOCK_SIZE bsize, int mi_row, int mi_col, - const int ref_set) { + BLOCK_SIZE bsize, const int ref_set) { AV1_COMMON *const cm = &cpi->common; const MACROBLOCKD *const xd = &x->e_mbd; const MB_MODE_INFO *const mbmi = xd->mi[0]; @@ -10690,7 +1988,8 @@ static int ref_mv_idx_to_search(AV1_COMP *const cpi, MACROBLOCK *x, // Only prune in NEARMV mode, if the speed feature is set, and the block size // is large enough. If these conditions are not met, return all good indices // found so far. - if (!cpi->sf.prune_mode_search_simple_translation) return good_indices; + if (!cpi->sf.inter_sf.prune_mode_search_simple_translation) + return good_indices; if (!have_nearmv_in_inter_mode(this_mode)) return good_indices; if (num_pels_log2_lookup[bsize] <= 6) return good_indices; // Do not prune when there is internal resizing. TODO(elliottk) fix this @@ -10709,8 +2008,7 @@ static int ref_mv_idx_to_search(AV1_COMP *const cpi, MACROBLOCK *x, continue; } idx_rdcost[ref_mv_idx] = simple_translation_pred_rd( - cpi, x, rd_stats, args, ref_mv_idx, mode_info, ref_best_rd, bsize, - mi_row, mi_col); + cpi, x, rd_stats, args, ref_mv_idx, mode_info, ref_best_rd, bsize); } // Find the index with the best RD cost. int best_idx = 0; @@ -10735,13 +2033,200 @@ static int ref_mv_idx_to_search(AV1_COMP *const cpi, MACROBLOCK *x, return result; } +typedef struct motion_mode_candidate { + MB_MODE_INFO mbmi; + int rate_mv; + int rate2_nocoeff; + int skip_motion_mode; + int64_t rd_cost; +} motion_mode_candidate; + +typedef struct motion_mode_best_st_candidate { + motion_mode_candidate motion_mode_cand[MAX_WINNER_MOTION_MODES]; + int num_motion_mode_cand; +} motion_mode_best_st_candidate; + +// Checks if the current reference frame matches with neighbouring block's +// (top/left) reference frames +static AOM_INLINE int ref_match_found_in_nb_blocks(MB_MODE_INFO *cur_mbmi, + MB_MODE_INFO *nb_mbmi) { + MV_REFERENCE_FRAME nb_ref_frames[2] = { nb_mbmi->ref_frame[0], + nb_mbmi->ref_frame[1] }; + MV_REFERENCE_FRAME cur_ref_frames[2] = { cur_mbmi->ref_frame[0], + cur_mbmi->ref_frame[1] }; + const int is_cur_comp_pred = has_second_ref(cur_mbmi); + int match_found = 0; + + for (int i = 0; i < (is_cur_comp_pred + 1); i++) { + if ((cur_ref_frames[i] == nb_ref_frames[0]) || + (cur_ref_frames[i] == nb_ref_frames[1])) + match_found = 1; + } + return match_found; +} + +static AOM_INLINE int find_ref_match_in_above_nbs(const int total_mi_cols, + MACROBLOCKD *xd) { + if (!xd->up_available) return 0; + const int mi_col = xd->mi_col; + MB_MODE_INFO **cur_mbmi = xd->mi; + // prev_row_mi points into the mi array, starting at the beginning of the + // previous row. + MB_MODE_INFO **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride; + const int end_col = AOMMIN(mi_col + xd->width, total_mi_cols); + uint8_t mi_step; + for (int above_mi_col = mi_col; above_mi_col < end_col; + above_mi_col += mi_step) { + MB_MODE_INFO **above_mi = prev_row_mi + above_mi_col; + mi_step = mi_size_wide[above_mi[0]->sb_type]; + int match_found = 0; + if (is_inter_block(*above_mi)) + match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *above_mi); + if (match_found) return 1; + } + return 0; +} + +static AOM_INLINE int find_ref_match_in_left_nbs(const int total_mi_rows, + MACROBLOCKD *xd) { + if (!xd->left_available) return 0; + const int mi_row = xd->mi_row; + MB_MODE_INFO **cur_mbmi = xd->mi; + // prev_col_mi points into the mi array, starting at the top of the + // previous column + MB_MODE_INFO **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride; + const int end_row = AOMMIN(mi_row + xd->height, total_mi_rows); + uint8_t mi_step; + for (int left_mi_row = mi_row; left_mi_row < end_row; + left_mi_row += mi_step) { + MB_MODE_INFO **left_mi = prev_col_mi + left_mi_row * xd->mi_stride; + mi_step = mi_size_high[left_mi[0]->sb_type]; + int match_found = 0; + if (is_inter_block(*left_mi)) + match_found = ref_match_found_in_nb_blocks(*cur_mbmi, *left_mi); + if (match_found) return 1; + } + return 0; +} + +typedef struct { + int64_t best_inter_cost; + int64_t ref_inter_cost[INTER_REFS_PER_FRAME]; +} PruneInfoFromTpl; + +#if !CONFIG_REALTIME_ONLY +// TODO(Remya): Check if get_tpl_stats_b() can be reused +static AOM_INLINE void get_block_level_tpl_stats( + AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, int *valid_refs, + PruneInfoFromTpl *inter_cost_info_from_tpl) { + const GF_GROUP *const gf_group = &cpi->gf_group; + AV1_COMMON *const cm = &cpi->common; + + assert(IMPLIES(gf_group->size > 0, gf_group->index < gf_group->size)); + const int tpl_idx = gf_group->index; + TplParams *const tpl_data = &cpi->tpl_data; + const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx]; + if (tpl_idx >= MAX_LAG_BUFFERS || !tpl_frame->is_valid) { + return; + } + + const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; + const int mi_wide = mi_size_wide[bsize]; + const int mi_high = mi_size_high[bsize]; + const int tpl_stride = tpl_frame->stride; + const int step = 1 << tpl_data->tpl_stats_block_mis_log2; + const int mi_col_sr = + coded_to_superres_mi(mi_col, cm->superres_scale_denominator); + const int mi_col_end_sr = + coded_to_superres_mi(mi_col + mi_wide, cm->superres_scale_denominator); + const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); + + for (int row = mi_row; row < AOMMIN(mi_row + mi_high, cm->mi_params.mi_rows); + row += step) { + for (int col = mi_col_sr; col < AOMMIN(mi_col_end_sr, mi_cols_sr); + col += step) { + const TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos( + row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)]; + + // Sums up the inter cost of corresponding ref frames + for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) { + inter_cost_info_from_tpl->ref_inter_cost[ref_idx] += + this_stats->pred_error[ref_idx]; + } + } + } + + // Computes the best inter cost (minimum inter_cost) + int64_t best_inter_cost = INT64_MAX; + for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ref_idx++) { + const int64_t cur_inter_cost = + inter_cost_info_from_tpl->ref_inter_cost[ref_idx]; + // For invalid ref frames, cur_inter_cost = 0 and has to be handled while + // calculating the minimum inter_cost + if (cur_inter_cost != 0 && (cur_inter_cost < best_inter_cost) && + valid_refs[ref_idx]) + best_inter_cost = cur_inter_cost; + } + inter_cost_info_from_tpl->best_inter_cost = best_inter_cost; +} +#endif + +static AOM_INLINE int prune_modes_based_on_tpl_stats( + PruneInfoFromTpl *inter_cost_info_from_tpl, const int *refs, int ref_mv_idx, + const PREDICTION_MODE this_mode, int prune_mode_level) { + const int have_newmv = have_newmv_in_inter_mode(this_mode); + if ((prune_mode_level < 3) && have_newmv) return 0; + + static const int prune_level_idx[3] = { 0, 1, 1 }; + const int prune_level = prune_level_idx[prune_mode_level - 1]; + int64_t cur_inter_cost; + + const int is_globalmv = + (this_mode == GLOBALMV) || (this_mode == GLOBAL_GLOBALMV); + const int prune_index = is_globalmv ? MAX_REF_MV_SEARCH : ref_mv_idx; + + // Thresholds used for pruning: + // Lower value indicates aggressive pruning and higher value indicates + // conservative pruning which is set based on ref_mv_idx and speed feature. + // 'prune_index' 0, 1, 2 corresponds to ref_mv indices 0, 1 and 2. prune_index + // 3 corresponds to GLOBALMV/GLOBAL_GLOBALMV + static const int tpl_inter_mode_prune_mul_factor[2][MAX_REF_MV_SEARCH + 1] = { + { 3, 3, 3, 2 }, { 3, 2, 2, 2 } + }; + + const int is_comp_pred = (refs[1] > INTRA_FRAME); + if (!is_comp_pred) { + cur_inter_cost = inter_cost_info_from_tpl->ref_inter_cost[refs[0] - 1]; + } else { + const int64_t inter_cost_ref0 = + inter_cost_info_from_tpl->ref_inter_cost[refs[0] - 1]; + const int64_t inter_cost_ref1 = + inter_cost_info_from_tpl->ref_inter_cost[refs[1] - 1]; + // Choose maximum inter_cost among inter_cost_ref0 and inter_cost_ref1 for + // more aggressive pruning + cur_inter_cost = AOMMAX(inter_cost_ref0, inter_cost_ref1); + } + + // Prune the mode if cur_inter_cost is greater than threshold times + // best_inter_cost + const int64_t best_inter_cost = inter_cost_info_from_tpl->best_inter_cost; + if (cur_inter_cost > + ((tpl_inter_mode_prune_mul_factor[prune_level][prune_index] * + best_inter_cost) >> + 1)) + return 1; + return 0; +} + static int64_t handle_inter_mode( 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, + RD_STATS *rd_stats_uv, int *disable_skip, HandleInterModeArgs *args, + int64_t ref_best_rd, uint8_t *const tmp_buf, const CompoundTypeRdBuffers *rd_buffers, int64_t *best_est_rd, - const int do_tx_search, InterModesInfo *inter_modes_info) { + const int do_tx_search, InterModesInfo *inter_modes_info, + motion_mode_candidate *motion_mode_cand, int64_t *skip_rd, + PruneInfoFromTpl *inter_cost_info_from_tpl) { const AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm); MACROBLOCKD *xd = &x->e_mbd; @@ -10749,9 +2234,16 @@ static int64_t handle_inter_mode( MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; const int is_comp_pred = has_second_ref(mbmi); const PREDICTION_MODE this_mode = mbmi->mode; + + const GF_GROUP *const gf_group = &cpi->gf_group; + const int tpl_idx = gf_group->index; + TplDepFrame *tpl_frame = &cpi->tpl_data.tpl_frame[tpl_idx]; + const int prune_modes_based_on_tpl = + cpi->sf.inter_sf.prune_inter_modes_based_on_tpl && + tpl_idx >= MAX_LAG_BUFFERS && tpl_frame->is_valid; int i; - int refs[2] = { mbmi->ref_frame[0], - (mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1]) }; + const int refs[2] = { mbmi->ref_frame[0], + (mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1]) }; int rate_mv = 0; int64_t rd = INT64_MAX; // do first prediction into the destination buffer. Do the next @@ -10768,7 +2260,6 @@ static int64_t handle_inter_mode( tmp_buf + 2 * MAX_SB_SQUARE }, { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE } }; - int16_t mode_ctx; const int masked_compound_used = is_any_masked_compound_used(bsize) && cm->seq_params.enable_masked_compound; int64_t ret_val = INT64_MAX; @@ -10786,19 +2277,46 @@ static int64_t handle_inter_mode( int mode_search_mask = (1 << COMPOUND_AVERAGE) | (1 << COMPOUND_DISTWTD) | (1 << COMPOUND_WEDGE) | (1 << COMPOUND_DIFFWTD); + // Do not prune the mode based on inter cost from tpl if the current ref frame + // is the winner ref in neighbouring blocks. + int ref_match_found_in_above_nb = 0; + int ref_match_found_in_left_nb = 0; + if (prune_modes_based_on_tpl) { + ref_match_found_in_above_nb = + find_ref_match_in_above_nbs(cm->mi_params.mi_cols, xd); + ref_match_found_in_left_nb = + find_ref_match_in_left_nbs(cm->mi_params.mi_rows, xd); + } + // First, perform a simple translation search for each of the indices. If // an index performs well, it will be fully searched here. const int ref_set = get_drl_refmv_count(x, mbmi->ref_frame, this_mode); - int idx_mask = - ref_mv_idx_to_search(cpi, x, rd_stats, args, ref_best_rd, mode_info, - bsize, mi_row, mi_col, ref_set); + // Save MV results from first 2 ref_mv_idx. + int_mv save_mv[MAX_REF_MV_SEARCH - 1][2] = { { { 0 } } }; + int best_ref_mv_idx = -1; + const int idx_mask = ref_mv_idx_to_search(cpi, x, rd_stats, args, ref_best_rd, + mode_info, bsize, ref_set); + const int16_t mode_ctx = + av1_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame); + const int ref_mv_cost = cost_mv_ref(x, this_mode, mode_ctx); + const int base_rate = + args->ref_frame_cost + args->single_comp_cost + ref_mv_cost; for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ++ref_mv_idx) { + mode_info[ref_mv_idx].full_search_mv.as_int = INVALID_MV; mode_info[ref_mv_idx].mv.as_int = INVALID_MV; mode_info[ref_mv_idx].rd = INT64_MAX; + if (!mask_check_bit(idx_mask, ref_mv_idx)) { // MV did not perform well in simple translation search. Skip it. continue; } + if (prune_modes_based_on_tpl && !ref_match_found_in_above_nb && + !ref_match_found_in_left_nb && (ref_best_rd != INT64_MAX)) { + if (prune_modes_based_on_tpl_stats( + inter_cost_info_from_tpl, refs, ref_mv_idx, this_mode, + cpi->sf.inter_sf.prune_inter_modes_based_on_tpl)) + continue; + } av1_init_rd_stats(rd_stats); mbmi->interinter_comp.type = COMPOUND_AVERAGE; @@ -10806,14 +2324,11 @@ static int64_t handle_inter_mode( mbmi->compound_idx = 1; if (mbmi->ref_frame[1] == INTRA_FRAME) mbmi->ref_frame[1] = NONE_FRAME; - mode_ctx = - av1_mode_context_analyzer(mbmi_ext->mode_context, mbmi->ref_frame); - mbmi->num_proj_ref = 0; mbmi->motion_mode = SIMPLE_TRANSLATION; mbmi->ref_mv_idx = ref_mv_idx; - rd_stats->rate += args->ref_frame_cost + args->single_comp_cost; + rd_stats->rate = base_rate; const int drl_cost = get_drl_cost(mbmi, mbmi_ext, x->drl_mode_cost0, ref_frame_type); rd_stats->rate += drl_cost; @@ -10823,14 +2338,19 @@ static int64_t handle_inter_mode( int compmode_interinter_cost = 0; int_mv cur_mv[2]; - if (!build_cur_mv(cur_mv, this_mode, cm, x)) { + + // TODO(Cherma): Extend this speed feature to support compound mode + int skip_repeated_ref_mv = + is_comp_pred ? 0 : cpi->sf.inter_sf.skip_repeated_ref_mv; + if (!build_cur_mv(cur_mv, this_mode, cm, x, skip_repeated_ref_mv)) { continue; } + if (have_newmv_in_inter_mode(this_mode)) { #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, handle_newmv_time); #endif - if (cpi->sf.prune_single_motion_modes_by_simple_trans && + if (cpi->sf.inter_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; @@ -10838,19 +2358,17 @@ static int64_t handle_inter_mode( rate_mv = args->single_newmv_rate[ref_mv_idx][ref0]; } else { newmv_ret_val = - handle_newmv(cpi, x, bsize, cur_mv, mi_row, mi_col, &rate_mv, args); + handle_newmv(cpi, x, bsize, cur_mv, &rate_mv, args, mode_info); } #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, handle_newmv_time); #endif - if (newmv_ret_val != 0) { - continue; - } else { - rd_stats->rate += rate_mv; - } + if (newmv_ret_val != 0) continue; - if (cpi->sf.skip_repeated_newmv) { + rd_stats->rate += rate_mv; + + if (cpi->sf.inter_sf.skip_repeated_newmv) { if (!is_comp_pred && this_mode == NEWMV && ref_mv_idx > 0) { int skip = 0; int this_rate_mv = 0; @@ -10874,20 +2392,23 @@ static int64_t handle_inter_mode( x->mv_cost_stack, MV_COST_WEIGHT); const int this_cost = this_rate_mv + drl_cost; - if (compare_cost < this_cost) { + if (compare_cost <= this_cost) { skip = 1; break; } else { // If the cost is less than current best result, make this - // the best and update corresponding variables - if (best_mbmi.ref_mv_idx == i) { + // the best and update corresponding variables unless the + // best_mv is the same as ref_mv. In this case we skip and + // rely on NEAR(EST)MV instead + if (best_mbmi.ref_mv_idx == i && + mode_info[i].mv.as_int != ref_mv.as_int) { assert(best_rd != INT64_MAX); best_mbmi.ref_mv_idx = ref_mv_idx; + motion_mode_cand->rate_mv = this_rate_mv; best_rd_stats.rate += this_cost - compare_cost; best_rd = RDCOST(x->rdmult, best_rd_stats.rate, best_rd_stats.dist); if (best_rd < ref_best_rd) ref_best_rd = best_rd; - skip = 1; break; } } @@ -10895,6 +2416,14 @@ static int64_t handle_inter_mode( } } if (skip) { + const THR_MODES mode_enum = get_prediction_mode_idx( + best_mbmi.mode, best_mbmi.ref_frame[0], best_mbmi.ref_frame[1]); + // Collect mode stats for multiwinner mode processing + store_winner_mode_stats( + &cpi->common, x, &best_mbmi, &best_rd_stats, &best_rd_stats_y, + &best_rd_stats_uv, mode_enum, NULL, bsize, best_rd, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + do_tx_search); args->modelled_rd[this_mode][ref_mv_idx][refs[0]] = args->modelled_rd[this_mode][i][refs[0]]; args->simple_rd[this_mode][ref_mv_idx][refs[0]] = @@ -10912,25 +2441,54 @@ static int64_t handle_inter_mode( for (i = 0; i < is_comp_pred + 1; ++i) { mbmi->mv[i].as_int = cur_mv[i].as_int; } - const int ref_mv_cost = cost_mv_ref(x, this_mode, mode_ctx); - rd_stats->rate += ref_mv_cost; if (RDCOST(x->rdmult, rd_stats->rate, 0) > ref_best_rd && mbmi->mode != NEARESTMV && mbmi->mode != NEAREST_NEARESTMV) { continue; } + if (cpi->sf.inter_sf.prune_ref_mv_idx_search && is_comp_pred) { + // TODO(yunqing): Move this part to a separate function when it is done. + // Store MV result. + if (ref_mv_idx < MAX_REF_MV_SEARCH - 1) { + for (i = 0; i < is_comp_pred + 1; ++i) + save_mv[ref_mv_idx][i].as_int = mbmi->mv[i].as_int; + } + // Skip the evaluation if an MV match is found. + if (ref_mv_idx > 0) { + int match = 0; + for (int idx = 0; idx < ref_mv_idx; ++idx) { + int mv_diff = 0; + for (i = 0; i < 1 + is_comp_pred; ++i) { + mv_diff += abs(save_mv[idx][i].as_mv.row - mbmi->mv[i].as_mv.row) + + abs(save_mv[idx][i].as_mv.col - mbmi->mv[i].as_mv.col); + } + + // If this mode is not the best one, and current MV is similar to + // previous stored MV, terminate this ref_mv_idx evaluation. + if (best_ref_mv_idx == -1 && mv_diff < 1) { + match = 1; + break; + } + } + if (match == 1) continue; + } + } + #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, compound_type_rd_time); #endif int skip_build_pred = 0; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; if (is_comp_pred) { // 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); - const InterpFilter assign_filter = cm->interp_filter; + const int need_search = av1_is_interp_needed(xd); + const InterpFilter assign_filter = cm->features.interp_filter; int is_luma_interp_done = 0; - find_interp_filter_match(x, cpi, assign_filter, need_search); + av1_find_interp_filter_match(mbmi, cpi, assign_filter, need_search, + args->interp_filter_stats, + args->interp_filter_stats_idx); int64_t best_rd_compound; int64_t rd_thresh; @@ -10938,11 +2496,10 @@ static int64_t handle_inter_mode( const int comp_type_rd_scale = COMP_TYPE_RD_THRESH_SCALE; rd_thresh = get_rd_thresh_from_best_rd( ref_best_rd, (1 << comp_type_rd_shift), comp_type_rd_scale); - compmode_interinter_cost = compound_type_rd( - cpi, x, bsize, mi_col, mi_row, cur_mv, mode_search_mask, - masked_compound_used, &orig_dst, &tmp_dst, rd_buffers, &rate_mv, - &best_rd_compound, rd_stats, ref_best_rd, &is_luma_interp_done, - rd_thresh); + compmode_interinter_cost = av1_compound_type_rd( + cpi, x, bsize, cur_mv, mode_search_mask, masked_compound_used, + &orig_dst, &tmp_dst, rd_buffers, &rate_mv, &best_rd_compound, + rd_stats, ref_best_rd, skip_rd[1], &is_luma_interp_done, rd_thresh); if (ref_best_rd < INT64_MAX && (best_rd_compound >> comp_type_rd_shift) * comp_type_rd_scale > ref_best_rd) { @@ -10951,7 +2508,7 @@ static int64_t handle_inter_mode( } // 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 + // candidate in av1_compound_type_rd, and the following // compound types searching uses tmp_dst buffer if (mbmi->interinter_comp.type == COMPOUND_AVERAGE && @@ -10971,9 +2528,9 @@ static int64_t handle_inter_mode( #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_build_pred, args, ref_best_rd); + ret_val = av1_interpolation_filter_search( + x, cpi, tile_data, bsize, &tmp_dst, &orig_dst, &rd, &rs, + &skip_build_pred, args, ref_best_rd); #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, interpolation_filter_search_time); #endif @@ -10983,16 +2540,12 @@ static int64_t handle_inter_mode( if (ret_val != 0) { restore_dst_buf(xd, orig_dst, num_planes); continue; - } else if (cpi->sf.model_based_post_interp_filter_breakout && + } else if (cpi->sf.inter_sf.model_based_post_interp_filter_breakout && ref_best_rd != INT64_MAX && (rd >> 3) * 3 > ref_best_rd) { restore_dst_buf(xd, orig_dst, num_planes); continue; } - if (!is_comp_pred) - args->single_filter[this_mode][refs[0]] = - mbmi->interp_filters.as_filters.y_filter; - if (args->modelled_rd != NULL) { if (is_comp_pred) { const int mode0 = compound_ref0_mode(this_mode); @@ -11015,10 +2568,11 @@ static int64_t handle_inter_mode( #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, motion_mode_rd_time); #endif + int rate2_nocoeff = rd_stats->rate; 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); + rd_stats_uv, disable_skip, args, ref_best_rd, + skip_rd, &rate_mv, &orig_dst, best_est_rd, + do_tx_search, inter_modes_info, 0); #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, motion_mode_rd_time); #endif @@ -11028,6 +2582,13 @@ static int64_t handle_inter_mode( if (ret_val != INT64_MAX) { int64_t tmp_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); mode_info[ref_mv_idx].rd = tmp_rd; + const THR_MODES mode_enum = get_prediction_mode_idx( + mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); + // Collect mode stats for multiwinner mode processing + store_winner_mode_stats( + &cpi->common, x, mbmi, rd_stats, rd_stats_y, rd_stats_uv, mode_enum, + NULL, bsize, tmp_rd, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, do_tx_search); if (tmp_rd < best_rd) { best_rd_stats = *rd_stats; best_rd_stats_y = *rd_stats_y; @@ -11035,14 +2596,18 @@ static int64_t handle_inter_mode( best_rd = tmp_rd; best_mbmi = *mbmi; best_disable_skip = *disable_skip; - best_xskip = x->skip; + best_xskip = x->force_skip; memcpy(best_blk_skip, x->blk_skip, - sizeof(best_blk_skip[0]) * xd->n4_h * xd->n4_w); - av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->n4_h * xd->n4_w); + sizeof(best_blk_skip[0]) * xd->height * xd->width); + av1_copy_array(best_tx_type_map, xd->tx_type_map, + xd->height * xd->width); + motion_mode_cand->rate_mv = rate_mv; + motion_mode_cand->rate2_nocoeff = rate2_nocoeff; } if (tmp_rd < ref_best_rd) { ref_best_rd = tmp_rd; + best_ref_mv_idx = ref_mv_idx; } } restore_dst_buf(xd, orig_dst, num_planes); @@ -11056,12 +2621,12 @@ static int64_t handle_inter_mode( *rd_stats_uv = best_rd_stats_uv; *mbmi = best_mbmi; *disable_skip = best_disable_skip; - x->skip = best_xskip; + x->force_skip = best_xskip; assert(IMPLIES(mbmi->comp_group_idx == 1, mbmi->interinter_comp.type != COMPOUND_AVERAGE)); memcpy(x->blk_skip, best_blk_skip, - sizeof(best_blk_skip[0]) * xd->n4_h * xd->n4_w); - av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->n4_h * xd->n4_w); + sizeof(best_blk_skip[0]) * xd->height * xd->width); + av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width); rd_stats->rdcost = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); @@ -11079,8 +2644,8 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *const xd = &x->e_mbd; const TileInfo *tile = &xd->tile; MB_MODE_INFO *mbmi = xd->mi[0]; - const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE); - const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; const int sb_row = mi_row >> cm->seq_params.mib_size_log2; @@ -11090,7 +2655,7 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, MV_REFERENCE_FRAME ref_frame = INTRA_FRAME; av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs, - mi_row, mi_col, mbmi_ext->mode_context); + mbmi_ext->mode_context); // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs. av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame); @@ -11106,16 +2671,16 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, } int_mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv; - if (dv_ref.as_int == 0) - av1_find_ref_dv(&dv_ref, tile, cm->seq_params.mib_size, mi_row, mi_col); + if (dv_ref.as_int == 0) { + av1_find_ref_dv(&dv_ref, tile, cm->seq_params.mib_size, mi_row); + } // Ref DV should not have sub-pel. assert((dv_ref.as_mv.col & 7) == 0); assert((dv_ref.as_mv.row & 7) == 0); mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref; struct buf_2d yv12_mb[MAX_MB_PLANE]; - av1_setup_pred_block(xd, yv12_mb, xd->cur_buf, mi_row, mi_col, NULL, NULL, - num_planes); + av1_setup_pred_block(xd, yv12_mb, xd->cur_buf, NULL, NULL, num_planes); for (int i = 0; i < num_planes; ++i) { xd->plane[i].pre[0] = yv12_mb[i]; } @@ -11128,65 +2693,77 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, MB_MODE_INFO best_mbmi = *mbmi; RD_STATS best_rdstats = *rd_stats; - int best_skip = x->skip; - uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE] = { 0 }; uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + FULLPEL_MOTION_SEARCH_PARAMS fullms_params; + const search_site_config *lookahead_search_sites = + &cpi->mv_search_params.ss_cfg[SS_CFG_LOOKAHEAD]; + av1_make_default_fullpel_ms_params(&fullms_params, cpi, x, bsize, + &dv_ref.as_mv, lookahead_search_sites); + fullms_params.is_intra_mode = 1; + for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE; dir < IBC_MOTION_DIRECTIONS; ++dir) { - const MvLimits tmp_mv_limits = x->mv_limits; switch (dir) { case IBC_MOTION_ABOVE: - x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE; - x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w; - x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE; - x->mv_limits.row_max = + fullms_params.mv_limits.col_min = + (tile->mi_col_start - mi_col) * MI_SIZE; + fullms_params.mv_limits.col_max = + (tile->mi_col_end - mi_col) * MI_SIZE - w; + fullms_params.mv_limits.row_min = + (tile->mi_row_start - mi_row) * MI_SIZE; + fullms_params.mv_limits.row_max = (sb_row * cm->seq_params.mib_size - mi_row) * MI_SIZE - h; break; case IBC_MOTION_LEFT: - x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE; - x->mv_limits.col_max = + fullms_params.mv_limits.col_min = + (tile->mi_col_start - mi_col) * MI_SIZE; + fullms_params.mv_limits.col_max = (sb_col * cm->seq_params.mib_size - mi_col) * MI_SIZE - w; // TODO(aconverse@google.com): Minimize the overlap between above and // left areas. - x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE; + fullms_params.mv_limits.row_min = + (tile->mi_row_start - mi_row) * MI_SIZE; int bottom_coded_mi_edge = AOMMIN((sb_row + 1) * cm->seq_params.mib_size, tile->mi_row_end); - x->mv_limits.row_max = (bottom_coded_mi_edge - mi_row) * MI_SIZE - h; + fullms_params.mv_limits.row_max = + (bottom_coded_mi_edge - mi_row) * MI_SIZE - h; break; default: assert(0); } - assert(x->mv_limits.col_min >= tmp_mv_limits.col_min); - assert(x->mv_limits.col_max <= tmp_mv_limits.col_max); - assert(x->mv_limits.row_min >= tmp_mv_limits.row_min); - assert(x->mv_limits.row_max <= tmp_mv_limits.row_max); - av1_set_mv_search_range(&x->mv_limits, &dv_ref.as_mv); + assert(fullms_params.mv_limits.col_min >= fullms_params.mv_limits.col_min); + assert(fullms_params.mv_limits.col_max <= fullms_params.mv_limits.col_max); + assert(fullms_params.mv_limits.row_min >= fullms_params.mv_limits.row_min); + assert(fullms_params.mv_limits.row_max <= fullms_params.mv_limits.row_max); - if (x->mv_limits.col_max < x->mv_limits.col_min || - x->mv_limits.row_max < x->mv_limits.row_min) { - x->mv_limits = tmp_mv_limits; + av1_set_mv_search_range(&fullms_params.mv_limits, &dv_ref.as_mv); + + if (fullms_params.mv_limits.col_max < fullms_params.mv_limits.col_min || + fullms_params.mv_limits.row_max < fullms_params.mv_limits.row_min) { continue; } - int step_param = cpi->mv_step_param; - MV mvp_full = dv_ref.as_mv; - mvp_full.col >>= 3; - mvp_full.row >>= 3; - const int sadpb = x->sadperbit16; - int cost_list[5]; - 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, - &cpi->ss_cfg[SS_CFG_LOOKAHEAD], 1); + const int step_param = cpi->mv_search_params.mv_step_param; + const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv); + IntraBCHashInfo *intrabc_hash_info = &x->intrabc_hash_info; + int_mv best_mv, best_hash_mv; + + int bestsme = av1_full_pixel_search(start_mv, &fullms_params, step_param, + NULL, &best_mv.as_fullmv, NULL); + const int hashsme = av1_intrabc_hash_search( + cpi, xd, &fullms_params, intrabc_hash_info, &best_hash_mv.as_fullmv); + if (hashsme < bestsme) { + best_mv = best_hash_mv; + bestsme = hashsme; + } - x->mv_limits = tmp_mv_limits; if (bestsme == INT_MAX) continue; - mvp_full = x->best_mv.as_mv; - const MV dv = { .row = mvp_full.row * 8, .col = mvp_full.col * 8 }; - if (mv_check_bounds(&x->mv_limits, &dv)) continue; + const MV dv = get_mv_from_fullmv(&best_mv.as_fullmv); + if (!av1_is_fullmv_in_range(&fullms_params.mv_limits, + get_fullmv_from_mv(&dv))) + continue; if (!av1_is_dv_valid(dv, cm, xd, mi_row, mi_col, bsize, cm->seq_params.mib_size_log2)) continue; @@ -11203,38 +2780,36 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, mbmi->mv[0].as_mv = dv; mbmi->interp_filters = av1_broadcast_interp_filter(BILINEAR); mbmi->skip = 0; - x->skip = 0; av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize, 0, av1_num_planes(cm) - 1); - int *dvcost[2] = { (int *)&cpi->dv_cost[0][MV_MAX], - (int *)&cpi->dv_cost[1][MV_MAX] }; + const IntraBCMVCosts *const dv_costs = &cpi->dv_costs; + int *dvcost[2] = { (int *)&dv_costs->mv_component[0][MV_MAX], + (int *)&dv_costs->mv_component[1][MV_MAX] }; // TODO(aconverse@google.com): The full motion field defining discount // in MV_COST_WEIGHT is too large. Explore other values. - const int rate_mv = av1_mv_bit_cost(&dv, &dv_ref.as_mv, cpi->dv_joint_cost, + const int rate_mv = av1_mv_bit_cost(&dv, &dv_ref.as_mv, dv_costs->joint_mv, dvcost, MV_COST_WEIGHT_SUB); const int rate_mode = x->intrabc_cost[1]; RD_STATS rd_stats_yuv, rd_stats_y, rd_stats_uv; - if (!txfm_search(cpi, NULL, x, bsize, mi_row, mi_col, &rd_stats_yuv, - &rd_stats_y, &rd_stats_uv, rate_mode + rate_mv, INT64_MAX)) + if (!av1_txfm_search(cpi, x, bsize, &rd_stats_yuv, &rd_stats_y, + &rd_stats_uv, rate_mode + rate_mv, INT64_MAX)) continue; rd_stats_yuv.rdcost = RDCOST(x->rdmult, rd_stats_yuv.rate, rd_stats_yuv.dist); if (rd_stats_yuv.rdcost < best_rd) { best_rd = rd_stats_yuv.rdcost; best_mbmi = *mbmi; - best_skip = mbmi->skip; best_rdstats = rd_stats_yuv; memcpy(best_blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); - av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->n4_h * xd->n4_w); + sizeof(x->blk_skip[0]) * xd->height * xd->width); + av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->height * xd->width); } } *mbmi = best_mbmi; *rd_stats = best_rdstats; - x->skip = best_skip; memcpy(x->blk_skip, best_blk_skip, - sizeof(x->blk_skip[0]) * xd->n4_h * xd->n4_w); + sizeof(x->blk_skip[0]) * xd->height * xd->width); av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); #if CONFIG_RD_DEBUG mbmi->rd_stats = *rd_stats; @@ -11242,8 +2817,8 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, return best_rd; } -void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, - int mi_col, RD_STATS *rd_cost, BLOCK_SIZE bsize, +void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd) { const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; @@ -11252,7 +2827,6 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int rate_y = 0, rate_uv = 0, rate_y_tokenonly = 0, rate_uv_tokenonly = 0; int y_skip = 0, uv_skip = 0; int64_t dist_y = 0, dist_uv = 0; - TX_SIZE max_uv_tx_size; ctx->rd_stats.skip = 0; mbmi->ref_frame[0] = INTRA_FRAME; @@ -11262,8 +2836,8 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, mbmi->skip_mode = 0; const int64_t intra_yrd = - rd_pick_intra_sby_mode(cpi, x, mi_row, mi_col, &rate_y, &rate_y_tokenonly, - &dist_y, &y_skip, bsize, best_rd, ctx); + av1_rd_pick_intra_sby_mode(cpi, x, &rate_y, &rate_y_tokenonly, &dist_y, + &y_skip, bsize, best_rd, ctx); // Initialize default mode evaluation params set_mode_eval_params(cpi, x, DEFAULT_EVAL); @@ -11271,27 +2845,24 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, if (intra_yrd < best_rd) { // Only store reconstructed luma when there's chroma RDO. When there's no // chroma RDO, the reconstructed luma will be stored in encode_superblock(). - xd->cfl.is_chroma_reference = - is_chroma_reference(mi_row, mi_col, bsize, cm->seq_params.subsampling_x, - cm->seq_params.subsampling_y); xd->cfl.store_y = store_cfl_required_rdo(cm, x); if (xd->cfl.store_y) { // Restore reconstructed luma values. memcpy(x->blk_skip, ctx->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); av1_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk); - av1_encode_intra_block_plane(cpi, x, bsize, AOM_PLANE_Y, - cpi->optimize_seg_arr[mbmi->segment_id], - mi_row, mi_col); + av1_encode_intra_block_plane(cpi, x, bsize, AOM_PLANE_Y, DRY_RUN_NORMAL, + cpi->optimize_seg_arr[mbmi->segment_id]); av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); xd->cfl.store_y = 0; } if (num_planes > 1) { - max_uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); init_sbuv_mode(mbmi); - if (!x->skip_chroma_rd) - rd_pick_intra_sbuv_mode(cpi, x, &rate_uv, &rate_uv_tokenonly, &dist_uv, - &uv_skip, bsize, max_uv_tx_size); + if (xd->is_chroma_ref) { + const TX_SIZE max_uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); + av1_rd_pick_intra_sbuv_mode(cpi, x, &rate_uv, &rate_uv_tokenonly, + &dist_uv, &uv_skip, bsize, max_uv_tx_size); + } } // Intra block is always coded as non-skip @@ -11307,7 +2878,7 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, if (rd_cost->rate != INT_MAX && rd_cost->rdcost < best_rd) best_rd = rd_cost->rdcost; if (rd_pick_intrabc_mode_sb(cpi, x, ctx, rd_cost, bsize, best_rd) < best_rd) { - ctx->rd_stats.skip = x->skip; + ctx->rd_stats.skip = mbmi->skip; memcpy(ctx->blk_skip, x->blk_skip, sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); assert(rd_cost->rate != INT_MAX); @@ -11315,62 +2886,20 @@ void av1_rd_pick_intra_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, if (rd_cost->rate == INT_MAX) return; ctx->mic = *xd->mi[0]; - ctx->mbmi_ext = *x->mbmi_ext; + av1_copy_mbmi_ext_to_mbmi_ext_frame(&ctx->mbmi_ext_best, x->mbmi_ext, + av1_ref_frame_type(xd->mi[0]->ref_frame)); av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); } -static AOM_INLINE void restore_uv_color_map(const AV1_COMP *const cpi, - MACROBLOCK *x) { - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; - const BLOCK_SIZE bsize = mbmi->sb_type; - int src_stride = x->plane[1].src.stride; - const uint8_t *const src_u = x->plane[1].src.buf; - const uint8_t *const src_v = x->plane[2].src.buf; - int *const data = x->palette_buffer->kmeans_data_buf; - int centroids[2 * PALETTE_MAX_SIZE]; - uint8_t *const color_map = xd->plane[1].color_index_map; - int r, c; - const uint16_t *const src_u16 = CONVERT_TO_SHORTPTR(src_u); - const uint16_t *const src_v16 = CONVERT_TO_SHORTPTR(src_v); - int plane_block_width, plane_block_height, rows, cols; - av1_get_block_dimensions(bsize, 1, xd, &plane_block_width, - &plane_block_height, &rows, &cols); - - for (r = 0; r < rows; ++r) { - for (c = 0; c < cols; ++c) { - if (cpi->common.seq_params.use_highbitdepth) { - data[(r * cols + c) * 2] = src_u16[r * src_stride + c]; - data[(r * cols + c) * 2 + 1] = src_v16[r * src_stride + c]; - } else { - data[(r * cols + c) * 2] = src_u[r * src_stride + c]; - data[(r * cols + c) * 2 + 1] = src_v[r * src_stride + c]; - } - } - } - - for (r = 1; r < 3; ++r) { - for (c = 0; c < pmi->palette_size[1]; ++c) { - centroids[c * 2 + r - 1] = pmi->palette_colors[r * PALETTE_MAX_SIZE + c]; - } - } - - av1_calc_indices(data, centroids, color_map, rows * cols, - pmi->palette_size[1], 2); - extend_palette_color_map(color_map, cols, rows, plane_block_width, - plane_block_height); -} - static AOM_INLINE void calc_target_weighted_pred( const AV1_COMMON *cm, const MACROBLOCK *x, const MACROBLOCKD *xd, - int mi_row, int mi_col, const uint8_t *above, int above_stride, - const uint8_t *left, int left_stride); + const uint8_t *above, int above_stride, const uint8_t *left, + int left_stride); static AOM_INLINE void rd_pick_skip_mode( RD_STATS *rd_cost, InterModeSearchState *search_state, const AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize, - int mi_row, int mi_col, struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) { + struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]) { const AV1_COMMON *const cm = &cpi->common; const SkipModeInfo *const skip_mode_info = &cm->current_frame.skip_mode_info; const int num_planes = av1_num_planes(cm); @@ -11398,7 +2927,9 @@ static AOM_INLINE void rd_pick_skip_mode( return; } - if (!cpi->oxcf.enable_onesided_comp && cpi->all_one_sided_refs) { + if ((!cpi->oxcf.enable_onesided_comp || + cpi->sf.inter_sf.disable_onesided_comp) && + cpi->all_one_sided_refs) { return; } @@ -11415,14 +2946,14 @@ static AOM_INLINE void rd_pick_skip_mode( MB_MODE_INFO_EXT *mbmi_ext = x->mbmi_ext; av1_find_mv_refs(cm, xd, mbmi, ref_frame_type, mbmi_ext->ref_mv_count, xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs, - mi_row, mi_col, mbmi_ext->mode_context); + mbmi_ext->mode_context); // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs. av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame_type); } assert(this_mode == NEAREST_NEARESTMV); - if (!build_cur_mv(mbmi->mv, this_mode, cm, x)) { + if (!build_cur_mv(mbmi->mv, this_mode, cm, x, 0)) { return; } @@ -11435,7 +2966,7 @@ static AOM_INLINE void rd_pick_skip_mode( mbmi->ref_mv_idx = 0; mbmi->skip_mode = mbmi->skip = 1; - set_default_interp_filters(mbmi, cm->interp_filter); + set_default_interp_filters(mbmi, cm->features.interp_filter); set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); for (int i = 0; i < num_planes; i++) { @@ -11450,7 +2981,7 @@ static AOM_INLINE void rd_pick_skip_mode( } // Obtain the rdcost for skip_mode. - skip_mode_rd(&skip_mode_rd_stats, cpi, x, bsize, mi_row, mi_col, &orig_dst); + skip_mode_rd(&skip_mode_rd_stats, cpi, x, bsize, &orig_dst); // Compare the use of skip_mode with the best intra/inter mode obtained. const int skip_mode_ctx = av1_get_skip_mode_context(xd); @@ -11480,12 +3011,13 @@ static AOM_INLINE void rd_pick_skip_mode( // Set up tx_size related variables for skip-specific loop filtering. search_state->best_mbmode.tx_size = - block_signals_txsize(bsize) ? tx_size_from_tx_mode(bsize, x->tx_mode) - : max_txsize_rect_lookup[bsize]; + block_signals_txsize(bsize) + ? tx_size_from_tx_mode(bsize, x->tx_mode_search_type) + : max_txsize_rect_lookup[bsize]; memset(search_state->best_mbmode.inter_tx_size, search_state->best_mbmode.tx_size, sizeof(search_state->best_mbmode.inter_tx_size)); - set_txfm_ctxs(search_state->best_mbmode.tx_size, xd->n4_w, xd->n4_h, + set_txfm_ctxs(search_state->best_mbmode.tx_size, xd->width, xd->height, search_state->best_mbmode.skip && is_inter_block(mbmi), xd); // Set up color-related variables for skip mode. @@ -11502,7 +3034,8 @@ static AOM_INLINE void rd_pick_skip_mode( (INTERINTRA_MODE)(II_DC_PRED - 1); search_state->best_mbmode.filter_intra_mode_info.use_filter_intra = 0; - set_default_interp_filters(&search_state->best_mbmode, cm->interp_filter); + set_default_interp_filters(&search_state->best_mbmode, + cm->features.interp_filter); search_state->best_mode_index = mode_index; @@ -11515,100 +3048,159 @@ static AOM_INLINE void rd_pick_skip_mode( search_state->best_skip2 = 1; search_state->best_mode_skippable = 1; - x->skip = 1; + x->force_skip = 1; } } +// Get winner mode stats of given mode index +static AOM_INLINE MB_MODE_INFO *get_winner_mode_stats( + MACROBLOCK *x, MB_MODE_INFO *best_mbmode, RD_STATS *best_rd_cost, + int best_rate_y, int best_rate_uv, THR_MODES *best_mode_index, + RD_STATS **winner_rd_cost, int *winner_rate_y, int *winner_rate_uv, + THR_MODES *winner_mode_index, int enable_multiwinner_mode_process, + int mode_idx) { + MB_MODE_INFO *winner_mbmi; + if (enable_multiwinner_mode_process) { + assert(mode_idx >= 0 && mode_idx < x->winner_mode_count); + WinnerModeStats *winner_mode_stat = &x->winner_mode_stats[mode_idx]; + winner_mbmi = &winner_mode_stat->mbmi; + + *winner_rd_cost = &winner_mode_stat->rd_cost; + *winner_rate_y = winner_mode_stat->rate_y; + *winner_rate_uv = winner_mode_stat->rate_uv; + *winner_mode_index = winner_mode_stat->mode_index; + } else { + winner_mbmi = best_mbmode; + *winner_rd_cost = best_rd_cost; + *winner_rate_y = best_rate_y; + *winner_rate_uv = best_rate_uv; + *winner_mode_index = *best_mode_index; + } + return winner_mbmi; +} + // speed feature: fast intra/inter transform type search // Used for speed >= 2 // When this speed feature is on, in rd mode search, only DCT is used. // After the mode is determined, this function is called, to select // transform types and get accurate rdcost. static AOM_INLINE void refine_winner_mode_tx( - const AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col, - RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, - THR_MODES best_mode_index, MB_MODE_INFO *best_mbmode, - struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE], int best_rate_y, - int best_rate_uv, int *best_skip2) { + const AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx, THR_MODES *best_mode_index, + MB_MODE_INFO *best_mbmode, struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE], + int best_rate_y, int best_rate_uv, int *best_skip2, int winner_mode_count) { const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; + int64_t best_rd; const int num_planes = av1_num_planes(cm); - if (xd->lossless[mbmi->segment_id] == 0 && best_mode_index != THR_INVALID && - is_winner_mode_processing_enabled(cpi, mbmi, best_mbmode->mode)) { - int skip_blk = 0; - RD_STATS rd_stats_y, rd_stats_uv; - const int skip_ctx = av1_get_skip_context(xd); + if (!is_winner_mode_processing_enabled(cpi, best_mbmode, best_mbmode->mode)) + return; - // Set params for winner mode evaluation - set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); + // Set params for winner mode evaluation + set_mode_eval_params(cpi, x, WINNER_MODE_EVAL); - *mbmi = *best_mbmode; + // No best mode identified so far + if (*best_mode_index == THR_INVALID) return; - set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + best_rd = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist); + for (int mode_idx = 0; mode_idx < winner_mode_count; mode_idx++) { + RD_STATS *winner_rd_stats = NULL; + int winner_rate_y = 0, winner_rate_uv = 0; + THR_MODES winner_mode_index = 0; - // Select prediction reference frames. - for (int i = 0; i < num_planes; i++) { - xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; - if (has_second_ref(mbmi)) - xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; - } + // TODO(any): Combine best mode and multi-winner mode processing paths + // Get winner mode stats for current mode index + MB_MODE_INFO *winner_mbmi = get_winner_mode_stats( + x, best_mbmode, rd_cost, best_rate_y, best_rate_uv, best_mode_index, + &winner_rd_stats, &winner_rate_y, &winner_rate_uv, &winner_mode_index, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, mode_idx); - if (is_inter_mode(mbmi->mode)) { - 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 (xd->lossless[winner_mbmi->segment_id] == 0 && + winner_mode_index != THR_INVALID && + is_winner_mode_processing_enabled(cpi, winner_mbmi, + winner_mbmi->mode)) { + RD_STATS rd_stats = *winner_rd_stats; + int skip_blk = 0; + RD_STATS rd_stats_y, rd_stats_uv; + const int skip_ctx = av1_get_skip_context(xd); - av1_subtract_plane(x, bsize, 0); - if (x->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id]) { - pick_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, mi_row, mi_col, - INT64_MAX); - assert(rd_stats_y.rate != INT_MAX); - } else { - super_block_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); - memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size)); - for (int i = 0; i < xd->n4_h * xd->n4_w; ++i) - set_blk_skip(x, 0, i, rd_stats_y.skip); + *mbmi = *winner_mbmi; + + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + + // Select prediction reference frames. + for (int i = 0; i < num_planes; i++) { + xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i]; + if (has_second_ref(mbmi)) + xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; } - } else { - super_block_yrd(cpi, x, &rd_stats_y, bsize, INT64_MAX); - } - if (num_planes > 1) { - super_block_uvrd(cpi, x, &rd_stats_uv, bsize, INT64_MAX); - } else { - av1_init_rd_stats(&rd_stats_uv); - } + if (is_inter_mode(mbmi->mode)) { + const int mi_row = xd->mi_row; + const int mi_col = xd->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); - if (RDCOST(x->rdmult, - x->skip_cost[skip_ctx][0] + rd_stats_y.rate + rd_stats_uv.rate, - (rd_stats_y.dist + rd_stats_uv.dist)) > - RDCOST(x->rdmult, x->skip_cost[skip_ctx][1], - (rd_stats_y.sse + rd_stats_uv.sse))) { - skip_blk = 1; - rd_stats_y.rate = x->skip_cost[skip_ctx][1]; - rd_stats_uv.rate = 0; - rd_stats_y.dist = rd_stats_y.sse; - rd_stats_uv.dist = rd_stats_uv.sse; - } else { - skip_blk = 0; - rd_stats_y.rate += x->skip_cost[skip_ctx][0]; - } + av1_subtract_plane(x, bsize, 0); + if (x->tx_mode_search_type == TX_MODE_SELECT && + !xd->lossless[mbmi->segment_id]) { + av1_pick_recursive_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, + INT64_MAX); + assert(rd_stats_y.rate != INT_MAX); + } else { + av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, + INT64_MAX); + memset(mbmi->inter_tx_size, mbmi->tx_size, + sizeof(mbmi->inter_tx_size)); + for (int i = 0; i < xd->height * xd->width; ++i) + set_blk_skip(x, 0, i, rd_stats_y.skip); + } + } else { + av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize, + INT64_MAX); + } - if (RDCOST(x->rdmult, best_rate_y + best_rate_uv, rd_cost->dist) > - RDCOST(x->rdmult, rd_stats_y.rate + rd_stats_uv.rate, - (rd_stats_y.dist + rd_stats_uv.dist))) { - best_mbmode->tx_size = mbmi->tx_size; - av1_copy(best_mbmode->inter_tx_size, mbmi->inter_tx_size); - av1_copy_array(ctx->blk_skip, x->blk_skip, ctx->num_4x4_blk); - av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - rd_cost->rate += - (rd_stats_y.rate + rd_stats_uv.rate - best_rate_y - best_rate_uv); - rd_cost->dist = rd_stats_y.dist + rd_stats_uv.dist; - rd_cost->rdcost = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist); - *best_skip2 = skip_blk; + if (num_planes > 1) { + av1_txfm_uvrd(cpi, x, &rd_stats_uv, bsize, INT64_MAX); + } else { + av1_init_rd_stats(&rd_stats_uv); + } + + if (is_inter_mode(mbmi->mode) && + RDCOST(x->rdmult, + x->skip_cost[skip_ctx][0] + rd_stats_y.rate + rd_stats_uv.rate, + (rd_stats_y.dist + rd_stats_uv.dist)) > + RDCOST(x->rdmult, x->skip_cost[skip_ctx][1], + (rd_stats_y.sse + rd_stats_uv.sse))) { + skip_blk = 1; + rd_stats_y.rate = x->skip_cost[skip_ctx][1]; + rd_stats_uv.rate = 0; + rd_stats_y.dist = rd_stats_y.sse; + rd_stats_uv.dist = rd_stats_uv.sse; + } else { + skip_blk = 0; + rd_stats_y.rate += x->skip_cost[skip_ctx][0]; + } + int this_rate = rd_stats.rate + rd_stats_y.rate + rd_stats_uv.rate - + winner_rate_y - winner_rate_uv; + int64_t this_rd = + RDCOST(x->rdmult, this_rate, (rd_stats_y.dist + rd_stats_uv.dist)); + if (best_rd > this_rd) { + *best_mbmode = *mbmi; + *best_mode_index = winner_mode_index; + av1_copy_array(ctx->blk_skip, x->blk_skip, ctx->num_4x4_blk); + av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + rd_cost->rate = this_rate; + rd_cost->dist = rd_stats_y.dist + rd_stats_uv.dist; + rd_cost->sse = rd_stats_y.sse + rd_stats_uv.sse; + rd_cost->rdcost = this_rd; + best_rd = this_rd; + *best_skip2 = skip_blk; + } } } } @@ -11713,7 +3305,7 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, const SPEED_FEATURES *const sf = &cpi->sf; REF_SET ref_set = REF_SET_FULL; - if (sf->use_real_time_ref_set) + if (sf->rt_sf.use_real_time_ref_set) ref_set = REF_SET_REALTIME; else if (cpi->oxcf.enable_reduced_reference_set) ref_set = REF_SET_REDUCED; @@ -11722,8 +3314,21 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, int min_pred_mv_sad = INT_MAX; MV_REFERENCE_FRAME ref_frame; - for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) - min_pred_mv_sad = AOMMIN(min_pred_mv_sad, x->pred_mv_sad[ref_frame]); + if (ref_set == REF_SET_REALTIME) { + // For real-time encoding, we only look at a subset of ref frames. So the + // threshold for pruning should be computed from this subset as well. + const int num_rt_refs = + sizeof(real_time_ref_combos) / sizeof(*real_time_ref_combos); + for (int r_idx = 0; r_idx < num_rt_refs; r_idx++) { + const MV_REFERENCE_FRAME ref = real_time_ref_combos[r_idx][0]; + if (ref != INTRA_FRAME) { + min_pred_mv_sad = AOMMIN(min_pred_mv_sad, x->pred_mv_sad[ref]); + } + } + } else { + for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) + 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 & av1_ref_frame_flag_list[ref_frame])) { @@ -11756,9 +3361,9 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, 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); - get_this_mv(&near_mv, NEARMV, 0, 0, tmp_ref_frames, x->mbmi_ext); - get_this_mv(&global_mv, GLOBALMV, 0, 0, tmp_ref_frames, x->mbmi_ext); + get_this_mv(&nearest_mv, NEARESTMV, 0, 0, 0, tmp_ref_frames, x->mbmi_ext); + get_this_mv(&near_mv, NEARMV, 0, 0, 0, tmp_ref_frames, x->mbmi_ext); + get_this_mv(&global_mv, GLOBALMV, 0, 0, 0, tmp_ref_frames, x->mbmi_ext); if (near_mv.as_int != global_mv.as_int) mask->pred_modes[ALTREF_FRAME] |= (1 << NEARMV); @@ -11768,7 +3373,7 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, } if (cpi->rc.is_src_frame_alt_ref) { - if (sf->alt_ref_search_fp) { + if (sf->inter_sf.alt_ref_search_fp) { 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); @@ -11776,7 +3381,7 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, } } - if (sf->alt_ref_search_fp) { + if (sf->inter_sf.alt_ref_search_fp) { if (!cm->show_frame && x->best_pred_mv_sad < INT_MAX) { int sad_thresh = x->best_pred_mv_sad + (x->best_pred_mv_sad >> 3); // Conservatively skip the modes w.r.t. BWDREF, ALTREF2 and ALTREF, if @@ -11789,40 +3394,26 @@ static AOM_INLINE void init_mode_skip_mask(mode_skip_mask_t *mask, } } - if (sf->adaptive_mode_search) { + if (sf->inter_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->pred_modes[GOLDEN_FRAME] |= INTER_ALL; } - if (bsize > sf->max_intra_bsize) { + if (bsize > sf->part_sf.max_intra_bsize) { disable_reference(INTRA_FRAME, mask->ref_combo); } mask->pred_modes[INTRA_FRAME] |= - ~(sf->intra_y_mode_mask[max_txsize_lookup[bsize]]); + ~(sf->intra_sf.intra_y_mode_mask[max_txsize_lookup[bsize]]); } -// Please add/modify parameter setting in this function, making it consistent -// and easy to read and maintain. -static AOM_INLINE void set_params_rd_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; - 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; - - for (int i = 0; i < MB_MODE_COUNT; ++i) - for (int k = 0; k < REF_FRAMES; ++k) args->single_filter[i][k] = SWITCHABLE; - +static AOM_INLINE void init_pred_buf(const MACROBLOCK *const x, + HandleInterModeArgs *const args) { + const MACROBLOCKD *const xd = &x->e_mbd; if (is_cur_buf_hbd(xd)) { - int len = sizeof(uint16_t); + const 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); @@ -11841,12 +3432,28 @@ static AOM_INLINE void set_params_rd_pick_inter_mode( 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; } +} +// Please add/modify parameter setting in this function, making it consistent +// and easy to read and maintain. +static AOM_INLINE void set_params_rd_pick_inter_mode( + const AV1_COMP *cpi, MACROBLOCK *x, HandleInterModeArgs *args, + BLOCK_SIZE bsize, mode_skip_mask_t *mode_skip_mask, int skip_ref_frame_mask, + unsigned int *ref_costs_single, unsigned int (*ref_costs_comp)[REF_FRAMES], + struct buf_2d (*yv12_mb)[MAX_MB_PLANE]) { + const AV1_COMMON *const cm = &cpi->common; + 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; + + init_pred_buf(x, args); av1_collect_neighbors_ref_counts(xd); - estimate_ref_frame_costs(cm, xd, x, segment_id, ref_costs_single, ref_costs_comp); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; MV_REFERENCE_FRAME ref_frame; x->best_pred_mv_sad = INT_MAX; for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { @@ -11871,18 +3478,17 @@ static AOM_INLINE void set_params_rd_pick_inter_mode( } } 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); + setup_buffer_ref_mvs_inter(cpi, x, ref_frame, bsize, yv12_mb); } // Store the best pred_mv_sad across all past frames - if (cpi->sf.alt_ref_search_fp && + if (cpi->sf.inter_sf.alt_ref_search_fp && cpi->ref_relative_dist[ref_frame - LAST_FRAME] < 0) x->best_pred_mv_sad = AOMMIN(x->best_pred_mv_sad, x->pred_mv_sad[ref_frame]); } // ref_frame = ALTREF_FRAME - if (!cpi->sf.use_real_time_ref_set) { // No second reference on RT ref set, - // so no need to initialize + if (!cpi->sf.rt_sf.use_real_time_ref_set) { + // No second reference on RT ref set, so no need to initialize for (; ref_frame < MODE_CTX_REF_FRAMES; ++ref_frame) { x->mbmi_ext->mode_context[ref_frame] = 0; mbmi_ext->ref_mv_count[ref_frame] = UINT8_MAX; @@ -11900,19 +3506,18 @@ static AOM_INLINE void set_params_rd_pick_inter_mode( } av1_find_mv_refs(cm, xd, mbmi, ref_frame, mbmi_ext->ref_mv_count, xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs, - mi_row, mi_col, mbmi_ext->mode_context); + mbmi_ext->mode_context); // TODO(Ravi): Populate mbmi_ext->ref_mv_stack[ref_frame][4] and // mbmi_ext->weight[ref_frame][4] inside av1_find_mv_refs. av1_copy_usable_ref_mv_stack_and_weight(xd, mbmi_ext, ref_frame); } } - av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); + av1_count_overlappable_neighbors(cm, xd); const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); - const int prune_obmc = - cpi->sf.prune_obmc_using_stats && - (cpi->obmc_probs[update_type][bsize] < cpi->obmc_probs_thresh); - if (cpi->oxcf.enable_obmc && !prune_obmc) { + const int prune_obmc = cpi->frame_probs.obmc_probs[update_type][bsize] < + cpi->sf.inter_sf.prune_obmc_prob_thresh; + if (cpi->oxcf.enable_obmc && !cpi->sf.inter_sf.disable_obmc && !prune_obmc) { if (check_num_overlappable_neighbors(mbmi) && is_motion_variation_allowed_bsize(bsize)) { int dst_width1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }; @@ -11921,19 +3526,18 @@ static AOM_INLINE void set_params_rd_pick_inter_mode( 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 }; - 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_build_prediction_by_above_preds(cm, xd, args->above_pred_buf, + dst_width1, dst_height1, + args->above_pred_stride); + av1_build_prediction_by_left_preds(cm, xd, args->left_pred_buf, + dst_width2, dst_height2, + args->left_pred_stride); const int num_planes = av1_num_planes(cm); 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]); + cm, x, xd, args->above_pred_buf[0], args->above_pred_stride[0], + args->left_pred_buf[0], args->left_pred_stride[0]); } } @@ -11942,111 +3546,29 @@ static AOM_INLINE void set_params_rd_pick_inter_mode( // Set params for mode evaluation set_mode_eval_params(cpi, x, MODE_EVAL); - if (cpi->sf.skip_repeat_interpolation_filter_search) { - x->interp_filter_stats_idx[0] = 0; - x->interp_filter_stats_idx[1] = 0; - } x->comp_rd_stats_idx = 0; } -static AOM_INLINE 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, - MB_MODE_INFO *const mbmi, PALETTE_MODE_INFO *const pmi, - unsigned int *ref_costs_single, InterModeSearchState *search_state) { - const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - MACROBLOCKD *const xd = &x->e_mbd; - int rate2 = 0; - int64_t distortion2 = 0, best_rd_palette = search_state->best_rd, this_rd, - best_model_rd_palette = INT64_MAX; - int skippable = 0, rate_overhead_palette = 0; - RD_STATS rd_stats_y; - TX_SIZE uv_tx = TX_4X4; - uint8_t *const best_palette_color_map = - x->palette_buffer->best_palette_color_map; - uint8_t *const color_map = xd->plane[0].color_index_map; - MB_MODE_INFO best_mbmi_palette = *mbmi; - uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; - uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - const int *const intra_mode_cost = x->mbmode_cost[size_group_lookup[bsize]]; - const int rows = block_size_high[bsize]; - const int cols = block_size_wide[bsize]; - - mbmi->mode = DC_PRED; - mbmi->uv_mode = UV_DC_PRED; - mbmi->ref_frame[0] = INTRA_FRAME; - mbmi->ref_frame[1] = NONE_FRAME; - rate_overhead_palette = rd_pick_palette_intra_sby( - cpi, x, bsize, mi_row, mi_col, intra_mode_cost[DC_PRED], - &best_mbmi_palette, best_palette_color_map, &best_rd_palette, - &best_model_rd_palette, NULL, NULL, NULL, NULL, NULL, ctx, best_blk_skip, - best_tx_type_map); - if (pmi->palette_size[0] == 0) return; - - memcpy(x->blk_skip, best_blk_skip, - sizeof(best_blk_skip[0]) * bsize_to_num_blk(bsize)); - av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); - memcpy(color_map, best_palette_color_map, - rows * cols * sizeof(best_palette_color_map[0])); - super_block_yrd(cpi, x, &rd_stats_y, bsize, search_state->best_rd); - if (rd_stats_y.rate == INT_MAX) return; - - skippable = rd_stats_y.skip; - distortion2 = rd_stats_y.dist; - rate2 = rd_stats_y.rate + rate_overhead_palette; - rate2 += ref_costs_single[INTRA_FRAME]; - if (num_planes > 1) { - uv_tx = av1_get_tx_size(AOM_PLANE_U, xd); - if (search_state->rate_uv_intra == INT_MAX) { - choose_intra_uv_mode(cpi, x, bsize, uv_tx, &search_state->rate_uv_intra, - &search_state->rate_uv_tokenonly, - &search_state->dist_uvs, &search_state->skip_uvs, - &search_state->mode_uv); - search_state->pmi_uv = *pmi; - search_state->uv_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; - } - mbmi->uv_mode = search_state->mode_uv; - pmi->palette_size[1] = search_state->pmi_uv.palette_size[1]; - if (pmi->palette_size[1] > 0) { - memcpy(pmi->palette_colors + PALETTE_MAX_SIZE, - search_state->pmi_uv.palette_colors + PALETTE_MAX_SIZE, - 2 * PALETTE_MAX_SIZE * sizeof(pmi->palette_colors[0])); - } - mbmi->angle_delta[PLANE_TYPE_UV] = search_state->uv_angle_delta; - skippable = skippable && search_state->skip_uvs; - distortion2 += search_state->dist_uvs; - rate2 += search_state->rate_uv_intra; - } - - if (skippable) { - rate2 -= rd_stats_y.rate; - if (num_planes > 1) rate2 -= search_state->rate_uv_tokenonly; - rate2 += x->skip_cost[av1_get_skip_context(xd)][1]; - } else { - rate2 += x->skip_cost[av1_get_skip_context(xd)][0]; - } - this_rd = RDCOST(x->rdmult, rate2, distortion2); - if (this_rd < search_state->best_rd) { - search_state->best_mode_index = THR_DC; - mbmi->mv[0].as_int = 0; - 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 = 0; - search_state->best_mode_skippable = skippable; - memcpy(ctx->blk_skip, x->blk_skip, - sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - } +static AOM_INLINE void init_intra_mode_search_state( + IntraModeSearchState *intra_search_state) { + intra_search_state->skip_intra_modes = 0; + intra_search_state->best_intra_mode = DC_PRED; + intra_search_state->angle_stats_ready = 0; + av1_zero(intra_search_state->directional_mode_skip_mask); + intra_search_state->rate_uv_intra = INT_MAX; + av1_zero(intra_search_state->pmi_uv); + for (int i = 0; i < REFERENCE_MODES; ++i) + intra_search_state->best_pred_rd[i] = INT64_MAX; } static AOM_INLINE void init_inter_mode_search_state( InterModeSearchState *search_state, const AV1_COMP *cpi, const MACROBLOCK *x, BLOCK_SIZE bsize, int64_t best_rd_so_far) { + init_intra_mode_search_state(&search_state->intra_search_state); + search_state->best_rd = best_rd_so_far; + search_state->best_skip_rd[0] = INT64_MAX; + search_state->best_skip_rd[1] = INT64_MAX; av1_zero(search_state->best_mbmode); @@ -12064,8 +3586,6 @@ static AOM_INLINE void init_inter_mode_search_state( const MB_MODE_INFO *const mbmi = xd->mi[0]; const unsigned char segment_id = mbmi->segment_id; - search_state->skip_intra_modes = 0; - search_state->num_available_refs = 0; memset(search_state->dist_refs, -1, sizeof(search_state->dist_refs)); memset(search_state->dist_order_refs, -1, @@ -12076,21 +3596,12 @@ static AOM_INLINE void init_inter_mode_search_state( const int *const rd_threshes = cpi->rd.threshes[segment_id][bsize]; for (int i = LAST_NEW_MV_INDEX + 1; i < MAX_MODES; ++i) search_state->mode_threshold[i] = - ((int64_t)rd_threshes[i] * x->thresh_freq_fact[bsize][i]) >> 5; + ((int64_t)rd_threshes[i] * x->thresh_freq_fact[bsize][i]) >> + RD_THRESH_FAC_FRAC_BITS; - search_state->best_intra_mode = DC_PRED; search_state->best_intra_rd = INT64_MAX; - search_state->angle_stats_ready = 0; - av1_zero(search_state->directional_mode_skip_mask); - search_state->best_pred_sse = UINT_MAX; - search_state->rate_uv_intra = INT_MAX; - - av1_zero(search_state->pmi_uv); - - for (int i = 0; i < REFERENCE_MODES; ++i) - search_state->best_pred_rd[i] = INT64_MAX; av1_zero(search_state->single_newmv); av1_zero(search_state->single_newmv_rate); @@ -12174,9 +3685,11 @@ static int inter_mode_compatible_skip(const AV1_COMP *cpi, const MACROBLOCK *x, } static int fetch_picked_ref_frames_mask(const MACROBLOCK *const x, - BLOCK_SIZE bsize, int mib_size, - int mi_row, int mi_col) { + BLOCK_SIZE bsize, int mib_size) { const int sb_size_mask = mib_size - 1; + const MACROBLOCKD *const xd = &x->e_mbd; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; 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]; @@ -12201,6 +3714,9 @@ static int inter_mode_search_order_independent_skip( return 1; } + const int ref_type = av1_ref_frame_type(ref_frame); + if ((cpi->prune_ref_frame_mask >> ref_type) & 1) return 1; + // This is only used in motion vector unit test. if (cpi->oxcf.motion_vector_unit_test && ref_frame[0] == INTRA_FRAME) return 1; @@ -12211,7 +3727,9 @@ static int inter_mode_search_order_independent_skip( } const int comp_pred = ref_frame[1] > INTRA_FRAME; - if (!cpi->oxcf.enable_onesided_comp && comp_pred && cpi->all_one_sided_refs) { + if ((!cpi->oxcf.enable_onesided_comp || + cpi->sf.inter_sf.disable_onesided_comp) && + comp_pred && cpi->all_one_sided_refs) { return 1; } @@ -12224,7 +3742,6 @@ static int inter_mode_search_order_independent_skip( int skip_motion_mode = 0; if (mbmi->partition != PARTITION_NONE && mbmi->partition != PARTITION_SPLIT) { - const int ref_type = av1_ref_frame_type(ref_frame); 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 @@ -12255,15 +3772,14 @@ static int inter_mode_search_order_independent_skip( // Threshold for intra skipping based on source variance // TODO(debargha): Specialize the threshold for super block sizes const unsigned int skip_intra_var_thresh = 64; - if ((sf->mode_search_skip_flags & FLAG_SKIP_INTRA_LOWVAR) && + if ((sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_LOWVAR) && x->source_variance < skip_intra_var_thresh) return 1; } } - if (prune_ref_by_selective_ref_frame(cpi, ref_frame, - cm->cur_frame->ref_display_order_hint, - cm->current_frame.display_order_hint)) + if (prune_ref_by_selective_ref_frame(cpi, x, ref_frame, + cm->cur_frame->ref_display_order_hint)) return 1; if (skip_motion_mode) return 2; @@ -12286,231 +3802,7 @@ static INLINE void init_mbmi(MB_MODE_INFO *mbmi, PREDICTION_MODE curr_mode, mbmi->mv[0].as_int = mbmi->mv[1].as_int = 0; mbmi->motion_mode = SIMPLE_TRANSLATION; mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1); - set_default_interp_filters(mbmi, cm->interp_filter); -} - -static int64_t handle_intra_mode(InterModeSearchState *search_state, - const AV1_COMP *cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int mi_row, int mi_col, - int ref_frame_cost, - const PICK_MODE_CONTEXT *ctx, int disable_skip, - RD_STATS *rd_stats, RD_STATS *rd_stats_y, - RD_STATS *rd_stats_uv) { - const AV1_COMMON *cm = &cpi->common; - const SPEED_FEATURES *const sf = &cpi->sf; - MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - assert(mbmi->ref_frame[0] == INTRA_FRAME); - const PREDICTION_MODE mode = mbmi->mode; - const int mode_cost = x->mbmode_cost[size_group_lookup[bsize]][mode]; - const int intra_cost_penalty = av1_get_intra_cost_penalty( - cm->base_qindex, cm->y_dc_delta_q, cm->seq_params.bit_depth); - const int skip_ctx = av1_get_skip_context(xd); - - int known_rate = mode_cost; - known_rate += ref_frame_cost; - if (mode != DC_PRED && mode != PAETH_PRED) known_rate += intra_cost_penalty; - known_rate += AOMMIN(x->skip_cost[skip_ctx][0], x->skip_cost[skip_ctx][1]); - const int64_t known_rd = RDCOST(x->rdmult, known_rate, 0); - if (known_rd > search_state->best_rd) { - search_state->skip_intra_modes = 1; - return INT64_MAX; - } - - const int is_directional_mode = av1_is_directional_mode(mode); - if (is_directional_mode && av1_use_angle_delta(bsize) && - cpi->oxcf.enable_angle_delta) { - if (sf->intra_angle_estimation && !search_state->angle_stats_ready) { - const int src_stride = x->plane[0].src.stride; - const uint8_t *src = x->plane[0].src.buf; - const int rows = block_size_high[bsize]; - const int cols = block_size_wide[bsize]; - angle_estimation(src, src_stride, rows, cols, bsize, is_cur_buf_hbd(xd), - search_state->directional_mode_skip_mask); - search_state->angle_stats_ready = 1; - } - if (search_state->directional_mode_skip_mask[mode]) return INT64_MAX; - av1_init_rd_stats(rd_stats_y); - rd_stats_y->rate = INT_MAX; - int64_t model_rd = INT64_MAX; - int rate_dummy; - rd_pick_intra_angle_sby(cpi, x, mi_row, mi_col, &rate_dummy, rd_stats_y, - bsize, mode_cost, search_state->best_rd, &model_rd, - 0); - - } else { - av1_init_rd_stats(rd_stats_y); - mbmi->angle_delta[PLANE_TYPE_Y] = 0; - super_block_yrd(cpi, x, rd_stats_y, bsize, search_state->best_rd); - } - - // Pick filter intra modes. - if (mode == DC_PRED && av1_filter_intra_allowed_bsize(cm, bsize)) { - int try_filter_intra = 0; - int64_t best_rd_so_far = INT64_MAX; - if (rd_stats_y->rate != INT_MAX) { - const int tmp_rate = - rd_stats_y->rate + x->filter_intra_cost[bsize][0] + mode_cost; - best_rd_so_far = RDCOST(x->rdmult, tmp_rate, rd_stats_y->dist); - try_filter_intra = (best_rd_so_far / 2) <= search_state->best_rd; - } else { - try_filter_intra = !search_state->best_mbmode.skip; - } - - if (try_filter_intra) { - RD_STATS rd_stats_y_fi; - int filter_intra_selected_flag = 0; - TX_SIZE best_tx_size = mbmi->tx_size; - FILTER_INTRA_MODE best_fi_mode = FILTER_DC_PRED; - uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; - memcpy(best_blk_skip, x->blk_skip, - sizeof(best_blk_skip[0]) * ctx->num_4x4_blk); - uint8_t best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; - av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - mbmi->filter_intra_mode_info.use_filter_intra = 1; - for (FILTER_INTRA_MODE fi_mode = FILTER_DC_PRED; - fi_mode < FILTER_INTRA_MODES; ++fi_mode) { - mbmi->filter_intra_mode_info.filter_intra_mode = fi_mode; - super_block_yrd(cpi, x, &rd_stats_y_fi, bsize, search_state->best_rd); - if (rd_stats_y_fi.rate == INT_MAX) continue; - const int this_rate_tmp = - rd_stats_y_fi.rate + - intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); - const int64_t this_rd_tmp = - RDCOST(x->rdmult, this_rate_tmp, rd_stats_y_fi.dist); - - if (this_rd_tmp != INT64_MAX && - this_rd_tmp / 2 > search_state->best_rd) { - break; - } - if (this_rd_tmp < best_rd_so_far) { - best_tx_size = mbmi->tx_size; - av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); - memcpy(best_blk_skip, x->blk_skip, - sizeof(best_blk_skip[0]) * ctx->num_4x4_blk); - best_fi_mode = fi_mode; - *rd_stats_y = rd_stats_y_fi; - filter_intra_selected_flag = 1; - best_rd_so_far = this_rd_tmp; - } - } - - mbmi->tx_size = best_tx_size; - av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk); - memcpy(x->blk_skip, best_blk_skip, - sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); - - if (filter_intra_selected_flag) { - mbmi->filter_intra_mode_info.use_filter_intra = 1; - mbmi->filter_intra_mode_info.filter_intra_mode = best_fi_mode; - } else { - mbmi->filter_intra_mode_info.use_filter_intra = 0; - } - } - } - - if (rd_stats_y->rate == INT_MAX) return INT64_MAX; - - const int mode_cost_y = - intra_mode_info_cost_y(cpi, x, mbmi, bsize, mode_cost); - av1_init_rd_stats(rd_stats); - av1_init_rd_stats(rd_stats_uv); - const int num_planes = av1_num_planes(cm); - if (num_planes > 1) { - 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 TX_SIZE uv_tx = av1_get_tx_size(AOM_PLANE_U, xd); - if (search_state->rate_uv_intra == INT_MAX) { - const int rate_y = - rd_stats_y->skip ? x->skip_cost[skip_ctx][1] : rd_stats_y->rate; - const int64_t rdy = - RDCOST(x->rdmult, rate_y + mode_cost_y, rd_stats_y->dist); - if (search_state->best_rd < (INT64_MAX / 2) && - rdy > (search_state->best_rd + (search_state->best_rd >> 2))) { - search_state->skip_intra_modes = 1; - return INT64_MAX; - } - choose_intra_uv_mode(cpi, x, bsize, uv_tx, &search_state->rate_uv_intra, - &search_state->rate_uv_tokenonly, - &search_state->dist_uvs, &search_state->skip_uvs, - &search_state->mode_uv); - if (try_palette) search_state->pmi_uv = *pmi; - search_state->uv_angle_delta = mbmi->angle_delta[PLANE_TYPE_UV]; - - const int uv_rate = search_state->rate_uv_tokenonly; - const int64_t uv_dist = search_state->dist_uvs; - const int64_t uv_rd = RDCOST(x->rdmult, uv_rate, uv_dist); - if (uv_rd > search_state->best_rd) { - search_state->skip_intra_modes = 1; - return INT64_MAX; - } - } - - rd_stats_uv->rate = search_state->rate_uv_tokenonly; - rd_stats_uv->dist = search_state->dist_uvs; - rd_stats_uv->skip = search_state->skip_uvs; - rd_stats->skip = rd_stats_y->skip && rd_stats_uv->skip; - mbmi->uv_mode = search_state->mode_uv; - if (try_palette) { - pmi->palette_size[1] = search_state->pmi_uv.palette_size[1]; - memcpy(pmi->palette_colors + PALETTE_MAX_SIZE, - search_state->pmi_uv.palette_colors + PALETTE_MAX_SIZE, - 2 * PALETTE_MAX_SIZE * sizeof(pmi->palette_colors[0])); - } - mbmi->angle_delta[PLANE_TYPE_UV] = search_state->uv_angle_delta; - } - - rd_stats->rate = rd_stats_y->rate + mode_cost_y; - if (!xd->lossless[mbmi->segment_id] && block_signals_txsize(bsize)) { - // super_block_yrd above includes the cost of the tx_size in the - // tokenonly rate, but for intra blocks, tx_size is always coded - // (prediction granularity), so we account for it in the full rate, - // not the tokenonly rate. - rd_stats_y->rate -= tx_size_cost(x, bsize, mbmi->tx_size); - } - if (num_planes > 1 && !x->skip_chroma_rd) { - const int uv_mode_cost = - x->intra_uv_mode_cost[is_cfl_allowed(xd)][mode][mbmi->uv_mode]; - rd_stats->rate += - rd_stats_uv->rate + - intra_mode_info_cost_uv(cpi, x, mbmi, bsize, uv_mode_cost); - } - if (mode != DC_PRED && mode != PAETH_PRED) { - rd_stats->rate += intra_cost_penalty; - } - - // Estimate the reference frame signaling cost and add it - // to the rolling cost variable. - rd_stats->rate += ref_frame_cost; - - // Intra block is always coded as non-skip - rd_stats->skip = 0; - rd_stats->dist = rd_stats_y->dist + rd_stats_uv->dist; - // Add in the cost of the no skip flag. - rd_stats->rate += x->skip_cost[skip_ctx][0]; - // Calculate the final RD estimate for this mode. - const int64_t this_rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); - // Keep record of best intra rd - if (this_rd < search_state->best_intra_rd) { - search_state->best_intra_rd = this_rd; - search_state->best_intra_mode = mode; - } - - if (sf->skip_intra_in_interframe) { - if (search_state->best_rd < (INT64_MAX / 2) && - this_rd > (search_state->best_rd + (search_state->best_rd >> 1))) - search_state->skip_intra_modes = 1; - } - - if (!disable_skip) { - for (int i = 0; i < REFERENCE_MODES; ++i) { - search_state->best_pred_rd[i] = - AOMMIN(search_state->best_pred_rd[i], this_rd); - } - } - return this_rd; + set_default_interp_filters(mbmi, cm->features.interp_filter); } static AOM_INLINE void collect_single_states(MACROBLOCK *x, @@ -12561,7 +3853,7 @@ static AOM_INLINE void collect_single_states(MACROBLOCK *x, static AOM_INLINE void analyze_single_states( const AV1_COMP *cpi, InterModeSearchState *search_state) { - const int prune_level = cpi->sf.prune_comp_search_by_single_result; + const int prune_level = cpi->sf.inter_sf.prune_comp_search_by_single_result; assert(prune_level >= 1); int i, j, dir, mode; @@ -12664,17 +3956,17 @@ static int compound_skip_get_candidates( } int candidates = max_candidates; - if (cpi->sf.prune_comp_search_by_single_result >= 2) { + if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 2) { candidates = AOMMIN(2, max_candidates); } - if (cpi->sf.prune_comp_search_by_single_result >= 3) { + if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 3) { if (state[0].rd != INT64_MAX && state_modelled[0].rd != INT64_MAX && state[0].ref_frame == state_modelled[0].ref_frame) candidates = 1; if (mode == NEARMV || mode == GLOBALMV) candidates = 1; } - if (cpi->sf.prune_comp_search_by_single_result >= 4) { + if (cpi->sf.inter_sf.prune_comp_search_by_single_result >= 4) { // Limit the number of candidates to 1 in each direction for compound // prediction candidates = AOMMIN(1, candidates); @@ -12718,8 +4010,9 @@ static int compound_skip_by_single_states( for (int ref_mv_idx = 0; ref_mv_idx < ref_set; ref_mv_idx++) { int_mv single_mv; int_mv comp_mv; - get_this_mv(&single_mv, mode[i], 0, ref_mv_idx, single_refs, x->mbmi_ext); - get_this_mv(&comp_mv, this_mode, i, ref_mv_idx, refs, x->mbmi_ext); + get_this_mv(&single_mv, mode[i], 0, ref_mv_idx, 0, single_refs, + x->mbmi_ext); + get_this_mv(&comp_mv, this_mode, i, ref_mv_idx, 0, refs, x->mbmi_ext); if (single_mv.as_int != comp_mv.as_int) { ref_mv_match[i] = 0; break; @@ -12746,91 +4039,45 @@ static int compound_skip_by_single_states( return 0; } -static INLINE int sf_check_is_drop_ref(const MODE_DEFINITION *mode, - InterModeSearchState *search_state) { - const MV_REFERENCE_FRAME ref_frame = mode->ref_frame[0]; - const MV_REFERENCE_FRAME second_ref_frame = mode->ref_frame[1]; - if (search_state->num_available_refs > 2) { - if ((ref_frame == search_state->dist_order_refs[0] && - second_ref_frame == search_state->dist_order_refs[1]) || - (ref_frame == search_state->dist_order_refs[1] && - second_ref_frame == search_state->dist_order_refs[0])) - return 1; // drop this pair of refs - } - return 0; -} - -static INLINE void sf_drop_ref_analyze(InterModeSearchState *search_state, - const MODE_DEFINITION *mode, - int64_t distortion2) { - const PREDICTION_MODE this_mode = mode->mode; - MV_REFERENCE_FRAME ref_frame = mode->ref_frame[0]; - const int idx = ref_frame - LAST_FRAME; - if (idx && distortion2 > search_state->dist_refs[idx]) { - search_state->dist_refs[idx] = distortion2; - search_state->dist_order_refs[idx] = ref_frame; - } - - // Reach the last single ref prediction mode - if (ref_frame == ALTREF_FRAME && this_mode == GLOBALMV) { - // bubble sort dist_refs and the order index - for (int i = 0; i < REF_FRAMES; ++i) { - for (int k = i + 1; k < REF_FRAMES; ++k) { - if (search_state->dist_refs[i] < search_state->dist_refs[k]) { - int64_t tmp_dist = search_state->dist_refs[i]; - search_state->dist_refs[i] = search_state->dist_refs[k]; - search_state->dist_refs[k] = tmp_dist; - - int tmp_idx = search_state->dist_order_refs[i]; - search_state->dist_order_refs[i] = search_state->dist_order_refs[k]; - search_state->dist_order_refs[k] = tmp_idx; - } - } +// Check if ref frames of current block matches with given block. +static INLINE void match_ref_frame(const MB_MODE_INFO *const mbmi, + const MV_REFERENCE_FRAME *ref_frames, + int *const is_ref_match) { + if (is_inter_block(mbmi)) { + is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[0]; + is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[0]; + if (has_second_ref(mbmi)) { + is_ref_match[0] |= ref_frames[0] == mbmi->ref_frame[1]; + is_ref_match[1] |= ref_frames[1] == mbmi->ref_frame[1]; } - for (int i = 0; i < REF_FRAMES; ++i) { - if (search_state->dist_refs[i] == -1) break; - search_state->num_available_refs = i; - } - search_state->num_available_refs++; } } -// sf->prune_single_motion_modes_by_simple_trans -static int analyze_simple_trans_states(const AV1_COMP *cpi, MACROBLOCK *x) { - (void)cpi; - int64_t rdcosts[REF_FRAMES] = { INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, - INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX }; - int skip_ref = 0; - int64_t min_rd = INT64_MAX; - for (THR_MODES i = SINGLE_REF_MODE_START; i < SINGLE_REF_MODE_END; ++i) { - const MODE_DEFINITION *mode_order = &av1_mode_defs[i]; - const MV_REFERENCE_FRAME ref_frame = mode_order->ref_frame[0]; - for (int k = 0; k < MAX_REF_MV_SEARCH; ++k) { - const int64_t rd = x->simple_rd_state[i][k].rd_stats.rdcost; - rdcosts[ref_frame] = AOMMIN(rdcosts[ref_frame], rd); - min_rd = AOMMIN(min_rd, rd); - } - } - int valid_cnt = 0; - for (int i = 1; i < REF_FRAMES; ++i) { - if (rdcosts[i] == INT64_MAX) { - skip_ref |= (1 << i); - } else { - valid_cnt++; - } - } - if (valid_cnt < 2) { +// Prune compound mode using ref frames of neighbor blocks. +static INLINE int compound_skip_using_neighbor_refs( + MACROBLOCKD *const xd, const PREDICTION_MODE this_mode, + const MV_REFERENCE_FRAME *ref_frames, int prune_compound_using_neighbors) { + // Exclude non-extended compound modes from pruning + if (this_mode == NEAREST_NEARESTMV || this_mode == NEAR_NEARMV || + this_mode == NEW_NEWMV || this_mode == GLOBAL_GLOBALMV) return 0; - } - min_rd += (min_rd >> 1); - if (valid_cnt > 2) { - for (int i = 1; i < REF_FRAMES; ++i) { - if (rdcosts[i] > min_rd) { - skip_ref |= (1 << i); - } - } - } - return skip_ref; + + int is_ref_match[2] = { 0 }; // 0 - match for forward refs + // 1 - match for backward refs + // Check if ref frames of this block matches with left neighbor. + if (xd->left_available) + match_ref_frame(xd->left_mbmi, ref_frames, is_ref_match); + + // Check if ref frames of this block matches with above neighbor. + if (xd->up_available) + match_ref_frame(xd->above_mbmi, ref_frames, is_ref_match); + + // Combine ref frame match with neighbors in forward and backward refs. + const int track_ref_match = is_ref_match[0] + is_ref_match[1]; + + // Pruning based on ref frame match with neighbors. + if (track_ref_match >= prune_compound_using_neighbors) return 0; + return 1; } static int compare_int64(const void *a, const void *b) { @@ -12864,9 +4111,9 @@ static INLINE void update_search_state( search_state->best_skip2 = skip; search_state->best_mode_skippable = new_best_rd_stats->skip; // When !txfm_search_done, new_best_rd_stats won't provide correct rate_y and - // rate_uv because txfm_search process is replaced by rd estimation. + // rate_uv because av1_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. + // These two values will be updated when av1_txfm_search is called. if (txfm_search_done) { search_state->best_rate_y = new_best_rd_stats_y->rate + @@ -12904,11 +4151,280 @@ static INLINE bool in_single_ref_cutoff(int64_t ref_frame_rd[REF_FRAMES], ref_frame_rd[frame2] <= ref_frame_rd[0]; } +static AOM_INLINE void evaluate_motion_mode_for_winner_candidates( + const AV1_COMP *const cpi, MACROBLOCK *const x, RD_STATS *const rd_cost, + HandleInterModeArgs *const args, TileDataEnc *const tile_data, + PICK_MODE_CONTEXT *const ctx, + struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE], + const motion_mode_best_st_candidate *const best_motion_mode_cands, + int do_tx_search, const BLOCK_SIZE bsize, int64_t *const best_est_rd, + InterModeSearchState *const search_state) { + 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]; + InterModesInfo *const inter_modes_info = x->inter_modes_info; + const int num_best_cand = best_motion_mode_cands->num_motion_mode_cand; + + for (int cand = 0; cand < num_best_cand; cand++) { + RD_STATS rd_stats; + RD_STATS rd_stats_y; + RD_STATS rd_stats_uv; + av1_init_rd_stats(&rd_stats); + av1_init_rd_stats(&rd_stats_y); + av1_init_rd_stats(&rd_stats_uv); + int disable_skip = 0, rate_mv; + + rate_mv = best_motion_mode_cands->motion_mode_cand[cand].rate_mv; + args->skip_motion_mode = + best_motion_mode_cands->motion_mode_cand[cand].skip_motion_mode; + *mbmi = best_motion_mode_cands->motion_mode_cand[cand].mbmi; + rd_stats.rate = + best_motion_mode_cands->motion_mode_cand[cand].rate2_nocoeff; + + // Continue if the best candidate is compound. + if (!is_inter_singleref_mode(mbmi->mode)) continue; + + x->force_skip = 0; + const int mode_index = get_prediction_mode_idx( + mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); + struct macroblockd_plane *p = xd->plane; + const BUFFER_SET orig_dst = { + { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf }, + { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride }, + }; + + set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); + args->simple_rd_state = x->simple_rd_state[mode_index]; + // Initialize motion mode to simple translation + // Calculation of switchable rate depends on it. + mbmi->motion_mode = 0; + const int is_comp_pred = mbmi->ref_frame[1] > INTRA_FRAME; + for (int 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]; + } + + int64_t skip_rd[2] = { search_state->best_skip_rd[0], + search_state->best_skip_rd[1] }; + int64_t ret_value = motion_mode_rd( + cpi, tile_data, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, + &disable_skip, args, search_state->best_rd, skip_rd, &rate_mv, + &orig_dst, best_est_rd, do_tx_search, inter_modes_info, 1); + + if (ret_value != INT64_MAX) { + rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist); + const THR_MODES mode_enum = get_prediction_mode_idx( + mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); + // Collect mode stats for multiwinner mode processing + store_winner_mode_stats( + &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, + mode_enum, NULL, bsize, rd_stats.rdcost, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, do_tx_search); + if (rd_stats.rdcost < search_state->best_rd) { + update_search_state(search_state, rd_cost, ctx, &rd_stats, &rd_stats_y, + &rd_stats_uv, mode_enum, x, do_tx_search); + if (do_tx_search) search_state->best_skip_rd[0] = skip_rd[0]; + } + } + } +} + +// Arguments for speed feature pruning of inter mode search +typedef struct { + int *skip_motion_mode; + mode_skip_mask_t *mode_skip_mask; + InterModeSearchState *search_state; + int skip_ref_frame_mask; + int reach_first_comp_mode; + int mode_thresh_mul_fact; + int *intra_mode_idx_ls; + int *intra_mode_num; + int prune_cpd_using_sr_stats_ready; +} InterModeSFArgs; + +static int skip_inter_mode(AV1_COMP *cpi, MACROBLOCK *x, const BLOCK_SIZE bsize, + int64_t *ref_frame_rd, int midx, + InterModeSFArgs *args) { + const SPEED_FEATURES *const sf = &cpi->sf; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + // Get the actual prediction mode we are trying in this iteration + const THR_MODES mode_enum = av1_default_mode_order[midx]; + const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum]; + const PREDICTION_MODE this_mode = mode_def->mode; + const MV_REFERENCE_FRAME *ref_frames = mode_def->ref_frame; + const MV_REFERENCE_FRAME ref_frame = ref_frames[0]; + const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1]; + const int comp_pred = second_ref_frame > INTRA_FRAME; + const int last_single_ref_mode_idx = + find_last_single_ref_mode_idx(av1_default_mode_order); + + // After we done with single reference modes, find the 2nd best RD + // for a reference frame. Only search compound modes that have a reference + // frame at least as good as the 2nd best. + if (sf->inter_sf.prune_compound_using_single_ref && + midx == last_single_ref_mode_idx + 1) { + find_top_ref(ref_frame_rd); + args->prune_cpd_using_sr_stats_ready = 1; + } + + // Check if this mode should be skipped because it is incompatible with the + // current frame + if (inter_mode_compatible_skip(cpi, x, bsize, this_mode, ref_frames)) + return 1; + const int ret = inter_mode_search_order_independent_skip( + cpi, x, args->mode_skip_mask, args->search_state, + args->skip_ref_frame_mask, this_mode, mode_def->ref_frame); + if (ret == 1) return 1; + *(args->skip_motion_mode) = (ret == 2); + + // We've reached the first compound prediction mode, get stats from the + // single reference predictors to help with pruning + if (sf->inter_sf.prune_comp_search_by_single_result > 0 && comp_pred && + args->reach_first_comp_mode == 0) { + analyze_single_states(cpi, args->search_state); + args->reach_first_comp_mode = 1; + } + + // Prune aggressively when best mode is skippable. + int mul_fact = args->search_state->best_mode_skippable + ? args->mode_thresh_mul_fact + : (1 << MODE_THRESH_QBITS); + int64_t mode_threshold = + (args->search_state->mode_threshold[mode_enum] * mul_fact) >> + MODE_THRESH_QBITS; + + if (args->search_state->best_rd < mode_threshold) return 1; + + // Skip this compound mode based on the RD results from the single prediction + // modes + if (sf->inter_sf.prune_comp_search_by_single_result > 0 && comp_pred) { + if (compound_skip_by_single_states(cpi, args->search_state, this_mode, + ref_frame, second_ref_frame, x)) + return 1; + } + + // Speed features to prune out INTRA frames + if (ref_frame == INTRA_FRAME) { + if ((!cpi->oxcf.enable_smooth_intra || sf->intra_sf.disable_smooth_intra) && + (mbmi->mode == SMOOTH_PRED || mbmi->mode == SMOOTH_H_PRED || + mbmi->mode == SMOOTH_V_PRED)) + return 1; + if (!cpi->oxcf.enable_paeth_intra && mbmi->mode == PAETH_PRED) return 1; + if (sf->inter_sf.adaptive_mode_search > 1) + if ((x->source_variance << num_pels_log2_lookup[bsize]) > + args->search_state->best_pred_sse) + return 1; + + // Intra modes will be handled in another loop later. + assert(*args->intra_mode_num < INTRA_MODES); + args->intra_mode_idx_ls[(*args->intra_mode_num)++] = mode_enum; + return 1; + } + + if (sf->inter_sf.prune_compound_using_single_ref && + args->prune_cpd_using_sr_stats_ready && comp_pred && + !in_single_ref_cutoff(ref_frame_rd, ref_frame, second_ref_frame)) { + return 1; + } + + if (sf->inter_sf.prune_compound_using_neighbors && comp_pred) { + if (compound_skip_using_neighbor_refs( + xd, this_mode, ref_frames, + sf->inter_sf.prune_compound_using_neighbors)) + return 1; + } + + return 0; +} + +static void record_best_compound(REFERENCE_MODE reference_mode, + RD_STATS *rd_stats, int comp_pred, int rdmult, + InterModeSearchState *search_state, + int compmode_cost) { + int64_t single_rd, hybrid_rd, single_rate, hybrid_rate; + + if (reference_mode == REFERENCE_MODE_SELECT) { + single_rate = rd_stats->rate - compmode_cost; + hybrid_rate = rd_stats->rate; + } else { + single_rate = rd_stats->rate; + hybrid_rate = rd_stats->rate + compmode_cost; + } + + single_rd = RDCOST(rdmult, single_rate, rd_stats->dist); + hybrid_rd = RDCOST(rdmult, hybrid_rate, rd_stats->dist); + + if (!comp_pred) { + if (single_rd < + search_state->intra_search_state.best_pred_rd[SINGLE_REFERENCE]) + search_state->intra_search_state.best_pred_rd[SINGLE_REFERENCE] = + single_rd; + } else { + if (single_rd < + search_state->intra_search_state.best_pred_rd[COMPOUND_REFERENCE]) + search_state->intra_search_state.best_pred_rd[COMPOUND_REFERENCE] = + single_rd; + } + if (hybrid_rd < + search_state->intra_search_state.best_pred_rd[REFERENCE_MODE_SELECT]) + search_state->intra_search_state.best_pred_rd[REFERENCE_MODE_SELECT] = + hybrid_rd; +} + +// Indicates number of winner simple translation modes to be used +static const unsigned int num_winner_motion_modes[3] = { 0, 10, 3 }; + +// Adds a motion mode to the candidate list for motion_mode_for_winner_cand +// speed feature. This list consists of modes that have only searched +// SIMPLE_TRANSLATION. The final list will be used to search other motion +// modes after the initial RD search. +static void handle_winner_cand( + MB_MODE_INFO *const mbmi, + motion_mode_best_st_candidate *best_motion_mode_cands, + int max_winner_motion_mode_cand, int64_t this_rd, + motion_mode_candidate *motion_mode_cand, int skip_motion_mode) { + // Number of current motion mode candidates in list + const int num_motion_mode_cand = best_motion_mode_cands->num_motion_mode_cand; + int valid_motion_mode_cand_loc = num_motion_mode_cand; + + // find the best location to insert new motion mode candidate + for (int j = 0; j < num_motion_mode_cand; j++) { + if (this_rd < best_motion_mode_cands->motion_mode_cand[j].rd_cost) { + valid_motion_mode_cand_loc = j; + break; + } + } + + // Insert motion mode if location is found + if (valid_motion_mode_cand_loc < max_winner_motion_mode_cand) { + if (num_motion_mode_cand > 0 && + valid_motion_mode_cand_loc < max_winner_motion_mode_cand - 1) + memmove( + &best_motion_mode_cands + ->motion_mode_cand[valid_motion_mode_cand_loc + 1], + &best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc], + (AOMMIN(num_motion_mode_cand, max_winner_motion_mode_cand - 1) - + valid_motion_mode_cand_loc) * + sizeof(best_motion_mode_cands->motion_mode_cand[0])); + motion_mode_cand->mbmi = *mbmi; + motion_mode_cand->rd_cost = this_rd; + motion_mode_cand->skip_motion_mode = skip_motion_mode; + best_motion_mode_cands->motion_mode_cand[valid_motion_mode_cand_loc] = + *motion_mode_cand; + best_motion_mode_cands->num_motion_mode_cand = + AOMMIN(max_winner_motion_mode_cand, + best_motion_mode_cands->num_motion_mode_cand + 1); + } +} + 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, const BLOCK_SIZE bsize, - PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far) { + MACROBLOCK *x, RD_STATS *rd_cost, + const BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, + int64_t best_rd_so_far) { AV1_COMMON *const cm = &cpi->common; + const FeatureFlags *const features = &cm->features; const int num_planes = av1_num_planes(cm); const SPEED_FEATURES *const sf = &cpi->sf; MACROBLOCKD *const xd = &x->e_mbd; @@ -12923,32 +4439,53 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, 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 - }; + 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, + INT_MAX, + INT_MAX, + search_state.simple_rd, + 0, + interintra_modes, + 1, + NULL, + { { { 0 }, { { 0 } }, { 0 }, 0, 0, 0, 0 } }, + 0 }; + // Indicates the appropriate number of simple translation winner modes for + // exhaustive motion mode evaluation + const int max_winner_motion_mode_cand = + num_winner_motion_modes[cpi->sf.winner_mode_sf + .motion_mode_for_winner_cand]; + assert(max_winner_motion_mode_cand <= MAX_WINNER_MOTION_MODES); + motion_mode_candidate motion_mode_cand; + motion_mode_best_st_candidate best_motion_mode_cands; + // Initializing the number of motion mode candidates to zero. + best_motion_mode_cands.num_motion_mode_cand = 0; + for (i = 0; i < MAX_WINNER_MOTION_MODES; ++i) + best_motion_mode_cands.motion_mode_cand[i].rd_cost = INT64_MAX; + 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 && + if (cpi->sf.inter_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); + cpi->sf.inter_sf.prune_ref_frame_for_rect_partitions >= 2) { + picked_ref_frames_mask = + fetch_picked_ref_frames_mask(x, bsize, cm->seq_params.mib_size); } } @@ -12960,25 +4497,24 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, unsigned int ref_costs_comp[REF_FRAMES][REF_FRAMES]; struct buf_2d yv12_mb[REF_FRAMES][MAX_MB_PLANE]; // init params, set frame modes, speed features - set_params_rd_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); + set_params_rd_pick_inter_mode(cpi, x, &args, bsize, &mode_skip_mask, + skip_ref_frame_mask, ref_costs_single, + ref_costs_comp, yv12_mb); int64_t best_est_rd = INT64_MAX; const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize]; // If do_tx_search is 0, only estimated RD should be computed. // If do_tx_search is 1, all modes have TX search performed. const int do_tx_search = - !((cpi->sf.inter_mode_rd_model_estimation == 1 && md->ready) || - (cpi->sf.inter_mode_rd_model_estimation == 2 && + !((cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 && md->ready) || + (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 2 && num_pels_log2_lookup[bsize] > 8) || - cpi->sf.force_tx_search_off); + cpi->sf.rt_sf.force_tx_search_off); InterModesInfo *inter_modes_info = x->inter_modes_info; inter_modes_info->num = 0; int intra_mode_num = 0; int intra_mode_idx_ls[INTRA_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]); @@ -12995,9 +4531,36 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, int64_t inter_cost = -1; int64_t intra_cost = -1; // Need to tweak the threshold for hdres speed 0 & 1. + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + // Obtain the relevant tpl stats for pruning inter modes + PruneInfoFromTpl inter_cost_info_from_tpl; +#if !CONFIG_REALTIME_ONLY + if (cpi->sf.inter_sf.prune_inter_modes_based_on_tpl) { + // x->search_ref_frame[id] = 1 => no pruning in + // prune_ref_by_selective_ref_frame() + // x->search_ref_frame[id] = 0 => ref frame can be pruned in + // prune_ref_by_selective_ref_frame() + // Populating valid_refs[idx] = 1 ensures that + // 'inter_cost_info_from_tpl.best_inter_cost' does not correspond to a + // pruned ref frame. + int valid_refs[INTER_REFS_PER_FRAME]; + for (MV_REFERENCE_FRAME frame = LAST_FRAME; frame < REF_FRAMES; frame++) { + const MV_REFERENCE_FRAME refs[2] = { frame, NONE_FRAME }; + valid_refs[frame - 1] = + x->search_ref_frame[frame] || + !prune_ref_by_selective_ref_frame( + cpi, x, refs, cm->cur_frame->ref_display_order_hint); + } + av1_zero(inter_cost_info_from_tpl); + get_block_level_tpl_stats(cpi, bsize, mi_row, mi_col, valid_refs, + &inter_cost_info_from_tpl); + } +#endif const int do_pruning = (AOMMIN(cm->width, cm->height) > 480 && cpi->speed <= 1) ? 0 : 1; - if (do_pruning && sf->skip_intra_in_interframe) { + if (do_pruning && sf->intra_sf.skip_intra_in_interframe) { // Only consider full SB. int len = tpl_blocks_in_sb(cm->seq_params.sb_size); if (len == x->valid_cost_b) { @@ -13023,99 +4586,56 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, } } - const int last_single_ref_mode_idx = - find_last_single_ref_mode_idx(av1_default_mode_order); - int prune_cpd_using_sr_stats_ready = 0; + // Initialize best mode stats for winner mode processing + av1_zero(x->winner_mode_stats); + x->winner_mode_count = 0; + store_winner_mode_stats( + &cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID, NULL, bsize, + best_rd_so_far, cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + 0); - // Here midx is just an interator index that should not be used by itself + int mode_thresh_mul_fact = (1 << MODE_THRESH_QBITS); + if (sf->inter_sf.prune_inter_modes_if_skippable) { + // Higher multiplication factor values for lower quantizers. + mode_thresh_mul_fact = mode_threshold_mul_factor[x->qindex]; + } + + // Initialize arguments for mode loop speed features + InterModeSFArgs sf_args = { &args.skip_motion_mode, + &mode_skip_mask, + &search_state, + skip_ref_frame_mask, + 0, + mode_thresh_mul_fact, + intra_mode_idx_ls, + &intra_mode_num, + 0 }; + + // Here midx is just an iterator index that should not be used by itself // except to keep track of the number of modes searched. It should be used // with av1_default_mode_order to get the enum that defines the mode, which // can be used with av1_mode_defs to get the prediction mode and the ref // frames. - for (int midx = 0; midx < MAX_MODES; ++midx) { - // After we done with single reference modes, find the 2nd best RD - // for a reference frame. Only search compound modes that have a reference - // frame at least as good as the 2nd best. - if (sf->prune_compound_using_single_ref && - midx == last_single_ref_mode_idx + 1) { - find_top_ref(ref_frame_rd); - prune_cpd_using_sr_stats_ready = 1; - } - + for (THR_MODES midx = THR_MODE_START; midx < THR_MODE_END; ++midx) { + // Get the actual prediction mode we are trying in this iteration const THR_MODES mode_enum = av1_default_mode_order[midx]; const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum]; const PREDICTION_MODE this_mode = mode_def->mode; const MV_REFERENCE_FRAME *ref_frames = mode_def->ref_frame; - if (inter_mode_compatible_skip(cpi, x, bsize, this_mode, ref_frames)) - continue; - const int ret = inter_mode_search_order_independent_skip( - cpi, x, &mode_skip_mask, &search_state, skip_ref_frame_mask, this_mode, - mode_def->ref_frame); - if (ret == 1) continue; - args.skip_motion_mode = (ret == 2); - const MV_REFERENCE_FRAME ref_frame = ref_frames[0]; const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1]; const int is_single_pred = ref_frame > INTRA_FRAME && second_ref_frame == NONE_FRAME; const int comp_pred = second_ref_frame > INTRA_FRAME; - if (sf->prune_compound_using_single_ref && prune_cpd_using_sr_stats_ready && - comp_pred && - !in_single_ref_cutoff(ref_frame_rd, ref_frame, second_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; - } - init_mbmi(mbmi, this_mode, ref_frames, cm); - x->skip = 0; + x->force_skip = 0; set_ref_ptrs(cm, xd, ref_frame, second_ref_frame); - if (sf->drop_ref && comp_pred) { - if (sf_check_is_drop_ref(mode_def, &search_state)) { - continue; - } - } - - if (search_state.best_rd < search_state.mode_threshold[mode_enum]) 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 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 (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; - - // Intra modes will be handled in another loop later. - assert(intra_mode_num < INTRA_MODES); - intra_mode_idx_ls[intra_mode_num++] = mode_enum; - continue; - } + // Apply speed features to decide if this inter mode can be skipped + if (skip_inter_mode(cpi, x, bsize, ref_frame_rd, midx, &sf_args)) continue; // Select prediction reference frames. for (i = 0; i < num_planes; i++) { @@ -13136,6 +4656,12 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, 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; // 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; @@ -13146,12 +4672,15 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, args.simple_rd_state = x->simple_rd_state[mode_enum]; } + int64_t skip_rd[2] = { search_state.best_skip_rd[0], + search_state.best_skip_rd[1] }; int64_t 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, - &x->comp_rd_buffer, &best_est_rd, do_tx_search, inter_modes_info); + &disable_skip, &args, ref_best_rd, tmp_buf, &x->comp_rd_buffer, + &best_est_rd, do_tx_search, inter_modes_info, &motion_mode_cand, + skip_rd, &inter_cost_info_from_tpl); - if (sf->prune_comp_search_by_single_result > 0 && + if (sf->inter_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); } @@ -13163,51 +4692,43 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, rd_stats_uv.rate = 0; } - if (sf->prune_compound_using_single_ref && is_single_pred && + if (sf->inter_sf.prune_compound_using_single_ref && is_single_pred && this_rd < ref_frame_rd[ref_frame]) { ref_frame_rd[ref_frame] = this_rd; } // Did this mode help, i.e., is it the new best mode - if (this_rd < search_state.best_rd || x->skip) { + if (this_rd < search_state.best_rd) { assert(IMPLIES(comp_pred, cm->current_frame.reference_mode != SINGLE_REFERENCE)); search_state.best_pred_sse = x->pred_sse[ref_frame]; update_search_state(&search_state, rd_cost, ctx, &rd_stats, &rd_stats_y, &rd_stats_uv, mode_enum, x, do_tx_search); + if (do_tx_search) search_state.best_skip_rd[0] = skip_rd[0]; + search_state.best_skip_rd[1] = skip_rd[1]; + } + if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) { + // Add this mode to motion mode candidate list for motion mode search + // if using motion_mode_for_winner_cand speed feature + handle_winner_cand(mbmi, &best_motion_mode_cands, + max_winner_motion_mode_cand, this_rd, + &motion_mode_cand, args.skip_motion_mode); } /* keep record of best compound/single-only prediction */ if (!disable_skip) { - int64_t single_rd, hybrid_rd, single_rate, hybrid_rate; - - if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT) { - single_rate = rd_stats.rate - compmode_cost; - hybrid_rate = rd_stats.rate; - } else { - single_rate = rd_stats.rate; - hybrid_rate = rd_stats.rate + compmode_cost; - } - - single_rd = RDCOST(x->rdmult, single_rate, rd_stats.dist); - hybrid_rd = RDCOST(x->rdmult, hybrid_rate, rd_stats.dist); - - 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_def, rd_stats.dist); + record_best_compound(cm->current_frame.reference_mode, &rd_stats, + comp_pred, x->rdmult, &search_state, compmode_cost); } + } - if (x->skip && !comp_pred) break; + if (cpi->sf.winner_mode_sf.motion_mode_for_winner_cand) { + // For the single ref winner candidates, evaluate other motion modes (non + // simple translation). + evaluate_motion_mode_for_winner_candidates( + cpi, x, rd_cost, &args, tile_data, ctx, yv12_mb, + &best_motion_mode_cands, do_tx_search, bsize, &best_est_rd, + &search_state); } #if CONFIG_COLLECT_COMPONENT_TIMING @@ -13217,10 +4738,16 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr); search_state.best_rd = best_rd_so_far; search_state.best_mode_index = THR_INVALID; + // Initialize best mode stats for winner mode processing + x->winner_mode_count = 0; + store_winner_mode_stats( + &cpi->common, x, mbmi, NULL, NULL, NULL, THR_INVALID, NULL, bsize, + best_rd_so_far, cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + do_tx_search); inter_modes_info->num = - inter_modes_info->num < cpi->sf.num_inter_modes_for_tx_search + inter_modes_info->num < cpi->sf.rt_sf.num_inter_modes_for_tx_search ? inter_modes_info->num - : cpi->sf.num_inter_modes_for_tx_search; + : cpi->sf.rt_sf.num_inter_modes_for_tx_search; const int64_t top_est_rd = inter_modes_info->num > 0 ? inter_modes_info @@ -13232,7 +4759,7 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, int64_t curr_est_rd = inter_modes_info->est_rd_arr[data_idx]; if (curr_est_rd * 0.80 > top_est_rd) break; - x->skip = 0; + x->force_skip = 0; set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]); // Select prediction reference frames. @@ -13244,18 +4771,29 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, 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 (mbmi->motion_mode == OBMC_CAUSAL) { + av1_build_obmc_inter_predictors_sb(cm, xd); + } RD_STATS rd_stats; RD_STATS rd_stats_y; RD_STATS rd_stats_uv; const int mode_rate = inter_modes_info->mode_rate_arr[data_idx]; - 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)) { + int64_t skip_rd = INT64_MAX; + if (cpi->sf.inter_sf.txfm_rd_gate_level) { + // Check if the mode is good enough based on skip RD + int64_t curr_sse = inter_modes_info->sse_arr[data_idx]; + skip_rd = RDCOST(x->rdmult, mode_rate, curr_sse); + int eval_txfm = + check_txfm_eval(x, bsize, search_state.best_skip_rd[0], skip_rd, + cpi->sf.inter_sf.txfm_rd_gate_level, 0); + if (!eval_txfm) continue; + } + + if (!av1_txfm_search(cpi, x, bsize, &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) { + } else if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) { inter_mode_data_push(tile_data, mbmi->sb_type, rd_stats.sse, rd_stats.dist, rd_stats_y.rate + rd_stats_uv.rate + @@ -13263,14 +4801,21 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, } rd_stats.rdcost = RDCOST(x->rdmult, rd_stats.rate, rd_stats.dist); + const THR_MODES mode_enum = get_prediction_mode_idx( + mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); + + // Collect mode stats for multiwinner mode processing + const int txfm_search_done = 1; + store_winner_mode_stats( + &cpi->common, x, mbmi, &rd_stats, &rd_stats_y, &rd_stats_uv, + mode_enum, NULL, bsize, rd_stats.rdcost, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + txfm_search_done); + if (rd_stats.rdcost < search_state.best_rd) { - // TODO(chiyotsai@google.com): get_prediction_mode_idx gives incorrect - // output once we change the mode order. Fix this! - const THR_MODES mode_enum = get_prediction_mode_idx( - mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); - const int txfm_search_done = 1; update_search_state(&search_state, rd_cost, ctx, &rd_stats, &rd_stats_y, &rd_stats_uv, mode_enum, x, txfm_search_done); + search_state.best_skip_rd[0] = skip_rd; } } } @@ -13284,40 +4829,42 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, // Gate intra mode evaluation if best of inter is skip except when source // variance is extremely low - if (sf->skip_intra_in_interframe && - (x->source_variance > sf->src_var_thresh_intra_skip)) { + if (sf->intra_sf.skip_intra_in_interframe && + (x->source_variance > sf->intra_sf.src_var_thresh_intra_skip)) { if (inter_cost >= 0 && intra_cost >= 0) { aom_clear_system_state(); const NN_CONFIG *nn_config = (AOMMIN(cm->width, cm->height) <= 480) ? &av1_intrap_nn_config : &av1_intrap_hd_nn_config; - float features[6]; + float nn_features[6]; float scores[2] = { 0.0f }; float probs[2] = { 0.0f }; - features[0] = (float)search_state.best_mbmode.skip; - features[1] = (float)mi_size_wide_log2[bsize]; - features[2] = (float)mi_size_high_log2[bsize]; - features[3] = (float)intra_cost; - features[4] = (float)inter_cost; + nn_features[0] = (float)search_state.best_mbmode.skip; + nn_features[1] = (float)mi_size_wide_log2[bsize]; + nn_features[2] = (float)mi_size_high_log2[bsize]; + nn_features[3] = (float)intra_cost; + nn_features[4] = (float)inter_cost; const int ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd); const int ac_q_max = av1_ac_quant_QTX(255, 0, xd->bd); - features[5] = (float)(ac_q_max / ac_q); + nn_features[5] = (float)(ac_q_max / ac_q); - av1_nn_predict(features, nn_config, 1, scores); + av1_nn_predict(nn_features, nn_config, 1, scores); aom_clear_system_state(); av1_nn_softmax(scores, probs, 2); - if (probs[1] > 0.8) search_state.skip_intra_modes = 1; + if (probs[1] > 0.8) search_state.intra_search_state.skip_intra_modes = 1; } else if ((search_state.best_mbmode.skip) && - (sf->skip_intra_in_interframe >= 2)) { - search_state.skip_intra_modes = 1; + (sf->intra_sf.skip_intra_in_interframe >= 2)) { + search_state.intra_search_state.skip_intra_modes = 1; } } const int intra_ref_frame_cost = ref_costs_single[INTRA_FRAME]; for (int j = 0; j < intra_mode_num; ++j) { - if (sf->skip_intra_in_interframe && search_state.skip_intra_modes) break; + if (sf->intra_sf.skip_intra_in_interframe && + search_state.intra_search_state.skip_intra_modes) + break; const THR_MODES mode_enum = intra_mode_idx_ls[j]; const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum]; const PREDICTION_MODE this_mode = mode_def->mode; @@ -13325,29 +4872,38 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, assert(av1_mode_defs[mode_enum].ref_frame[0] == INTRA_FRAME); assert(av1_mode_defs[mode_enum].ref_frame[1] == NONE_FRAME); init_mbmi(mbmi, this_mode, av1_mode_defs[mode_enum].ref_frame, cm); - x->skip = 0; + x->force_skip = 0; 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) && + if ((sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_BESTINTER) && (this_mode >= D45_PRED && this_mode <= PAETH_PRED)) { if (search_state.best_mode_index != THR_INVALID && 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)) + if (sf->rt_sf.mode_search_skip_flags & FLAG_SKIP_INTRA_DIRMISMATCH) { + if (conditional_skipintra( + this_mode, search_state.intra_search_state.best_intra_mode)) continue; } } RD_STATS intra_rd_stats, intra_rd_stats_y, intra_rd_stats_uv; - intra_rd_stats.rdcost = handle_intra_mode( - &search_state, cpi, x, bsize, mi_row, mi_col, intra_ref_frame_cost, ctx, - 0, &intra_rd_stats, &intra_rd_stats_y, &intra_rd_stats_uv); + intra_rd_stats.rdcost = av1_handle_intra_mode( + &search_state.intra_search_state, cpi, x, bsize, intra_ref_frame_cost, + ctx, 0, &intra_rd_stats, &intra_rd_stats_y, &intra_rd_stats_uv, + search_state.best_rd, &search_state.best_intra_rd, + search_state.best_mbmode.skip); + // Collect mode stats for multiwinner mode processing + const int txfm_search_done = 1; + store_winner_mode_stats( + &cpi->common, x, mbmi, &intra_rd_stats, &intra_rd_stats_y, + &intra_rd_stats_uv, mode_enum, NULL, bsize, intra_rd_stats.rdcost, + cpi->sf.winner_mode_sf.enable_multiwinner_mode_process, + txfm_search_done); if (intra_rd_stats.rdcost < search_state.best_rd) { - const int txfm_search_done = 1; update_search_state(&search_state, rd_cost, ctx, &intra_rd_stats, &intra_rd_stats_y, &intra_rd_stats_uv, mode_enum, x, txfm_search_done); @@ -13357,11 +4913,14 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, end_timing(cpi, handle_intra_mode_time); #endif + int winner_mode_count = cpi->sf.winner_mode_sf.enable_multiwinner_mode_process + ? x->winner_mode_count + : 1; // In effect only when fast tx search speed features are enabled. - refine_winner_mode_tx(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); + refine_winner_mode_tx( + cpi, x, 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, winner_mode_count); // Initialize default mode evaluation params set_mode_eval_params(cpi, x, DEFAULT_EVAL); @@ -13369,12 +4928,29 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, // Only try palette mode when the best mode so far is an intra mode. const int try_palette = cpi->oxcf.enable_palette && - av1_allow_palette(cm->allow_screen_content_tools, mbmi->sb_type) && + av1_allow_palette(features->allow_screen_content_tools, mbmi->sb_type) && !is_inter_mode(search_state.best_mbmode.mode); PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info; + RD_STATS this_rd_cost; + int this_skippable = 0; if (try_palette) { - search_palette_mode(cpi, x, mi_row, mi_col, rd_cost, ctx, bsize, mbmi, pmi, - ref_costs_single, &search_state); + this_skippable = av1_search_palette_mode( + cpi, x, &this_rd_cost, ctx, bsize, mbmi, pmi, ref_costs_single, + &search_state.intra_search_state, search_state.best_rd); + if (this_rd_cost.rdcost < search_state.best_rd) { + search_state.best_mode_index = THR_DC; + mbmi->mv[0].as_int = 0; + rd_cost->rate = this_rd_cost.rate; + rd_cost->dist = this_rd_cost.dist; + rd_cost->rdcost = this_rd_cost.rdcost; + search_state.best_rd = rd_cost->rdcost; + search_state.best_mbmode = *mbmi; + search_state.best_skip2 = 0; + search_state.best_mode_skippable = this_skippable; + memcpy(ctx->blk_skip, x->blk_skip, + sizeof(x->blk_skip[0]) * ctx->num_4x4_blk); + av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk); + } } search_state.best_mbmode.skip_mode = 0; @@ -13383,8 +4959,7 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, const struct segmentation *const seg = &cm->seg; unsigned char segment_id = mbmi->segment_id; if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) { - rd_pick_skip_mode(rd_cost, &search_state, cpi, x, bsize, mi_row, mi_col, - yv12_mb); + rd_pick_skip_mode(rd_cost, &search_state, cpi, x, bsize, yv12_mb); } } @@ -13404,46 +4979,49 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, return; } - assert((cm->interp_filter == SWITCHABLE) || - (cm->interp_filter == + const InterpFilter interp_filter = features->interp_filter; + assert((interp_filter == SWITCHABLE) || + (interp_filter == search_state.best_mbmode.interp_filters.as_filters.y_filter) || !is_inter_block(&search_state.best_mbmode)); - assert((cm->interp_filter == SWITCHABLE) || - (cm->interp_filter == + assert((interp_filter == SWITCHABLE) || + (interp_filter == search_state.best_mbmode.interp_filters.as_filters.x_filter) || !is_inter_block(&search_state.best_mbmode)); - if (!cpi->rc.is_src_frame_alt_ref) { - av1_update_rd_thresh_fact(cm, x->thresh_freq_fact, sf->adaptive_rd_thresh, - bsize, search_state.best_mode_index); + if (!cpi->rc.is_src_frame_alt_ref && cpi->sf.inter_sf.adaptive_rd_thresh) { + av1_update_rd_thresh_fact(cm, x->thresh_freq_fact, + sf->inter_sf.adaptive_rd_thresh, bsize, + search_state.best_mode_index); } // macroblock modes *mbmi = search_state.best_mbmode; - x->skip |= search_state.best_skip2; + x->force_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])) { - int_interpfilters filters = av1_broadcast_interp_filter( - av1_unswitchable_filter(cm->interp_filter)); + int_interpfilters filters = + av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter)); assert(mbmi->interp_filters.as_int == filters.as_int); (void)filters; } } for (i = 0; i < REFERENCE_MODES; ++i) { - if (search_state.best_pred_rd[i] == INT64_MAX) { + if (search_state.intra_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]; + search_state.best_rd - + search_state.intra_search_state.best_pred_rd[i]; } } - x->skip |= search_state.best_mode_skippable; + x->force_skip |= search_state.best_mode_skippable; assert(search_state.best_mode_index != THR_INVALID); @@ -13458,569 +5036,10 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data, if (pmi->palette_size[1] > 0) { assert(try_palette); - restore_uv_color_map(cpi, x); + av1_restore_uv_color_map(cpi, x); } } -// 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 AOM_INLINE 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; - 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; - - 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); - 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; - } -} - -// 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; - 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, x, bsize, best_rd_so_far); - 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, NULL, - 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 || (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]); - - for (int midx = 0; midx < MAX_MODES; ++midx) { - const THR_MODES mode_enum = av1_default_mode_order[midx]; - const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum]; - const PREDICTION_MODE this_mode = mode_def->mode; - const MV_REFERENCE_FRAME *ref_frames = mode_def->ref_frame; - - if (inter_mode_compatible_skip(cpi, x, bsize, this_mode, ref_frames)) - continue; - - const int ret = inter_mode_search_order_independent_skip( - cpi, x, &mode_skip_mask, &search_state, skip_ref_frame_mask, this_mode, - mode_def->ref_frame); - if (ret == 1) continue; - args.skip_motion_mode = (ret == 2); - - const MV_REFERENCE_FRAME ref_frame = ref_frames[0]; - const MV_REFERENCE_FRAME second_ref_frame = ref_frames[1]; - const int is_single_pred = - ref_frame > INTRA_FRAME && second_ref_frame == NONE_FRAME; - 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_SEARCH; ++k) { - x->simple_rd_state[mode_enum][k].rd_stats.rdcost = INT64_MAX; - x->simple_rd_state[mode_enum][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, this_mode, ref_frames, cm); - - x->skip = 0; - set_ref_ptrs(cm, xd, ref_frame, second_ref_frame); - - if (sf->drop_ref && comp_pred) { - if (sf_check_is_drop_ref(mode_def, &search_state)) { - continue; - } - } - - if (search_state.best_rd < search_state.mode_threshold[mode_enum]) 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 != THR_INVALID && - search_state.best_mbmode.ref_frame[0] == INTRA_FRAME) - continue; - } - - if (ref_frame == INTRA_FRAME) { - if (!cpi->oxcf.enable_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; - } - - // 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++] = mode_enum; - 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 (is_single_pred) { - args.simple_rd_state = x->simple_rd_state[mode_enum]; - } - 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, - &x->comp_rd_buffer, &best_est_rd, 0, inter_modes_info); - rate2 = rd_stats.rate; - skippable = rd_stats.skip; - distortion2 = rd_stats.dist; - } - - 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); - } - - // 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 = mode_enum; - - 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; - 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_def, distortion2); - } - - if (x->skip && !comp_pred) break; - } - - inter_modes_info_sort(inter_modes_info, inter_modes_info->rd_idx_pair_arr); - search_state.best_rd = INT64_MAX; - - 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]; - - 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]; - } - - 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); - - 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, - 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) { - // TODO(chiyotsai@google.com): get_prediction_mode_idx gives incorrect - // output once we change the mode order. Fix this! - const THR_MODES mode_enum = get_prediction_mode_idx( - mbmi->mode, mbmi->ref_frame[0], mbmi->ref_frame[1]); - const int txfm_search_done = 1; - update_search_state(&search_state, rd_cost, ctx, &rd_stats, &rd_stats_y, - &rd_stats_uv, mode_enum, x, txfm_search_done); - } - } - } - - for (int j = 0; j < intra_mode_num; ++j) { - const THR_MODES mode_enum = intra_mode_idx_ls[j]; - const MODE_DEFINITION *mode_def = &av1_mode_defs[mode_enum]; - const PREDICTION_MODE curr_mode = mode_def->mode; - const MV_REFERENCE_FRAME ref_frame = av1_mode_defs[mode_enum].ref_frame[0]; - assert(av1_mode_defs[mode_enum].ref_frame[1] == NONE_FRAME); - assert(ref_frame == INTRA_FRAME); - if (sf->skip_intra_in_interframe && search_state.skip_intra_modes) break; - if (curr_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) && - (curr_mode >= D45_PRED && curr_mode <= PAETH_PRED)) { - if (search_state.best_mode_index != THR_INVALID && - search_state.best_mbmode.ref_frame[0] > INTRA_FRAME) - continue; - } - if (sf->mode_search_skip_flags & FLAG_SKIP_INTRA_DIRMISMATCH) { - if (conditional_skipintra(curr_mode, search_state.best_intra_mode)) - continue; - } - } - init_mbmi(mbmi, curr_mode, mode_def->ref_frame, 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) { - const int txfm_search_done = 1; - update_search_state(&search_state, rd_cost, ctx, &intra_rd_stats, - &intra_rd_stats_y, &intra_rd_stats_uv, mode_enum, x, - txfm_search_done); - } - } - - 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 == THR_INVALID || - 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 == - search_state.best_mbmode.interp_filters.as_filters.y_filter) || - !is_inter_block(&search_state.best_mbmode)); - assert((cm->interp_filter == SWITCHABLE) || - (cm->interp_filter == - search_state.best_mbmode.interp_filters.as_filters.x_filter) || - !is_inter_block(&search_state.best_mbmode)); - - if (!cpi->rc.is_src_frame_alt_ref) - av1_update_rd_thresh_fact(cm, x->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])) { - int_interpfilters filters = av1_broadcast_interp_filter( - av1_unswitchable_filter(cm->interp_filter)); - assert(mbmi->interp_filters.as_int == filters.as_int); - (void)filters; - } - } - - 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 != THR_INVALID); - -#if CONFIG_INTERNAL_STATS - store_coding_context(x, ctx, search_state.best_mode_index, - search_state.best_pred_diff, - search_state.best_mode_skippable); -#else - store_coding_context(x, ctx, search_state.best_pred_diff, - search_state.best_mode_skippable); -#endif // CONFIG_INTERNAL_STATS -} - void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x, int mi_row, int mi_col, @@ -14028,6 +5047,7 @@ void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far) { const AV1_COMMON *const cm = &cpi->common; + const FeatureFlags *const features = &cm->features; MACROBLOCKD *const xd = &x->e_mbd; MB_MODE_INFO *const mbmi = xd->mi[0]; unsigned char segment_id = mbmi->segment_id; @@ -14070,39 +5090,40 @@ void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, mbmi->ref_frame[1] = NONE_FRAME; mbmi->mv[0].as_int = gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]], - cm->allow_high_precision_mv, bsize, mi_col, mi_row, - cm->cur_frame_force_integer_mv) + features->allow_high_precision_mv, bsize, mi_col, + mi_row, features->cur_frame_force_integer_mv) .as_int; mbmi->tx_size = max_txsize_lookup[bsize]; - x->skip = 1; + x->force_skip = 1; mbmi->ref_mv_idx = 0; mbmi->motion_mode = SIMPLE_TRANSLATION; - av1_count_overlappable_neighbors(cm, xd, mi_row, mi_col); + av1_count_overlappable_neighbors(cm, xd); if (is_motion_variation_allowed_bsize(bsize) && !has_second_ref(mbmi)) { int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE]; - mbmi->num_proj_ref = - av1_findSamples(cm, xd, mi_row, mi_col, pts, pts_inref); + mbmi->num_proj_ref = av1_findSamples(cm, xd, pts, pts_inref); // Select the samples according to motion vector difference if (mbmi->num_proj_ref > 1) mbmi->num_proj_ref = av1_selectSamples(&mbmi->mv[0].as_mv, pts, pts_inref, mbmi->num_proj_ref, bsize); } - set_default_interp_filters(mbmi, cm->interp_filter); + const InterpFilter interp_filter = features->interp_filter; + set_default_interp_filters(mbmi, interp_filter); - if (cm->interp_filter != SWITCHABLE) { - best_filter = cm->interp_filter; + if (interp_filter != SWITCHABLE) { + best_filter = interp_filter; } else { best_filter = EIGHTTAP_REGULAR; - if (av1_is_interp_needed(xd) && av1_is_interp_search_needed(xd) && - x->source_variance >= cpi->sf.disable_filter_search_var_thresh) { + if (av1_is_interp_needed(xd) && + x->source_variance >= + cpi->sf.interp_sf.disable_filter_search_var_thresh) { int rs; int best_rs = INT_MAX; for (i = 0; i < SWITCHABLE_FILTERS; ++i) { mbmi->interp_filters = av1_broadcast_interp_filter(i); - rs = av1_get_switchable_rate(cm, x, xd); + rs = av1_get_switchable_rate(x, xd, interp_filter); if (rs < best_rs) { best_rs = rs; best_filter = mbmi->interp_filters.as_filters.y_filter; @@ -14112,7 +5133,7 @@ void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, } // Set the appropriate filter mbmi->interp_filters = av1_broadcast_interp_filter(best_filter); - rate2 += av1_get_switchable_rate(cm, x, xd); + rate2 += av1_get_switchable_rate(x, xd, interp_filter); if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT) rate2 += comp_inter_cost[comp_pred]; @@ -14132,11 +5153,14 @@ void av1_rd_pick_inter_mode_sb_seg_skip(const AV1_COMP *cpi, return; } - assert((cm->interp_filter == SWITCHABLE) || - (cm->interp_filter == mbmi->interp_filters.as_filters.y_filter)); + assert((interp_filter == SWITCHABLE) || + (interp_filter == mbmi->interp_filters.as_filters.y_filter)); - av1_update_rd_thresh_fact(cm, x->thresh_freq_fact, cpi->sf.adaptive_rd_thresh, - bsize, THR_GLOBALMV); + if (cpi->sf.inter_sf.adaptive_rd_thresh) { + av1_update_rd_thresh_fact(cm, x->thresh_freq_fact, + cpi->sf.inter_sf.adaptive_rd_thresh, bsize, + THR_GLOBALMV); + } av1_zero(best_pred_diff); @@ -14155,15 +5179,17 @@ struct calc_target_weighted_pred_ctxt { }; static INLINE void calc_target_weighted_pred_above( - MACROBLOCKD *xd, int rel_mi_col, uint8_t nb_mi_width, MB_MODE_INFO *nb_mi, - void *fun_ctxt, const int num_planes) { + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *nb_mi, void *fun_ctxt, const int num_planes) { (void)nb_mi; (void)num_planes; + (void)rel_mi_row; + (void)dir; struct calc_target_weighted_pred_ctxt *ctxt = (struct calc_target_weighted_pred_ctxt *)fun_ctxt; - const int bw = xd->n4_w << MI_SIZE_LOG2; + const int bw = xd->width << MI_SIZE_LOG2; const uint8_t *const mask1d = av1_get_obmc_mask(ctxt->overlap); int32_t *wsrc = ctxt->x->wsrc_buf + (rel_mi_col * MI_SIZE); @@ -14175,7 +5201,7 @@ static INLINE void calc_target_weighted_pred_above( for (int row = 0; row < ctxt->overlap; ++row) { const uint8_t m0 = mask1d[row]; const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0; - for (int col = 0; col < nb_mi_width * MI_SIZE; ++col) { + for (int col = 0; col < op_mi_size * MI_SIZE; ++col) { wsrc[col] = m1 * tmp[col]; mask[col] = m0; } @@ -14189,7 +5215,7 @@ static INLINE void calc_target_weighted_pred_above( for (int row = 0; row < ctxt->overlap; ++row) { const uint8_t m0 = mask1d[row]; const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0; - for (int col = 0; col < nb_mi_width * MI_SIZE; ++col) { + for (int col = 0; col < op_mi_size * MI_SIZE; ++col) { wsrc[col] = m1 * tmp16[col]; mask[col] = m0; } @@ -14201,15 +5227,17 @@ static INLINE void calc_target_weighted_pred_above( } static INLINE void calc_target_weighted_pred_left( - MACROBLOCKD *xd, int rel_mi_row, uint8_t nb_mi_height, MB_MODE_INFO *nb_mi, - void *fun_ctxt, const int num_planes) { + MACROBLOCKD *xd, int rel_mi_row, int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *nb_mi, void *fun_ctxt, const int num_planes) { (void)nb_mi; (void)num_planes; + (void)rel_mi_col; + (void)dir; struct calc_target_weighted_pred_ctxt *ctxt = (struct calc_target_weighted_pred_ctxt *)fun_ctxt; - const int bw = xd->n4_w << MI_SIZE_LOG2; + const int bw = xd->width << MI_SIZE_LOG2; const uint8_t *const mask1d = av1_get_obmc_mask(ctxt->overlap); int32_t *wsrc = ctxt->x->wsrc_buf + (rel_mi_row * MI_SIZE * bw); @@ -14218,7 +5246,7 @@ static INLINE void calc_target_weighted_pred_left( const int is_hbd = is_cur_buf_hbd(xd); if (!is_hbd) { - for (int row = 0; row < nb_mi_height * MI_SIZE; ++row) { + for (int row = 0; row < op_mi_size * MI_SIZE; ++row) { for (int col = 0; col < ctxt->overlap; ++col) { const uint8_t m0 = mask1d[col]; const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0; @@ -14233,7 +5261,7 @@ static INLINE void calc_target_weighted_pred_left( } else { const uint16_t *tmp16 = CONVERT_TO_SHORTPTR(tmp); - for (int row = 0; row < nb_mi_height * MI_SIZE; ++row) { + for (int row = 0; row < op_mi_size * MI_SIZE; ++row) { for (int col = 0; col < ctxt->overlap; ++col) { const uint8_t m0 = mask1d[col]; const uint8_t m1 = AOM_BLEND_A64_MAX_ALPHA - m0; @@ -14288,18 +5316,18 @@ static INLINE void calc_target_weighted_pred_left( // static AOM_INLINE void calc_target_weighted_pred( const AV1_COMMON *cm, const MACROBLOCK *x, const MACROBLOCKD *xd, - int mi_row, int mi_col, const uint8_t *above, int above_stride, - const uint8_t *left, int left_stride) { + const uint8_t *above, int above_stride, const uint8_t *left, + int left_stride) { const BLOCK_SIZE bsize = xd->mi[0]->sb_type; - const int bw = xd->n4_w << MI_SIZE_LOG2; - const int bh = xd->n4_h << MI_SIZE_LOG2; + const int bw = xd->width << MI_SIZE_LOG2; + const int bh = xd->height << MI_SIZE_LOG2; int32_t *mask_buf = x->mask_buf; int32_t *wsrc_buf = x->wsrc_buf; const int is_hbd = is_cur_buf_hbd(xd); const int src_scale = AOM_BLEND_A64_MAX_ALPHA * AOM_BLEND_A64_MAX_ALPHA; - // plane 0 should not be subsampled + // plane 0 should not be sub-sampled assert(xd->plane[0].subsampling_x == 0); assert(xd->plane[0].subsampling_y == 0); @@ -14312,7 +5340,7 @@ static AOM_INLINE void calc_target_weighted_pred( AOMMIN(block_size_high[bsize], block_size_high[BLOCK_64X64]) >> 1; struct calc_target_weighted_pred_ctxt ctxt = { x, above, above_stride, overlap }; - foreach_overlappable_nb_above(cm, (MACROBLOCKD *)xd, mi_col, + foreach_overlappable_nb_above(cm, (MACROBLOCKD *)xd, max_neighbor_obmc[mi_size_wide_log2[bsize]], calc_target_weighted_pred_above, &ctxt); } @@ -14328,7 +5356,7 @@ static AOM_INLINE void calc_target_weighted_pred( AOMMIN(block_size_wide[bsize], block_size_wide[BLOCK_64X64]) >> 1; struct calc_target_weighted_pred_ctxt ctxt = { x, left, left_stride, overlap }; - foreach_overlappable_nb_left(cm, (MACROBLOCKD *)xd, mi_row, + foreach_overlappable_nb_left(cm, (MACROBLOCKD *)xd, max_neighbor_obmc[mi_size_high_log2[bsize]], calc_target_weighted_pred_left, &ctxt); } diff --git a/media/libaom/src/av1/encoder/rdopt.h b/media/libaom/src/av1/encoder/rdopt.h index d24401bc9e..c7c99ac4bd 100644 --- a/media/libaom/src/av1/encoder/rdopt.h +++ b/media/libaom/src/av1/encoder/rdopt.h @@ -21,45 +21,20 @@ #include "av1/encoder/context_tree.h" #include "av1/encoder/encoder.h" #include "av1/encoder/encodetxb.h" +#include "av1/encoder/rdopt_utils.h" #ifdef __cplusplus extern "C" { #endif -#define MAX_REF_MV_SEARCH 3 -#define INTER_INTRA_RD_THRESH_SCALE 9 -#define INTER_INTRA_RD_THRESH_SHIFT 4 #define COMP_TYPE_RD_THRESH_SCALE 11 #define COMP_TYPE_RD_THRESH_SHIFT 4 +#define MAX_WINNER_MOTION_MODES 10 struct TileInfo; struct macroblock; struct RD_STATS; -#if CONFIG_RD_DEBUG -static INLINE void av1_update_txb_coeff_cost(RD_STATS *rd_stats, int plane, - TX_SIZE tx_size, int blk_row, - int blk_col, int txb_coeff_cost) { - (void)blk_row; - (void)blk_col; - (void)tx_size; - rd_stats->txb_coeff_cost[plane] += txb_coeff_cost; - - { - const int txb_h = tx_size_high_unit[tx_size]; - const int txb_w = tx_size_wide_unit[tx_size]; - int idx, idy; - for (idy = 0; idy < txb_h; ++idy) - for (idx = 0; idx < txb_w; ++idx) - rd_stats->txb_coeff_cost_map[plane][blk_row + idy][blk_col + idx] = 0; - - rd_stats->txb_coeff_cost_map[plane][blk_row][blk_col] = txb_coeff_cost; - } - assert(blk_row < TXB_COEFF_COST_MAP_SIZE); - assert(blk_col < TXB_COEFF_COST_MAP_SIZE); -} -#endif - // Returns the number of colors in 'src'. int av1_count_colors(const uint8_t *src, int stride, int rows, int cols, int *val_count); @@ -67,13 +42,6 @@ int av1_count_colors(const uint8_t *src, int stride, int rows, int cols, int av1_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols, int bit_depth, int *val_count); -#if CONFIG_DIST_8X8 -int64_t av1_dist_8x8(const struct AV1_COMP *const cpi, const MACROBLOCK *x, - const uint8_t *src, int src_stride, const uint8_t *dst, - int dst_stride, const BLOCK_SIZE tx_bsize, int bsw, - int bsh, int visible_w, int visible_h, int qindex); -#endif - static INLINE int av1_cost_skip_txb(MACROBLOCK *x, const TXB_CTX *const txb_ctx, int plane, TX_SIZE tx_size) { const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); @@ -83,32 +51,9 @@ static INLINE int av1_cost_skip_txb(MACROBLOCK *x, const TXB_CTX *const txb_ctx, return coeff_costs->txb_skip_cost[txb_ctx->txb_skip_ctx][1]; } -static INLINE int av1_cost_coeffs(MACROBLOCK *x, int plane, int block, - TX_SIZE tx_size, const TX_TYPE tx_type, - const TXB_CTX *const txb_ctx, - int use_fast_coef_costing, - int reduced_tx_set_used) { -#if TXCOEFF_COST_TIMER - struct aom_usec_timer timer; - aom_usec_timer_start(&timer); -#endif - (void)use_fast_coef_costing; - const int cost = av1_cost_coeffs_txb(x, plane, block, tx_size, tx_type, - txb_ctx, reduced_tx_set_used); -#if TXCOEFF_COST_TIMER - AV1_COMMON *tmp_cm = (AV1_COMMON *)&cpi->common; - aom_usec_timer_mark(&timer); - const int64_t elapsed_time = aom_usec_timer_elapsed(&timer); - tmp_cm->txcoeff_cost_timer += elapsed_time; - ++tmp_cm->txcoeff_cost_count; -#endif - return cost; -} - void av1_rd_pick_intra_mode_sb(const struct AV1_COMP *cpi, 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); + struct RD_STATS *rd_cost, BLOCK_SIZE bsize, + PICK_MODE_CONTEXT *ctx, int64_t best_rd); unsigned int av1_get_sby_perpixel_variance(const struct AV1_COMP *cpi, const struct buf_2d *ref, @@ -119,20 +64,16 @@ unsigned int av1_high_get_sby_perpixel_variance(const struct AV1_COMP *cpi, void av1_rd_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); + struct macroblock *x, struct RD_STATS *rd_cost, + BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, + int64_t best_rd_so_far); -void av1_fast_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_pick_intra_mode(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost, + BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx); 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 macroblock *x, struct RD_STATS *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far); @@ -177,10 +118,11 @@ sobel_xy av1_sobel(const uint8_t *input, int stride, int i, int j, void av1_inter_mode_data_init(struct TileDataEnc *tile_data); void av1_inter_mode_data_fit(TileDataEnc *tile_data, int rdmult); -typedef int64_t (*pick_interinter_mask_type)( - const AV1_COMP *const cpi, MACROBLOCK *x, const BLOCK_SIZE bsize, - const uint8_t *const p0, const uint8_t *const p1, - const int16_t *const residual1, const int16_t *const diff10); +#if !CONFIG_REALTIME_ONLY +static INLINE int coded_to_superres_mi(int mi_col, int denom) { + return (mi_col * denom + SCALE_NUMERATOR / 2) / SCALE_NUMERATOR; +} +#endif static INLINE int av1_encoder_get_relative_dist(const OrderHintInfo *oh, int a, int b) { @@ -192,7 +134,7 @@ static INLINE int av1_encoder_get_relative_dist(const OrderHintInfo *oh, int a, // This function will return number of mi's in a superblock. static INLINE int av1_get_sb_mi_size(const AV1_COMMON *const cm) { - const int mi_alloc_size_1d = mi_size_wide[cm->mi_alloc_bsize]; + const int mi_alloc_size_1d = mi_size_wide[cm->mi_params.mi_alloc_bsize]; int sb_mi_rows = (mi_size_wide[cm->seq_params.sb_size] + mi_alloc_size_1d - 1) / mi_alloc_size_1d; @@ -215,238 +157,86 @@ static INLINE void av1_copy_usable_ref_mv_stack_and_weight( USABLE_REF_MV_STACK_SIZE * sizeof(xd->ref_mv_stack[0][0])); } -static TX_MODE select_tx_mode( - const AV1_COMP *cpi, const TX_SIZE_SEARCH_METHOD tx_size_search_method) { - if (cpi->common.coded_lossless) return ONLY_4X4; - if (tx_size_search_method == USE_LARGESTALL) - return TX_MODE_LARGEST; - else if (tx_size_search_method == USE_FULL_RD || - tx_size_search_method == USE_FAST_RD) - return TX_MODE_SELECT; - else - return cpi->common.tx_mode; -} +// This function prunes the mode if either of the reference frame falls in the +// pruning list +static INLINE int prune_ref(const MV_REFERENCE_FRAME *const ref_frame, + const OrderHintInfo *const order_hint_info, + const unsigned int *const ref_display_order_hint, + const unsigned int frame_display_order_hint, + const int *ref_frame_list) { + for (int i = 0; i < 2; i++) { + if (ref_frame_list[i] == NONE_FRAME) continue; -static INLINE TX_MODE get_eval_tx_mode(const AV1_COMP *cpi, - MODE_EVAL_TYPE eval_type) { - TX_MODE tx_mode; - if (cpi->sf.enable_winner_mode_for_tx_size_srch) - tx_mode = select_tx_mode(cpi, cpi->tx_size_search_methods[eval_type]); - else - tx_mode = select_tx_mode(cpi, cpi->tx_size_search_methods[DEFAULT_EVAL]); - - return tx_mode; -} - -static INLINE void set_tx_size_search_method( - const struct AV1_COMP *cpi, MACROBLOCK *x, - int enable_winner_mode_for_tx_size_srch, int is_winner_mode) { - // Populate transform size search method/transform mode appropriately - x->tx_size_search_method = cpi->tx_size_search_methods[DEFAULT_EVAL]; - if (enable_winner_mode_for_tx_size_srch) { - if (is_winner_mode) - x->tx_size_search_method = cpi->tx_size_search_methods[WINNER_MODE_EVAL]; - else - x->tx_size_search_method = cpi->tx_size_search_methods[MODE_EVAL]; + if (ref_frame[0] == ref_frame_list[i] || + ref_frame[1] == ref_frame_list[i]) { + if (av1_encoder_get_relative_dist( + order_hint_info, + ref_display_order_hint[ref_frame_list[i] - LAST_FRAME], + frame_display_order_hint) < 0) + return 1; + } } - x->tx_mode = select_tx_mode(cpi, x->tx_size_search_method); -} - -static INLINE void set_tx_domain_dist_params( - const struct AV1_COMP *cpi, MACROBLOCK *x, - int enable_winner_mode_for_tx_domain_dist, int is_winner_mode) { - if (!enable_winner_mode_for_tx_domain_dist) { - x->use_transform_domain_distortion = - cpi->use_transform_domain_distortion[DEFAULT_EVAL]; - x->tx_domain_dist_threshold = cpi->tx_domain_dist_threshold[DEFAULT_EVAL]; - return; - } - - if (is_winner_mode) { - x->use_transform_domain_distortion = - cpi->use_transform_domain_distortion[WINNER_MODE_EVAL]; - x->tx_domain_dist_threshold = - cpi->tx_domain_dist_threshold[WINNER_MODE_EVAL]; - } else { - x->use_transform_domain_distortion = - cpi->use_transform_domain_distortion[MODE_EVAL]; - x->tx_domain_dist_threshold = cpi->tx_domain_dist_threshold[MODE_EVAL]; - } -} - -// Checks the conditions to enable winner mode processing -static INLINE int is_winner_mode_processing_enabled( - const struct AV1_COMP *cpi, MB_MODE_INFO *const mbmi, - const PREDICTION_MODE best_mode) { - const SPEED_FEATURES *sf = &cpi->sf; - - // TODO(any): Move block independent condition checks to frame level - if (is_inter_block(mbmi)) { - if (is_inter_mode(best_mode) && - sf->tx_type_search.fast_inter_tx_type_search && - !cpi->oxcf.use_inter_dct_only) - return 1; - } else { - if (sf->tx_type_search.fast_intra_tx_type_search && - !cpi->oxcf.use_intra_default_tx_only && !cpi->oxcf.use_intra_dct_only) - return 1; - } - - // Check speed feature related to winner mode processing - if (sf->enable_winner_mode_for_coeff_opt && - cpi->optimize_seg_arr[mbmi->segment_id] != NO_TRELLIS_OPT && - cpi->optimize_seg_arr[mbmi->segment_id] != FINAL_PASS_TRELLIS_OPT) - return 1; - if (sf->enable_winner_mode_for_tx_size_srch) return 1; - return 0; } -// This function sets mode parameters for different mode evaluation stages -static INLINE void set_mode_eval_params(const struct AV1_COMP *cpi, - MACROBLOCK *x, - MODE_EVAL_TYPE mode_eval_type) { - const SPEED_FEATURES *sf = &cpi->sf; - - switch (mode_eval_type) { - case DEFAULT_EVAL: - x->use_default_inter_tx_type = 0; - x->use_default_intra_tx_type = 0; - // Set default transform domain distortion type - set_tx_domain_dist_params(cpi, x, 0, 0); - - // Get default threshold for R-D optimization of coefficients - x->coeff_opt_dist_threshold = - get_rd_opt_coeff_thresh(cpi->coeff_opt_dist_threshold, 0, 0); - // Set default transform size search method - set_tx_size_search_method(cpi, x, 0, 0); - break; - case MODE_EVAL: - x->use_default_intra_tx_type = - (cpi->sf.tx_type_search.fast_intra_tx_type_search || - cpi->oxcf.use_intra_default_tx_only); - x->use_default_inter_tx_type = - cpi->sf.tx_type_search.fast_inter_tx_type_search; - - // Set transform domain distortion type for mode evaluation - set_tx_domain_dist_params( - cpi, x, sf->enable_winner_mode_for_use_tx_domain_dist, 0); - - // Get threshold for R-D optimization of coefficients during mode - // evaluation - x->coeff_opt_dist_threshold = - get_rd_opt_coeff_thresh(cpi->coeff_opt_dist_threshold, - sf->enable_winner_mode_for_coeff_opt, 0); - // Set the transform size search method for mode evaluation - set_tx_size_search_method(cpi, x, sf->enable_winner_mode_for_tx_size_srch, - 0); - break; - case WINNER_MODE_EVAL: - x->use_default_inter_tx_type = 0; - x->use_default_intra_tx_type = 0; - - // Set transform domain distortion type for winner mode evaluation - set_tx_domain_dist_params( - cpi, x, sf->enable_winner_mode_for_use_tx_domain_dist, 1); - - // Get threshold for R-D optimization of coefficients for winner mode - // evaluation - x->coeff_opt_dist_threshold = - get_rd_opt_coeff_thresh(cpi->coeff_opt_dist_threshold, - sf->enable_winner_mode_for_coeff_opt, 1); - // Set the transform size search method for winner mode evaluation - set_tx_size_search_method(cpi, x, sf->enable_winner_mode_for_tx_size_srch, - 1); - break; - default: assert(0); - } -} - static INLINE int prune_ref_by_selective_ref_frame( - const AV1_COMP *const cpi, const MV_REFERENCE_FRAME *const ref_frame, - const unsigned int *const ref_display_order_hint, - const unsigned int cur_frame_display_order_hint) { + const AV1_COMP *const cpi, const MACROBLOCK *const x, + const MV_REFERENCE_FRAME *const ref_frame, + const unsigned int *const ref_display_order_hint) { const SPEED_FEATURES *const sf = &cpi->sf; - if (sf->selective_ref_frame) { - const AV1_COMMON *const cm = &cpi->common; - const OrderHintInfo *const order_hint_info = - &cm->seq_params.order_hint_info; - const int comp_pred = ref_frame[1] > INTRA_FRAME; - if (sf->selective_ref_frame >= 2 || - (sf->selective_ref_frame == 1 && comp_pred)) { - if (ref_frame[0] == LAST3_FRAME || ref_frame[1] == LAST3_FRAME) { - if (av1_encoder_get_relative_dist( - order_hint_info, - ref_display_order_hint[LAST3_FRAME - LAST_FRAME], - ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME]) <= 0) - return 1; - } - if (ref_frame[0] == LAST2_FRAME || ref_frame[1] == LAST2_FRAME) { - if (av1_encoder_get_relative_dist( - order_hint_info, - ref_display_order_hint[LAST2_FRAME - LAST_FRAME], - ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME]) <= 0) - return 1; - } + if (!sf->inter_sf.selective_ref_frame) return 0; + + const AV1_COMMON *const cm = &cpi->common; + const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info; + const int comp_pred = ref_frame[1] > INTRA_FRAME; + + if (sf->inter_sf.selective_ref_frame >= 2 || + (sf->inter_sf.selective_ref_frame == 1 && comp_pred)) { + int ref_frame_list[2] = { LAST3_FRAME, LAST2_FRAME }; + + if (x != NULL) { + if (x->search_ref_frame[LAST3_FRAME]) ref_frame_list[0] = NONE_FRAME; + if (x->search_ref_frame[LAST2_FRAME]) ref_frame_list[1] = NONE_FRAME; } - // One-sided compound is used only when all reference frames are one-sided. - if (sf->selective_ref_frame >= 2 && comp_pred && !cpi->all_one_sided_refs) { - unsigned int ref_offsets[2]; - for (int i = 0; i < 2; ++i) { - const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame[i]); - assert(buf != NULL); - ref_offsets[i] = buf->display_order_hint; - } - const int ref0_dist = av1_encoder_get_relative_dist( - order_hint_info, ref_offsets[0], cur_frame_display_order_hint); - const int ref1_dist = av1_encoder_get_relative_dist( - order_hint_info, ref_offsets[1], cur_frame_display_order_hint); - if ((ref0_dist <= 0 && ref1_dist <= 0) || - (ref0_dist > 0 && ref1_dist > 0)) { - return 1; - } - } - - if (sf->selective_ref_frame >= 3) { - if (ref_frame[0] == ALTREF2_FRAME || ref_frame[1] == ALTREF2_FRAME) - if (av1_encoder_get_relative_dist( - order_hint_info, - ref_display_order_hint[ALTREF2_FRAME - LAST_FRAME], - cur_frame_display_order_hint) < 0) - return 1; - if (ref_frame[0] == BWDREF_FRAME || ref_frame[1] == BWDREF_FRAME) - if (av1_encoder_get_relative_dist( - order_hint_info, - ref_display_order_hint[BWDREF_FRAME - LAST_FRAME], - cur_frame_display_order_hint) < 0) - return 1; - } - - if (sf->selective_ref_frame >= 4 && comp_pred) { - // 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 & av1_ref_frame_flag_list[BWDREF_FRAME])) { - // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references. - const int arf2_dist = av1_encoder_get_relative_dist( - order_hint_info, ref_display_order_hint[ALTREF2_FRAME - LAST_FRAME], - cur_frame_display_order_hint); - const int bwd_dist = av1_encoder_get_relative_dist( - order_hint_info, ref_display_order_hint[BWDREF_FRAME - LAST_FRAME], - cur_frame_display_order_hint); - if (arf2_dist > 0 && bwd_dist > 0 && bwd_dist <= arf2_dist) { - // Drop ALTREF2_FRAME as a reference if BWDREF_FRAME is a closer - // reference to the current frame than ALTREF2_FRAME - assert(get_ref_frame_buf(cm, ALTREF2_FRAME) != NULL); - assert(get_ref_frame_buf(cm, BWDREF_FRAME) != NULL); - return 1; - } - } - } + if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint, + ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME], + ref_frame_list)) + return 1; } + + if (sf->inter_sf.selective_ref_frame >= 3) { + int ref_frame_list[2] = { ALTREF2_FRAME, BWDREF_FRAME }; + + if (x != NULL) { + if (x->search_ref_frame[ALTREF2_FRAME]) ref_frame_list[0] = NONE_FRAME; + if (x->search_ref_frame[BWDREF_FRAME]) ref_frame_list[1] = NONE_FRAME; + } + + if (prune_ref(ref_frame, order_hint_info, ref_display_order_hint, + ref_display_order_hint[LAST_FRAME - LAST_FRAME], + ref_frame_list)) + return 1; + } + return 0; } + +// This function will copy the best reference mode information from +// MB_MODE_INFO_EXT to MB_MODE_INFO_EXT_FRAME. +static INLINE void av1_copy_mbmi_ext_to_mbmi_ext_frame( + MB_MODE_INFO_EXT_FRAME *mbmi_ext_best, + const MB_MODE_INFO_EXT *const mbmi_ext, uint8_t ref_frame_type) { + memcpy(mbmi_ext_best->ref_mv_stack, mbmi_ext->ref_mv_stack[ref_frame_type], + sizeof(mbmi_ext->ref_mv_stack[USABLE_REF_MV_STACK_SIZE])); + memcpy(mbmi_ext_best->weight, mbmi_ext->weight[ref_frame_type], + sizeof(mbmi_ext->weight[USABLE_REF_MV_STACK_SIZE])); + mbmi_ext_best->mode_context = mbmi_ext->mode_context[ref_frame_type]; + mbmi_ext_best->ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type]; + memcpy(mbmi_ext_best->global_mvs, mbmi_ext->global_mvs, + sizeof(mbmi_ext->global_mvs)); +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/av1/encoder/rdopt_data_defs.h b/media/libaom/src/av1/encoder/rdopt_data_defs.h new file mode 100644 index 0000000000..ca7ef810f3 --- /dev/null +++ b/media/libaom/src/av1/encoder/rdopt_data_defs.h @@ -0,0 +1,294 @@ +/* + * 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_RDOPT_DATA_DEFS_H_ +#define AOM_AV1_ENCODER_RDOPT_DATA_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +static const THR_MODES intra_to_mode_idx[INTRA_MODE_NUM] = { + THR_DC, // DC_PRED, + THR_V_PRED, // V_PRED, + THR_H_PRED, // H_PRED, + THR_D45_PRED, // D45_PRED, + THR_D135_PRED, // D135_PRED, + THR_D113_PRED, // D113_PRED, + THR_D157_PRED, // D157_PRED, + THR_D203_PRED, // D203_PRED, + THR_D67_PRED, // D67_PRED, + THR_SMOOTH, // SMOOTH_PRED, + THR_SMOOTH_V, // SMOOTH_V_PRED, + THR_SMOOTH_H, // SMOOTH_H_PRED, + THR_PAETH, // PAETH_PRED, +}; + +/* clang-format off */ +static const THR_MODES single_inter_to_mode_idx[SINGLE_INTER_MODE_NUM] + [REF_FRAMES] = { + // NEARESTMV, + { THR_INVALID, THR_NEARESTMV, THR_NEARESTL2, THR_NEARESTL3, + THR_NEARESTG, THR_NEARESTB, THR_NEARESTA2, THR_NEARESTA, }, + // NEARMV, + { THR_INVALID, THR_NEARMV, THR_NEARL2, THR_NEARL3, + THR_NEARG, THR_NEARB, THR_NEARA2, THR_NEARA, }, + // GLOBALMV, + { THR_INVALID, THR_GLOBALMV, THR_GLOBALL2, THR_GLOBALL3, + THR_GLOBALG, THR_GLOBALB, THR_GLOBALA2, THR_GLOBALA, }, + // NEWMV, + { THR_INVALID, THR_NEWMV, THR_NEWL2, THR_NEWL3, + THR_NEWG, THR_NEWB, THR_NEWA2, THR_NEWA, }, +}; +/* clang-format on */ + +/* clang-format off */ +static const THR_MODES comp_inter_to_mode_idx[COMP_INTER_MODE_NUM][REF_FRAMES] + [REF_FRAMES] = { + // NEAREST_NEARESTMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEAREST_NEARESTLL2, THR_COMP_NEAREST_NEARESTLL3, + THR_COMP_NEAREST_NEARESTLG, THR_COMP_NEAREST_NEARESTLB, + THR_COMP_NEAREST_NEARESTLA2, THR_COMP_NEAREST_NEARESTLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEARESTL2B, + THR_COMP_NEAREST_NEARESTL2A2, THR_COMP_NEAREST_NEARESTL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEARESTL3B, + THR_COMP_NEAREST_NEARESTL3A2, THR_COMP_NEAREST_NEARESTL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEARESTGB, + THR_COMP_NEAREST_NEARESTGA2, THR_COMP_NEAREST_NEARESTGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEARESTBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEAR_NEARMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEAR_NEARLL2, THR_COMP_NEAR_NEARLL3, + THR_COMP_NEAR_NEARLG, THR_COMP_NEAR_NEARLB, + THR_COMP_NEAR_NEARLA2, THR_COMP_NEAR_NEARLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEARL2B, + THR_COMP_NEAR_NEARL2A2, THR_COMP_NEAR_NEARL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEARL3B, + THR_COMP_NEAR_NEARL3A2, THR_COMP_NEAR_NEARL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEARGB, + THR_COMP_NEAR_NEARGA2, THR_COMP_NEAR_NEARGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEARBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEAREST_NEWMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEAREST_NEWLL2, THR_COMP_NEAREST_NEWLL3, + THR_COMP_NEAREST_NEWLG, THR_COMP_NEAREST_NEWLB, + THR_COMP_NEAREST_NEWLA2, THR_COMP_NEAREST_NEWLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEWL2B, + THR_COMP_NEAREST_NEWL2A2, THR_COMP_NEAREST_NEWL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEWL3B, + THR_COMP_NEAREST_NEWL3A2, THR_COMP_NEAREST_NEWL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEWGB, + THR_COMP_NEAREST_NEWGA2, THR_COMP_NEAREST_NEWGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAREST_NEWBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEW_NEARESTMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEW_NEARESTLL2, THR_COMP_NEW_NEARESTLL3, + THR_COMP_NEW_NEARESTLG, THR_COMP_NEW_NEARESTLB, + THR_COMP_NEW_NEARESTLA2, THR_COMP_NEW_NEARESTLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARESTL2B, + THR_COMP_NEW_NEARESTL2A2, THR_COMP_NEW_NEARESTL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARESTL3B, + THR_COMP_NEW_NEARESTL3A2, THR_COMP_NEW_NEARESTL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARESTGB, + THR_COMP_NEW_NEARESTGA2, THR_COMP_NEW_NEARESTGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARESTBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEAR_NEWMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEAR_NEWLL2, THR_COMP_NEAR_NEWLL3, + THR_COMP_NEAR_NEWLG, THR_COMP_NEAR_NEWLB, + THR_COMP_NEAR_NEWLA2, THR_COMP_NEAR_NEWLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEWL2B, + THR_COMP_NEAR_NEWL2A2, THR_COMP_NEAR_NEWL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEWL3B, + THR_COMP_NEAR_NEWL3A2, THR_COMP_NEAR_NEWL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEWGB, + THR_COMP_NEAR_NEWGA2, THR_COMP_NEAR_NEWGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEAR_NEWBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEW_NEARMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEW_NEARLL2, THR_COMP_NEW_NEARLL3, + THR_COMP_NEW_NEARLG, THR_COMP_NEW_NEARLB, + THR_COMP_NEW_NEARLA2, THR_COMP_NEW_NEARLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARL2B, + THR_COMP_NEW_NEARL2A2, THR_COMP_NEW_NEARL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARL3B, + THR_COMP_NEW_NEARL3A2, THR_COMP_NEW_NEARL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARGB, + THR_COMP_NEW_NEARGA2, THR_COMP_NEW_NEARGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEARBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // GLOBAL_GLOBALMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_GLOBAL_GLOBALLL2, THR_COMP_GLOBAL_GLOBALLL3, + THR_COMP_GLOBAL_GLOBALLG, THR_COMP_GLOBAL_GLOBALLB, + THR_COMP_GLOBAL_GLOBALLA2, THR_COMP_GLOBAL_GLOBALLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_GLOBAL_GLOBALL2B, + THR_COMP_GLOBAL_GLOBALL2A2, THR_COMP_GLOBAL_GLOBALL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_GLOBAL_GLOBALL3B, + THR_COMP_GLOBAL_GLOBALL3A2, THR_COMP_GLOBAL_GLOBALL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_GLOBAL_GLOBALGB, + THR_COMP_GLOBAL_GLOBALGA2, THR_COMP_GLOBAL_GLOBALGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_GLOBAL_GLOBALBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, + // NEW_NEWMV, + { + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, + THR_COMP_NEW_NEWLL2, THR_COMP_NEW_NEWLL3, + THR_COMP_NEW_NEWLG, THR_COMP_NEW_NEWLB, + THR_COMP_NEW_NEWLA2, THR_COMP_NEW_NEWLA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEWL2B, + THR_COMP_NEW_NEWL2A2, THR_COMP_NEW_NEWL2A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEWL3B, + THR_COMP_NEW_NEWL3A2, THR_COMP_NEW_NEWL3A, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEWGB, + THR_COMP_NEW_NEWGA2, THR_COMP_NEW_NEWGA, }, + { THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, + THR_INVALID, THR_COMP_NEW_NEWBA, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + { THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, THR_INVALID, + THR_INVALID, THR_INVALID, THR_INVALID, }, + }, +}; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_RDOPT_DATA_DEFS_H_ diff --git a/media/libaom/src/av1/encoder/rdopt_utils.h b/media/libaom/src/av1/encoder/rdopt_utils.h new file mode 100644 index 0000000000..53b410a224 --- /dev/null +++ b/media/libaom/src/av1/encoder/rdopt_utils.h @@ -0,0 +1,652 @@ +/* + * 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_RDOPT_UTILS_H_ +#define AOM_AV1_ENCODER_RDOPT_UTILS_H_ + +#include "aom/aom_integer.h" +#include "av1/encoder/block.h" +#include "av1/common/cfl.h" +#include "av1/common/pred_common.h" +#include "av1/encoder/rdopt_data_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_REF_MV_SEARCH 3 +#define INTER_INTRA_RD_THRESH_SCALE 9 +#define INTER_INTRA_RD_THRESH_SHIFT 4 + +typedef struct { + PREDICTION_MODE mode; + MV_REFERENCE_FRAME ref_frame[2]; +} MODE_DEFINITION; + +// This array defines the mapping from the enums in THR_MODES to the actual +// prediction modes and refrence frames +static const MODE_DEFINITION av1_mode_defs[MAX_MODES] = { + { NEARESTMV, { LAST_FRAME, NONE_FRAME } }, + { NEARESTMV, { LAST2_FRAME, NONE_FRAME } }, + { NEARESTMV, { LAST3_FRAME, NONE_FRAME } }, + { NEARESTMV, { BWDREF_FRAME, NONE_FRAME } }, + { NEARESTMV, { ALTREF2_FRAME, NONE_FRAME } }, + { NEARESTMV, { ALTREF_FRAME, NONE_FRAME } }, + { NEARESTMV, { GOLDEN_FRAME, NONE_FRAME } }, + + { NEWMV, { LAST_FRAME, NONE_FRAME } }, + { NEWMV, { LAST2_FRAME, NONE_FRAME } }, + { NEWMV, { LAST3_FRAME, NONE_FRAME } }, + { NEWMV, { BWDREF_FRAME, NONE_FRAME } }, + { NEWMV, { ALTREF2_FRAME, NONE_FRAME } }, + { NEWMV, { ALTREF_FRAME, NONE_FRAME } }, + { NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, + + { NEARMV, { LAST_FRAME, NONE_FRAME } }, + { NEARMV, { LAST2_FRAME, NONE_FRAME } }, + { NEARMV, { LAST3_FRAME, NONE_FRAME } }, + { NEARMV, { BWDREF_FRAME, NONE_FRAME } }, + { NEARMV, { ALTREF2_FRAME, NONE_FRAME } }, + { NEARMV, { ALTREF_FRAME, NONE_FRAME } }, + { NEARMV, { GOLDEN_FRAME, NONE_FRAME } }, + + { GLOBALMV, { LAST_FRAME, NONE_FRAME } }, + { GLOBALMV, { LAST2_FRAME, NONE_FRAME } }, + { GLOBALMV, { LAST3_FRAME, NONE_FRAME } }, + { GLOBALMV, { BWDREF_FRAME, NONE_FRAME } }, + { GLOBALMV, { ALTREF2_FRAME, NONE_FRAME } }, + { GLOBALMV, { ALTREF_FRAME, NONE_FRAME } }, + { GLOBALMV, { GOLDEN_FRAME, NONE_FRAME } }, + + // TODO(zoeliu): May need to reconsider the order on the modes to check + + { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEAREST_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + + { NEAREST_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAREST_NEARESTMV, { LAST_FRAME, LAST3_FRAME } }, + { NEAREST_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAREST_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, ALTREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF_FRAME } }, + + { NEAR_NEARMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { LAST2_FRAME, ALTREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF_FRAME } }, + + { NEAR_NEARMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { LAST3_FRAME, ALTREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF_FRAME } }, + + { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, BWDREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, BWDREF_FRAME } }, + + { NEAR_NEARMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEW_NEARESTMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEAREST_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEW_NEARMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEAR_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, + { NEW_NEWMV, { LAST2_FRAME, BWDREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST2_FRAME, BWDREF_FRAME } }, + + { NEAR_NEARMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEW_NEARESTMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEAREST_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEW_NEARMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEAR_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, + { NEW_NEWMV, { LAST3_FRAME, BWDREF_FRAME } }, + { GLOBAL_GLOBALMV, { LAST3_FRAME, BWDREF_FRAME } }, + + { NEAR_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEW_NEARESTMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEAREST_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEW_NEARMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEAR_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { NEW_NEWMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + { GLOBAL_GLOBALMV, { GOLDEN_FRAME, BWDREF_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, ALTREF2_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, ALTREF2_FRAME } }, + + { NEAR_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEW_NEARESTMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEW_NEARMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEAR_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { NEW_NEWMV, { LAST2_FRAME, ALTREF2_FRAME } }, + { GLOBAL_GLOBALMV, { LAST2_FRAME, ALTREF2_FRAME } }, + + { NEAR_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEW_NEARESTMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEW_NEARMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEAR_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { NEW_NEWMV, { LAST3_FRAME, ALTREF2_FRAME } }, + { GLOBAL_GLOBALMV, { LAST3_FRAME, ALTREF2_FRAME } }, + + { NEAR_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { NEW_NEARESTMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { NEAREST_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { NEW_NEARMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { NEAR_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { NEW_NEWMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + { GLOBAL_GLOBALMV, { GOLDEN_FRAME, ALTREF2_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, LAST2_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, LAST2_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, LAST2_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, LAST3_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, LAST3_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, LAST3_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, LAST3_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, LAST3_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, LAST3_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, LAST3_FRAME } }, + + { NEAR_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEARESTMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAREST_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEARMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEAR_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { NEW_NEWMV, { LAST_FRAME, GOLDEN_FRAME } }, + { GLOBAL_GLOBALMV, { LAST_FRAME, GOLDEN_FRAME } }, + + { NEAR_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEARESTMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEAREST_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEARMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEAR_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { NEW_NEWMV, { BWDREF_FRAME, ALTREF_FRAME } }, + { GLOBAL_GLOBALMV, { BWDREF_FRAME, ALTREF_FRAME } }, + + // intra modes + { DC_PRED, { INTRA_FRAME, NONE_FRAME } }, + { PAETH_PRED, { INTRA_FRAME, NONE_FRAME } }, + { SMOOTH_PRED, { INTRA_FRAME, NONE_FRAME } }, + { SMOOTH_V_PRED, { INTRA_FRAME, NONE_FRAME } }, + { SMOOTH_H_PRED, { INTRA_FRAME, NONE_FRAME } }, + { H_PRED, { INTRA_FRAME, NONE_FRAME } }, + { V_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D135_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D203_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D157_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D67_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D113_PRED, { INTRA_FRAME, NONE_FRAME } }, + { D45_PRED, { INTRA_FRAME, NONE_FRAME } }, +}; + +static AOM_INLINE void restore_dst_buf(MACROBLOCKD *xd, const BUFFER_SET dst, + const int num_planes) { + for (int i = 0; i < num_planes; i++) { + xd->plane[i].dst.buf = dst.plane[i]; + xd->plane[i].dst.stride = dst.stride[i]; + } +} + +/* clang-format on */ +// Calculate rd threshold based on ref best rd and relevant scaling factors +static AOM_INLINE int64_t get_rd_thresh_from_best_rd(int64_t ref_best_rd, + int mul_factor, + int div_factor) { + int64_t rd_thresh = ref_best_rd; + if (div_factor != 0) { + rd_thresh = ref_best_rd < (div_factor * (INT64_MAX / mul_factor)) + ? ((ref_best_rd / div_factor) * mul_factor) + : INT64_MAX; + } + return rd_thresh; +} + +static AOM_INLINE THR_MODES +get_prediction_mode_idx(PREDICTION_MODE this_mode, MV_REFERENCE_FRAME ref_frame, + MV_REFERENCE_FRAME second_ref_frame) { + if (this_mode < INTRA_MODE_END) { + assert(ref_frame == INTRA_FRAME); + assert(second_ref_frame == NONE_FRAME); + return intra_to_mode_idx[this_mode - INTRA_MODE_START]; + } + if (this_mode >= SINGLE_INTER_MODE_START && + this_mode < SINGLE_INTER_MODE_END) { + assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME)); + return single_inter_to_mode_idx[this_mode - SINGLE_INTER_MODE_START] + [ref_frame]; + } + if (this_mode >= COMP_INTER_MODE_START && this_mode < COMP_INTER_MODE_END) { + assert((ref_frame > INTRA_FRAME) && (ref_frame <= ALTREF_FRAME)); + assert((second_ref_frame > INTRA_FRAME) && + (second_ref_frame <= ALTREF_FRAME)); + return comp_inter_to_mode_idx[this_mode - COMP_INTER_MODE_START][ref_frame] + [second_ref_frame]; + } + assert(0); + return THR_INVALID; +} + +static AOM_INLINE int inter_mode_data_block_idx(BLOCK_SIZE bsize) { + if (bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 || + bsize == BLOCK_4X16 || bsize == BLOCK_16X4) { + return -1; + } + return 1; +} + +// Get transform block visible dimensions cropped to the MI units. +static AOM_INLINE void get_txb_dimensions(const MACROBLOCKD *xd, int plane, + BLOCK_SIZE plane_bsize, int blk_row, + int blk_col, BLOCK_SIZE tx_bsize, + int *width, int *height, + int *visible_width, + int *visible_height) { + assert(tx_bsize <= plane_bsize); + const int txb_height = block_size_high[tx_bsize]; + const int txb_width = block_size_wide[tx_bsize]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + + // TODO(aconverse@google.com): Investigate using crop_width/height here rather + // than the MI size + if (xd->mb_to_bottom_edge >= 0) { + *visible_height = txb_height; + } else { + const int block_height = block_size_high[plane_bsize]; + const int block_rows = + (xd->mb_to_bottom_edge >> (3 + pd->subsampling_y)) + block_height; + *visible_height = + clamp(block_rows - (blk_row << MI_SIZE_LOG2), 0, txb_height); + } + if (height) *height = txb_height; + + if (xd->mb_to_right_edge >= 0) { + *visible_width = txb_width; + } else { + const int block_width = block_size_wide[plane_bsize]; + const int block_cols = + (xd->mb_to_right_edge >> (3 + pd->subsampling_x)) + block_width; + *visible_width = + clamp(block_cols - (blk_col << MI_SIZE_LOG2), 0, txb_width); + } + if (width) *width = txb_width; +} + +static AOM_INLINE int bsize_to_num_blk(BLOCK_SIZE bsize) { + int num_blk = 1 << (num_pels_log2_lookup[bsize] - 2 * MI_SIZE_LOG2); + return num_blk; +} + +static INLINE int check_txfm_eval(MACROBLOCK *const x, BLOCK_SIZE bsize, + int64_t best_skip_rd, int64_t skip_rd, + int level, int is_luma_only) { + int eval_txfm = 1; + // Derive aggressiveness factor for gating the transform search + // Lower value indicates more aggressiveness. Be more conservative (high + // value) for (i) low quantizers (ii) regions where prediction is poor + const int scale[5] = { INT_MAX, 4, 3, 3, 2 }; + const int qslope = 2 * (!is_luma_only); + int aggr_factor = 1; + if (!is_luma_only) { + aggr_factor = AOMMAX( + 1, ((MAXQ - x->qindex) * qslope + QINDEX_RANGE / 2) >> QINDEX_BITS); + } + if (best_skip_rd > + (x->source_variance << (num_pels_log2_lookup[bsize] + RDDIV_BITS))) + aggr_factor *= scale[level]; + // For level setting 1, be more conservative for luma only case even when + // prediction is good + else if ((level <= 1) && !is_luma_only) + aggr_factor *= 2; + + // Be more conservative for luma only cases (called from compound type rd) + // since best_skip_rd is computed after and skip_rd is computed (with 8-bit + // prediction signals blended for WEDGE/DIFFWTD rather than 16-bit) before + // interpolation filter search + const int luma_mul[5] = { INT_MAX, 32, 29, 20, 17 }; + int mul_factor = is_luma_only ? luma_mul[level] : 16; + int64_t rd_thresh = + (best_skip_rd == INT64_MAX) + ? best_skip_rd + : (int64_t)(best_skip_rd * aggr_factor * mul_factor >> 4); + if (skip_rd > rd_thresh) eval_txfm = 0; + return eval_txfm; +} + +static TX_MODE select_tx_mode( + const AV1_COMMON *cm, const TX_SIZE_SEARCH_METHOD tx_size_search_method) { + if (cm->features.coded_lossless) return ONLY_4X4; + if (tx_size_search_method == USE_LARGESTALL) { + return TX_MODE_LARGEST; + } else { + assert(tx_size_search_method == USE_FULL_RD || + tx_size_search_method == USE_FAST_RD); + return TX_MODE_SELECT; + } +} +// Checks the conditions to enable winner mode processing +static INLINE int is_winner_mode_processing_enabled( + const struct AV1_COMP *cpi, MB_MODE_INFO *const mbmi, + const PREDICTION_MODE best_mode) { + const SPEED_FEATURES *sf = &cpi->sf; + + // TODO(any): Move block independent condition checks to frame level + if (is_inter_block(mbmi)) { + if (is_inter_mode(best_mode) && + sf->tx_sf.tx_type_search.fast_inter_tx_type_search && + !cpi->oxcf.use_inter_dct_only) + return 1; + } else { + if (sf->tx_sf.tx_type_search.fast_intra_tx_type_search && + !cpi->oxcf.use_intra_default_tx_only && !cpi->oxcf.use_intra_dct_only) + return 1; + } + + // Check speed feature related to winner mode processing + if (sf->winner_mode_sf.enable_winner_mode_for_coeff_opt && + cpi->optimize_seg_arr[mbmi->segment_id] != NO_TRELLIS_OPT && + cpi->optimize_seg_arr[mbmi->segment_id] != FINAL_PASS_TRELLIS_OPT) + return 1; + if (sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch) return 1; + + return 0; +} + +static INLINE void set_tx_size_search_method( + const AV1_COMMON *cm, const WinnerModeParams *winner_mode_params, + MACROBLOCK *x, int enable_winner_mode_for_tx_size_srch, + int is_winner_mode) { + // Populate transform size search method/transform mode appropriately + x->tx_size_search_method = + winner_mode_params->tx_size_search_methods[DEFAULT_EVAL]; + if (enable_winner_mode_for_tx_size_srch) { + if (is_winner_mode) + x->tx_size_search_method = + winner_mode_params->tx_size_search_methods[WINNER_MODE_EVAL]; + else + x->tx_size_search_method = + winner_mode_params->tx_size_search_methods[MODE_EVAL]; + } + x->tx_mode_search_type = select_tx_mode(cm, x->tx_size_search_method); +} + +static INLINE void set_tx_type_prune(const SPEED_FEATURES *sf, MACROBLOCK *x, + int enable_winner_mode_tx_type_pruning, + int is_winner_mode) { + // Populate prune transform mode appropriately + x->prune_mode = sf->tx_sf.tx_type_search.prune_mode; + if (enable_winner_mode_tx_type_pruning) { + if (is_winner_mode) + x->prune_mode = NO_PRUNE; + else + x->prune_mode = PRUNE_2D_AGGRESSIVE; + } +} + +static INLINE void set_tx_domain_dist_params( + const WinnerModeParams *winner_mode_params, MACROBLOCK *x, + int enable_winner_mode_for_tx_domain_dist, int is_winner_mode) { + if (!enable_winner_mode_for_tx_domain_dist) { + x->use_transform_domain_distortion = + winner_mode_params->use_transform_domain_distortion[DEFAULT_EVAL]; + x->tx_domain_dist_threshold = + winner_mode_params->tx_domain_dist_threshold[DEFAULT_EVAL]; + return; + } + + if (is_winner_mode) { + x->use_transform_domain_distortion = + winner_mode_params->use_transform_domain_distortion[WINNER_MODE_EVAL]; + x->tx_domain_dist_threshold = + winner_mode_params->tx_domain_dist_threshold[WINNER_MODE_EVAL]; + } else { + x->use_transform_domain_distortion = + winner_mode_params->use_transform_domain_distortion[MODE_EVAL]; + x->tx_domain_dist_threshold = + winner_mode_params->tx_domain_dist_threshold[MODE_EVAL]; + } +} + +// This function sets mode parameters for different mode evaluation stages +static INLINE void set_mode_eval_params(const struct AV1_COMP *cpi, + MACROBLOCK *x, + MODE_EVAL_TYPE mode_eval_type) { + const AV1_COMMON *cm = &cpi->common; + const SPEED_FEATURES *sf = &cpi->sf; + const WinnerModeParams *winner_mode_params = &cpi->winner_mode_params; + + switch (mode_eval_type) { + case DEFAULT_EVAL: + x->use_default_inter_tx_type = 0; + x->use_default_intra_tx_type = 0; + x->predict_skip_level = + winner_mode_params->predict_skip_level[DEFAULT_EVAL]; + // Set default transform domain distortion type + set_tx_domain_dist_params(winner_mode_params, x, 0, 0); + + // Get default threshold for R-D optimization of coefficients + x->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh( + winner_mode_params->coeff_opt_dist_threshold, 0, 0); + // Set default transform size search method + set_tx_size_search_method(cm, winner_mode_params, x, 0, 0); + // Set default transform type prune + set_tx_type_prune(sf, x, 0, 0); + break; + case MODE_EVAL: + x->use_default_intra_tx_type = + (cpi->sf.tx_sf.tx_type_search.fast_intra_tx_type_search || + cpi->oxcf.use_intra_default_tx_only); + x->use_default_inter_tx_type = + cpi->sf.tx_sf.tx_type_search.fast_inter_tx_type_search; + x->predict_skip_level = winner_mode_params->predict_skip_level[MODE_EVAL]; + + // Set transform domain distortion type for mode evaluation + set_tx_domain_dist_params( + winner_mode_params, x, + sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 0); + + // Get threshold for R-D optimization of coefficients during mode + // evaluation + x->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh( + winner_mode_params->coeff_opt_dist_threshold, + sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 0); + // Set the transform size search method for mode evaluation + set_tx_size_search_method( + cm, winner_mode_params, x, + sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 0); + // Set transform type prune for mode evaluation + set_tx_type_prune( + sf, x, sf->tx_sf.tx_type_search.enable_winner_mode_tx_type_pruning, + 0); + break; + case WINNER_MODE_EVAL: + x->use_default_inter_tx_type = 0; + x->use_default_intra_tx_type = 0; + x->predict_skip_level = + winner_mode_params->predict_skip_level[WINNER_MODE_EVAL]; + + // Set transform domain distortion type for winner mode evaluation + set_tx_domain_dist_params( + winner_mode_params, x, + sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist, 1); + + // Get threshold for R-D optimization of coefficients for winner mode + // evaluation + x->coeff_opt_dist_threshold = get_rd_opt_coeff_thresh( + winner_mode_params->coeff_opt_dist_threshold, + sf->winner_mode_sf.enable_winner_mode_for_coeff_opt, 1); + // Set the transform size search method for winner mode evaluation + set_tx_size_search_method( + cm, winner_mode_params, x, + sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch, 1); + // Set default transform type prune mode for winner mode evaluation + set_tx_type_prune( + sf, x, sf->tx_sf.tx_type_search.enable_winner_mode_tx_type_pruning, + 1); + + // Reset hash state for winner mode processing. Winner mode and subsequent + // transform/mode evaluations (palette/IntraBC) cann't reuse old data as + // the decisions would have been sub-optimal + // TODO(any): Move the evaluation of palette/IntraBC modes before winner + // mode is processed and clean-up the code below + reset_hash_records(x, cpi->sf.tx_sf.use_inter_txb_hash); + + break; + default: assert(0); + } +} + +// Similar to store_cfl_required(), but for use during the RDO process, +// where we haven't yet determined whether this block uses CfL. +static INLINE CFL_ALLOWED_TYPE store_cfl_required_rdo(const AV1_COMMON *cm, + const MACROBLOCK *x) { + const MACROBLOCKD *xd = &x->e_mbd; + + if (cm->seq_params.monochrome || !xd->is_chroma_ref) return CFL_DISALLOWED; + + if (!xd->is_chroma_ref) { + // For non-chroma-reference blocks, we should always store the luma pixels, + // in case the corresponding chroma-reference block uses CfL. + // Note that this can only happen for block sizes which are <8 on + // their shortest side, as otherwise they would be chroma reference + // blocks. + return CFL_ALLOWED; + } + + // For chroma reference blocks, we should store data in the encoder iff we're + // allowed to try out CfL. + return is_cfl_allowed(xd); +} + +static AOM_INLINE void init_sbuv_mode(MB_MODE_INFO *const mbmi) { + mbmi->uv_mode = UV_DC_PRED; + mbmi->palette_mode_info.palette_size[1] = 0; +} + +// Store best mode stats for winner mode processing +static INLINE void store_winner_mode_stats( + const AV1_COMMON *const cm, MACROBLOCK *x, MB_MODE_INFO *mbmi, + RD_STATS *rd_cost, RD_STATS *rd_cost_y, RD_STATS *rd_cost_uv, + THR_MODES mode_index, uint8_t *color_map, BLOCK_SIZE bsize, int64_t this_rd, + int enable_multiwinner_mode_process, int txfm_search_done) { + WinnerModeStats *winner_mode_stats = x->winner_mode_stats; + int mode_idx = 0; + int is_palette_mode = mbmi->palette_mode_info.palette_size[PLANE_TYPE_Y] > 0; + // Mode stat is not required when multiwinner mode processing is disabled + if (!enable_multiwinner_mode_process) return; + // Ignore mode with maximum rd + if (this_rd == INT64_MAX) return; + // TODO(any): Winner mode processing is currently not applicable for palette + // mode in Inter frames. Clean-up the following code, once support is added + if (!frame_is_intra_only(cm) && is_palette_mode) return; + + const int max_winner_mode_count = frame_is_intra_only(cm) + ? MAX_WINNER_MODE_COUNT_INTRA + : MAX_WINNER_MODE_COUNT_INTER; + assert(x->winner_mode_count >= 0 && + x->winner_mode_count <= max_winner_mode_count); + + if (x->winner_mode_count) { + // Find the mode which has higher rd cost than this_rd + for (mode_idx = 0; mode_idx < x->winner_mode_count; mode_idx++) + if (winner_mode_stats[mode_idx].rd > this_rd) break; + + if (mode_idx == max_winner_mode_count) { + // No mode has higher rd cost than this_rd + return; + } else if (mode_idx < max_winner_mode_count - 1) { + // Create a slot for current mode and move others to the next slot + memmove( + &winner_mode_stats[mode_idx + 1], &winner_mode_stats[mode_idx], + (max_winner_mode_count - mode_idx - 1) * sizeof(*winner_mode_stats)); + } + } + // Add a mode stat for winner mode processing + winner_mode_stats[mode_idx].mbmi = *mbmi; + winner_mode_stats[mode_idx].rd = this_rd; + winner_mode_stats[mode_idx].mode_index = mode_index; + + // Update rd stats required for inter frame + if (!frame_is_intra_only(cm) && rd_cost && rd_cost_y && rd_cost_uv) { + const MACROBLOCKD *xd = &x->e_mbd; + const int skip_ctx = av1_get_skip_context(xd); + const int is_intra_mode = av1_mode_defs[mode_index].mode < INTRA_MODE_END; + const int skip = mbmi->skip && !is_intra_mode; + + winner_mode_stats[mode_idx].rd_cost = *rd_cost; + if (txfm_search_done) { + winner_mode_stats[mode_idx].rate_y = + rd_cost_y->rate + x->skip_cost[skip_ctx][rd_cost->skip || skip]; + winner_mode_stats[mode_idx].rate_uv = rd_cost_uv->rate; + } + } + + if (color_map) { + // Store color_index_map for palette mode + const MACROBLOCKD *const xd = &x->e_mbd; + int block_width, block_height; + av1_get_block_dimensions(bsize, AOM_PLANE_Y, xd, &block_width, + &block_height, NULL, NULL); + memcpy(winner_mode_stats[mode_idx].color_index_map, color_map, + block_width * block_height * sizeof(color_map[0])); + } + + x->winner_mode_count = + AOMMIN(x->winner_mode_count + 1, max_winner_mode_count); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_RDOPT_UTILS_H_ diff --git a/media/libaom/src/av1/encoder/reconinter_enc.c b/media/libaom/src/av1/encoder/reconinter_enc.c index e987ff76a7..231b02091e 100644 --- a/media/libaom/src/av1/encoder/reconinter_enc.c +++ b/media/libaom/src/av1/encoder/reconinter_enc.c @@ -20,400 +20,201 @@ #include "aom/aom_integer.h" #include "aom_dsp/blend.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/mvref_common.h" +#include "av1/common/obmc.h" #include "av1/common/reconinter.h" #include "av1/common/reconintra.h" -#include "av1/common/onyxc_int.h" -#include "av1/common/obmc.h" #include "av1/encoder/reconinter_enc.h" -static INLINE void calc_subpel_params( - MACROBLOCKD *xd, const struct scale_factors *const sf, const MV mv, - int plane, const int pre_x, const int pre_y, int x, int y, - struct buf_2d *const pre_buf, uint8_t **pre, SubpelParams *subpel_params, - int bw, int bh) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - const int is_scaled = av1_is_scaled(sf); - if (is_scaled) { - int ssx = pd->subsampling_x; - int ssy = pd->subsampling_y; - int orig_pos_y = (pre_y + y) << SUBPEL_BITS; - orig_pos_y += mv.row * (1 << (1 - ssy)); - int orig_pos_x = (pre_x + x) << SUBPEL_BITS; - orig_pos_x += mv.col * (1 << (1 - ssx)); - int pos_y = sf->scale_value_y(orig_pos_y, sf); - int pos_x = sf->scale_value_x(orig_pos_x, sf); - pos_x += SCALE_EXTRA_OFF; - pos_y += SCALE_EXTRA_OFF; +static void enc_calc_subpel_params(const MV *const src_mv, + InterPredParams *const inter_pred_params, + MACROBLOCKD *xd, int mi_x, int mi_y, int ref, + uint8_t **pre, SubpelParams *subpel_params, + int *src_stride) { + // These are part of the function signature to use this function through a + // function pointer. See typedef of 'CalcSubpelParamsFunc'. + (void)xd; + (void)mi_x; + (void)mi_y; + (void)ref; - const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); - const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); - const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) - << SCALE_SUBPEL_BITS; - const int right = (pre_buf->width + AOM_INTERP_EXTEND) << SCALE_SUBPEL_BITS; - pos_y = clamp(pos_y, top, bottom); - pos_x = clamp(pos_x, left, right); + const struct scale_factors *sf = inter_pred_params->scale_factors; - *pre = pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + - (pos_x >> SCALE_SUBPEL_BITS); - subpel_params->subpel_x = pos_x & SCALE_SUBPEL_MASK; - subpel_params->subpel_y = pos_y & SCALE_SUBPEL_MASK; - subpel_params->xs = sf->x_step_q4; - subpel_params->ys = sf->y_step_q4; - } else { - const MV mv_q4 = clamp_mv_to_umv_border_sb( - xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); - subpel_params->xs = subpel_params->ys = SCALE_SUBPEL_SHIFTS; - subpel_params->subpel_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; - subpel_params->subpel_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS; - *pre = pre_buf->buf0 + - (pre_y + y + (mv_q4.row >> SUBPEL_BITS)) * pre_buf->stride + - (pre_x + x + (mv_q4.col >> SUBPEL_BITS)); - } + struct buf_2d *pre_buf = &inter_pred_params->ref_frame_buf; + int ssx = inter_pred_params->subsampling_x; + int ssy = inter_pred_params->subsampling_y; + int orig_pos_y = inter_pred_params->pix_row << SUBPEL_BITS; + orig_pos_y += src_mv->row * (1 << (1 - ssy)); + int orig_pos_x = inter_pred_params->pix_col << SUBPEL_BITS; + orig_pos_x += src_mv->col * (1 << (1 - ssx)); + int pos_y = sf->scale_value_y(orig_pos_y, sf); + int pos_x = sf->scale_value_x(orig_pos_x, sf); + pos_x += SCALE_EXTRA_OFF; + pos_y += SCALE_EXTRA_OFF; + + const int top = -AOM_LEFT_TOP_MARGIN_SCALED(ssy); + const int left = -AOM_LEFT_TOP_MARGIN_SCALED(ssx); + const int bottom = (pre_buf->height + AOM_INTERP_EXTEND) << SCALE_SUBPEL_BITS; + const int right = (pre_buf->width + AOM_INTERP_EXTEND) << SCALE_SUBPEL_BITS; + pos_y = clamp(pos_y, top, bottom); + pos_x = clamp(pos_x, left, right); + + subpel_params->subpel_x = pos_x & SCALE_SUBPEL_MASK; + subpel_params->subpel_y = pos_y & SCALE_SUBPEL_MASK; + subpel_params->xs = sf->x_step_q4; + subpel_params->ys = sf->y_step_q4; + *pre = pre_buf->buf0 + (pos_y >> SCALE_SUBPEL_BITS) * pre_buf->stride + + (pos_x >> SCALE_SUBPEL_BITS); + *src_stride = pre_buf->stride; } -static INLINE void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, - int plane, const MB_MODE_INFO *mi, - int build_for_obmc, int bw, int bh, - int mi_x, int mi_y) { - struct macroblockd_plane *const pd = &xd->plane[plane]; - int is_compound = has_second_ref(mi); - int ref; - const int is_intrabc = is_intrabc_block(mi); - assert(IMPLIES(is_intrabc, !is_compound)); - int is_global[2] = { 0, 0 }; - for (ref = 0; ref < 1 + is_compound; ++ref) { - const WarpedMotionParams *const wm = &xd->global_motion[mi->ref_frame[ref]]; - is_global[ref] = is_global_mv_block(mi, wm->wmtype); - } - - const BLOCK_SIZE bsize = mi->sb_type; - const int ss_x = pd->subsampling_x; - const int ss_y = pd->subsampling_y; - int sub8x8_inter = (block_size_wide[bsize] < 8 && ss_x) || - (block_size_high[bsize] < 8 && ss_y); - - if (is_intrabc) sub8x8_inter = 0; - - // For sub8x8 chroma blocks, we may be covering more than one luma block's - // worth of pixels. Thus (mi_x, mi_y) may not be the correct coordinates for - // the top-left corner of the prediction source - the correct top-left corner - // is at (pre_x, pre_y). - const int row_start = - (block_size_high[bsize] == 4) && ss_y && !build_for_obmc ? -1 : 0; - const int col_start = - (block_size_wide[bsize] == 4) && ss_x && !build_for_obmc ? -1 : 0; - const int pre_x = (mi_x + MI_SIZE * col_start) >> ss_x; - const int pre_y = (mi_y + MI_SIZE * row_start) >> ss_y; - - sub8x8_inter = sub8x8_inter && !build_for_obmc; - if (sub8x8_inter) { - for (int row = row_start; row <= 0 && sub8x8_inter; ++row) { - for (int col = col_start; col <= 0; ++col) { - const MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; - if (!is_inter_block(this_mbmi)) sub8x8_inter = 0; - if (is_intrabc_block(this_mbmi)) sub8x8_inter = 0; - } - } - } - - if (sub8x8_inter) { - // block size - const int b4_w = block_size_wide[bsize] >> ss_x; - const int b4_h = block_size_high[bsize] >> ss_y; - const BLOCK_SIZE plane_bsize = scale_chroma_bsize(bsize, ss_x, ss_y); - const int b8_w = block_size_wide[plane_bsize] >> ss_x; - const int b8_h = block_size_high[plane_bsize] >> ss_y; - assert(!is_compound); - - const struct buf_2d orig_pred_buf[2] = { pd->pre[0], pd->pre[1] }; - - int row = row_start; - for (int y = 0; y < b8_h; y += b4_h) { - int col = col_start; - for (int x = 0; x < b8_w; x += b4_w) { - MB_MODE_INFO *this_mbmi = xd->mi[row * xd->mi_stride + col]; - is_compound = has_second_ref(this_mbmi); - int tmp_dst_stride = 8; - assert(bw < 8 || bh < 8); - InterPredParams inter_pred_params; - inter_pred_params.conv_params = get_conv_params_no_round( - 0, plane, xd->tmp_conv_dst, tmp_dst_stride, is_compound, xd->bd); - inter_pred_params.conv_params.use_dist_wtd_comp_avg = 0; - struct buf_2d *const dst_buf = &pd->dst; - uint8_t *dst = dst_buf->buf + dst_buf->stride * y + x; - - ref = 0; - const RefCntBuffer *ref_buf = - get_ref_frame_buf(cm, this_mbmi->ref_frame[ref]); - const struct scale_factors *ref_scale_factors = - get_ref_scale_factors_const(cm, this_mbmi->ref_frame[ref]); - - pd->pre[ref].buf0 = - (plane == 1) ? ref_buf->buf.u_buffer : ref_buf->buf.v_buffer; - pd->pre[ref].buf = - pd->pre[ref].buf0 + scaled_buffer_offset(pre_x, pre_y, - ref_buf->buf.uv_stride, - ref_scale_factors); - pd->pre[ref].width = ref_buf->buf.uv_crop_width; - pd->pre[ref].height = ref_buf->buf.uv_crop_height; - pd->pre[ref].stride = ref_buf->buf.uv_stride; - - const struct scale_factors *const sf = - is_intrabc ? &cm->sf_identity : ref_scale_factors; - struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; - - const MV mv = this_mbmi->mv[ref].as_mv; - - uint8_t *pre; - SubpelParams subpel_params; - - calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, x, y, pre_buf, &pre, - &subpel_params, bw, bh); - inter_pred_params.conv_params.do_average = ref; - - av1_init_inter_params( - &inter_pred_params, b4_w, b4_h, (mi_y >> pd->subsampling_y) + y, - (mi_x >> pd->subsampling_x) + x, pd->subsampling_x, - pd->subsampling_y, xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, - this_mbmi->interp_filters); - av1_make_inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, - &inter_pred_params, &subpel_params); - - ++col; - } - ++row; - } - - for (ref = 0; ref < 2; ++ref) pd->pre[ref] = orig_pred_buf[ref]; - return; - } - - { - InterPredParams inter_pred_params; - inter_pred_params.conv_params = get_conv_params_no_round( - 0, plane, xd->tmp_conv_dst, MAX_SB_SIZE, is_compound, xd->bd); - av1_dist_wtd_comp_weight_assign( - cm, mi, 0, &inter_pred_params.conv_params.fwd_offset, - &inter_pred_params.conv_params.bck_offset, - &inter_pred_params.conv_params.use_dist_wtd_comp_avg, is_compound); - - struct buf_2d *const dst_buf = &pd->dst; - uint8_t *const dst = dst_buf->buf; - for (ref = 0; ref < 1 + is_compound; ++ref) { - const struct scale_factors *const sf = - is_intrabc ? &cm->sf_identity : xd->block_ref_scale_factors[ref]; - struct buf_2d *const pre_buf = is_intrabc ? dst_buf : &pd->pre[ref]; - const MV mv = mi->mv[ref].as_mv; - - uint8_t *pre; - SubpelParams subpel_params; - calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, 0, 0, pre_buf, &pre, - &subpel_params, bw, bh); - - WarpTypesAllowed warp_types; - warp_types.global_warp_allowed = is_global[ref]; - warp_types.local_warp_allowed = mi->motion_mode == WARPED_CAUSAL; - - av1_init_inter_params( - &inter_pred_params, bw, bh, mi_y >> pd->subsampling_y, - mi_x >> pd->subsampling_x, pd->subsampling_x, pd->subsampling_y, - xd->bd, is_cur_buf_hbd(xd), mi->use_intrabc, sf, mi->interp_filters); - - if (!build_for_obmc) - av1_init_warp_params(&inter_pred_params, &pd->pre[ref], &warp_types, - ref, xd, mi); - - if (ref && is_masked_compound_type(mi->interinter_comp.type)) { - // masked compound type has its own average mechanism - inter_pred_params.conv_params.do_average = 0; - av1_make_masked_inter_predictor(pre, pre_buf->stride, dst, - dst_buf->stride, &inter_pred_params, - &subpel_params, bw, bh, plane, xd); - } else { - inter_pred_params.conv_params.do_average = ref; - av1_make_inter_predictor(pre, pre_buf->stride, dst, dst_buf->stride, - &inter_pred_params, &subpel_params); - } - } - } +void av1_enc_build_one_inter_predictor(uint8_t *dst, int dst_stride, + const MV *src_mv, + InterPredParams *inter_pred_params) { + av1_build_one_inter_predictor(dst, dst_stride, src_mv, inter_pred_params, + NULL /* xd */, 0 /* mi_x */, 0 /* mi_y */, + 0 /* ref */, enc_calc_subpel_params); } -static void build_inter_predictors_for_plane(const AV1_COMMON *cm, - MACROBLOCKD *xd, int mi_row, - int mi_col, const BUFFER_SET *ctx, - BLOCK_SIZE bsize, int plane_idx) { - const struct macroblockd_plane *pd = &xd->plane[plane_idx]; - if (!is_chroma_reference(mi_row, mi_col, bsize, pd->subsampling_x, - pd->subsampling_y)) - return; +static void enc_build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, + int plane, const MB_MODE_INFO *mi, + int bw, int bh, int mi_x, int mi_y) { + av1_build_inter_predictors(cm, xd, plane, mi, 0 /* build_for_obmc */, bw, bh, + mi_x, mi_y, enc_calc_subpel_params); +} +void av1_enc_build_inter_predictor_y(MACROBLOCKD *xd, int mi_row, int mi_col) { const int mi_x = mi_col * MI_SIZE; const int mi_y = mi_row * MI_SIZE; - build_inter_predictors(cm, xd, plane_idx, xd->mi[0], 0, pd->width, pd->height, - mi_x, mi_y); + struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; + InterPredParams inter_pred_params; - if (is_interintra_pred(xd->mi[0])) { - BUFFER_SET default_ctx = { { NULL, NULL, NULL }, { 0, 0, 0 } }; - if (!ctx) { - default_ctx.plane[plane_idx] = xd->plane[plane_idx].dst.buf; - default_ctx.stride[plane_idx] = xd->plane[plane_idx].dst.stride; - ctx = &default_ctx; - } - av1_build_interintra_predictors_sbp(cm, xd, xd->plane[plane_idx].dst.buf, - xd->plane[plane_idx].dst.stride, ctx, - plane_idx, bsize); - } + struct buf_2d *const dst_buf = &pd->dst; + uint8_t *const dst = dst_buf->buf; + const MV mv = xd->mi[0]->mv[0].as_mv; + const struct scale_factors *const sf = xd->block_ref_scale_factors[0]; + + av1_init_inter_params(&inter_pred_params, pd->width, pd->height, mi_y, mi_x, + pd->subsampling_x, pd->subsampling_y, xd->bd, + is_cur_buf_hbd(xd), false, sf, pd->pre, + xd->mi[0]->interp_filters); + + inter_pred_params.conv_params = get_conv_params_no_round( + 0, AOM_PLANE_Y, xd->tmp_conv_dst, MAX_SB_SIZE, false, xd->bd); + + inter_pred_params.conv_params.use_dist_wtd_comp_avg = 0; + av1_enc_build_one_inter_predictor(dst, dst_buf->stride, &mv, + &inter_pred_params); } void av1_enc_build_inter_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, const BUFFER_SET *ctx, BLOCK_SIZE bsize, int plane_from, int plane_to) { - for (int plane_idx = plane_from; plane_idx <= plane_to; ++plane_idx) { - build_inter_predictors_for_plane(cm, xd, mi_row, mi_col, ctx, bsize, - plane_idx); + for (int plane = plane_from; plane <= plane_to; ++plane) { + if (plane && !xd->is_chroma_ref) break; + const int mi_x = mi_col * MI_SIZE; + const int mi_y = mi_row * MI_SIZE; + enc_build_inter_predictors(cm, xd, plane, xd->mi[0], xd->plane[plane].width, + xd->plane[plane].height, mi_x, mi_y); + + if (is_interintra_pred(xd->mi[0])) { + BUFFER_SET default_ctx = { + { xd->plane[0].dst.buf, xd->plane[1].dst.buf, xd->plane[2].dst.buf }, + { xd->plane[0].dst.stride, xd->plane[1].dst.stride, + xd->plane[2].dst.stride } + }; + if (!ctx) { + ctx = &default_ctx; + } + av1_build_interintra_predictor(cm, xd, xd->plane[plane].dst.buf, + xd->plane[plane].dst.stride, ctx, plane, + bsize); + } } } -void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, - int dst_stride, const MV *src_mv, int x, int y, - InterPredParams *inter_pred_params) { - const MV mv_q4 = { - inter_pred_params->subsampling_y ? src_mv->row : src_mv->row * 2, - inter_pred_params->subsampling_x ? src_mv->col : src_mv->col * 2 - }; - - MV32 mv = av1_scale_mv(&mv_q4, x, y, inter_pred_params->scale_factors); - mv.col += SCALE_EXTRA_OFF; - mv.row += SCALE_EXTRA_OFF; - - const SubpelParams subpel_params = { - inter_pred_params->scale_factors->x_step_q4, - inter_pred_params->scale_factors->y_step_q4, mv.col & SCALE_SUBPEL_MASK, - mv.row & SCALE_SUBPEL_MASK - }; - src += (mv.row >> SCALE_SUBPEL_BITS) * src_stride + - (mv.col >> SCALE_SUBPEL_BITS); - - av1_make_inter_predictor(src, src_stride, dst, dst_stride, inter_pred_params, - &subpel_params); -} - -static INLINE void build_prediction_by_above_pred( - MACROBLOCKD *xd, int rel_mi_col, uint8_t above_mi_width, - MB_MODE_INFO *above_mbmi, void *fun_ctxt, const int num_planes) { +static INLINE void build_obmc_prediction(MACROBLOCKD *xd, int rel_mi_row, + int rel_mi_col, uint8_t op_mi_size, + int dir, MB_MODE_INFO *above_mbmi, + void *fun_ctxt, const int num_planes) { struct build_prediction_ctxt *ctxt = (struct build_prediction_ctxt *)fun_ctxt; - const int above_mi_col = ctxt->mi_col + rel_mi_col; - int mi_x, mi_y; - MB_MODE_INFO backup_mbmi = *above_mbmi; + av1_setup_address_for_obmc(xd, rel_mi_row, rel_mi_col, above_mbmi, ctxt, + num_planes); - av1_setup_build_prediction_by_above_pred(xd, rel_mi_col, above_mi_width, - &backup_mbmi, ctxt, num_planes); - mi_x = above_mi_col << MI_SIZE_LOG2; - mi_y = ctxt->mi_row << MI_SIZE_LOG2; + const int mi_x = (xd->mi_col + rel_mi_col) << MI_SIZE_LOG2; + const int mi_y = (xd->mi_row + rel_mi_row) << MI_SIZE_LOG2; const BLOCK_SIZE bsize = xd->mi[0]->sb_type; + InterPredParams inter_pred_params; + for (int j = 0; j < num_planes; ++j) { const struct macroblockd_plane *pd = &xd->plane[j]; - int bw = (above_mi_width * MI_SIZE) >> pd->subsampling_x; - int bh = clamp(block_size_high[bsize] >> (pd->subsampling_y + 1), 4, - block_size_high[BLOCK_64X64] >> (pd->subsampling_y + 1)); + int bw = 0, bh = 0; - if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 0)) continue; - build_inter_predictors(ctxt->cm, xd, j, &backup_mbmi, 1, bw, bh, mi_x, - mi_y); + if (dir) { + // prepare left reference block size + bw = clamp(block_size_wide[bsize] >> (pd->subsampling_x + 1), 4, + block_size_wide[BLOCK_64X64] >> (pd->subsampling_x + 1)); + bh = (op_mi_size << MI_SIZE_LOG2) >> pd->subsampling_y; + } else { + // prepare above reference block size + bw = (op_mi_size * MI_SIZE) >> pd->subsampling_x; + bh = clamp(block_size_high[bsize] >> (pd->subsampling_y + 1), 4, + block_size_high[BLOCK_64X64] >> (pd->subsampling_y + 1)); + } + + if (av1_skip_u4x4_pred_in_obmc(bsize, pd, dir)) continue; + + const struct buf_2d *const pre_buf = &pd->pre[0]; + const MV mv = above_mbmi->mv[0].as_mv; + + av1_init_inter_params(&inter_pred_params, bw, bh, mi_y >> pd->subsampling_y, + mi_x >> pd->subsampling_x, pd->subsampling_x, + pd->subsampling_y, xd->bd, is_cur_buf_hbd(xd), 0, + xd->block_ref_scale_factors[0], pre_buf, + above_mbmi->interp_filters); + inter_pred_params.conv_params = get_conv_params(0, j, xd->bd); + + av1_enc_build_one_inter_predictor(pd->dst.buf, pd->dst.stride, &mv, + &inter_pred_params); } } void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]) { if (!xd->up_available) return; - - // Adjust mb_to_bottom_edge to have the correct value for the OBMC - // prediction block. This is half the height of the original block, - // except for 128-wide blocks, where we only use a height of 32. - int this_height = xd->n4_h * MI_SIZE; - int pred_height = AOMMIN(this_height / 2, 32); - xd->mb_to_bottom_edge += (this_height - pred_height) * 8; - - struct build_prediction_ctxt ctxt = { cm, mi_row, - mi_col, tmp_buf, + struct build_prediction_ctxt ctxt = { cm, tmp_buf, tmp_width, tmp_height, tmp_stride, xd->mb_to_right_edge }; BLOCK_SIZE bsize = xd->mi[0]->sb_type; - foreach_overlappable_nb_above(cm, xd, mi_col, + foreach_overlappable_nb_above(cm, xd, max_neighbor_obmc[mi_size_wide_log2[bsize]], - build_prediction_by_above_pred, &ctxt); - - xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8); - xd->mb_to_right_edge = ctxt.mb_to_far_edge; - xd->mb_to_bottom_edge -= (this_height - pred_height) * 8; -} - -static INLINE void build_prediction_by_left_pred( - MACROBLOCKD *xd, int rel_mi_row, uint8_t left_mi_height, - MB_MODE_INFO *left_mbmi, void *fun_ctxt, const int num_planes) { - struct build_prediction_ctxt *ctxt = (struct build_prediction_ctxt *)fun_ctxt; - const int left_mi_row = ctxt->mi_row + rel_mi_row; - int mi_x, mi_y; - MB_MODE_INFO backup_mbmi = *left_mbmi; - - av1_setup_build_prediction_by_left_pred(xd, rel_mi_row, left_mi_height, - &backup_mbmi, ctxt, num_planes); - mi_x = ctxt->mi_col << MI_SIZE_LOG2; - mi_y = left_mi_row << MI_SIZE_LOG2; - const BLOCK_SIZE bsize = xd->mi[0]->sb_type; - - for (int j = 0; j < num_planes; ++j) { - const struct macroblockd_plane *pd = &xd->plane[j]; - int bw = clamp(block_size_wide[bsize] >> (pd->subsampling_x + 1), 4, - block_size_wide[BLOCK_64X64] >> (pd->subsampling_x + 1)); - int bh = (left_mi_height << MI_SIZE_LOG2) >> pd->subsampling_y; - - if (av1_skip_u4x4_pred_in_obmc(bsize, pd, 1)) continue; - build_inter_predictors(ctxt->cm, xd, j, &backup_mbmi, 1, bw, bh, mi_x, - mi_y); - } + build_obmc_prediction, &ctxt); } void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]) { if (!xd->left_available) return; - - // Adjust mb_to_right_edge to have the correct value for the OBMC - // prediction block. This is half the width of the original block, - // except for 128-wide blocks, where we only use a width of 32. - int this_width = xd->n4_w * MI_SIZE; - int pred_width = AOMMIN(this_width / 2, 32); - xd->mb_to_right_edge += (this_width - pred_width) * 8; - - struct build_prediction_ctxt ctxt = { cm, mi_row, - mi_col, tmp_buf, + struct build_prediction_ctxt ctxt = { cm, tmp_buf, tmp_width, tmp_height, tmp_stride, xd->mb_to_bottom_edge }; BLOCK_SIZE bsize = xd->mi[0]->sb_type; - foreach_overlappable_nb_left(cm, xd, mi_row, + foreach_overlappable_nb_left(cm, xd, max_neighbor_obmc[mi_size_high_log2[bsize]], - build_prediction_by_left_pred, &ctxt); - - xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8); - xd->mb_to_right_edge -= (this_width - pred_width) * 8; - xd->mb_to_bottom_edge = ctxt.mb_to_far_edge; + build_obmc_prediction, &ctxt); } -void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col) { +void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd) { const int num_planes = av1_num_planes(cm); uint8_t *dst_buf1[MAX_MB_PLANE], *dst_buf2[MAX_MB_PLANE]; int dst_stride1[MAX_MB_PLANE] = { MAX_SB_SIZE, MAX_SB_SIZE, MAX_SB_SIZE }; @@ -443,22 +244,26 @@ void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, dst_buf2[1] = xd->tmp_obmc_bufs[1] + MAX_SB_SQUARE; dst_buf2[2] = xd->tmp_obmc_bufs[1] + MAX_SB_SQUARE * 2; } - av1_build_prediction_by_above_preds(cm, xd, mi_row, mi_col, dst_buf1, - dst_width1, dst_height1, dst_stride1); - av1_build_prediction_by_left_preds(cm, xd, mi_row, mi_col, dst_buf2, - dst_width2, dst_height2, dst_stride2); + + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + av1_build_prediction_by_above_preds(cm, xd, dst_buf1, dst_width1, dst_height1, + dst_stride1); + av1_build_prediction_by_left_preds(cm, xd, dst_buf2, dst_width2, dst_height2, + dst_stride2); av1_setup_dst_planes(xd->plane, xd->mi[0]->sb_type, &cm->cur_frame->buf, mi_row, mi_col, 0, num_planes); - av1_build_obmc_inter_prediction(cm, xd, mi_row, mi_col, dst_buf1, dst_stride1, - dst_buf2, dst_stride2); + av1_build_obmc_inter_prediction(cm, xd, dst_buf1, dst_stride1, dst_buf2, + dst_stride2); } void av1_build_inter_predictors_for_planes_single_buf( - MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane_from, int plane_to, int mi_row, - int mi_col, int ref, uint8_t *ext_dst[3], int ext_dst_stride[3]) { + MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane_from, int plane_to, int ref, + uint8_t *ext_dst[3], int ext_dst_stride[3]) { assert(bsize < BLOCK_SIZES_ALL); const MB_MODE_INFO *mi = xd->mi[0]; - int plane; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; const int mi_x = mi_col * MI_SIZE; const int mi_y = mi_row * MI_SIZE; WarpTypesAllowed warp_types; @@ -466,7 +271,7 @@ void av1_build_inter_predictors_for_planes_single_buf( warp_types.global_warp_allowed = is_global_mv_block(mi, wm->wmtype); warp_types.local_warp_allowed = mi->motion_mode == WARPED_CAUSAL; - for (plane = plane_from; plane <= plane_to; ++plane) { + for (int plane = plane_from; plane <= plane_to; ++plane) { const struct macroblockd_plane *pd = &xd->plane[plane]; const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); @@ -475,21 +280,19 @@ void av1_build_inter_predictors_for_planes_single_buf( InterPredParams inter_pred_params; - av1_init_inter_params(&inter_pred_params, bw, bh, mi_y, mi_x, - pd->subsampling_x, pd->subsampling_y, xd->bd, - is_cur_buf_hbd(xd), 0, - xd->block_ref_scale_factors[ref], mi->interp_filters); + av1_init_inter_params(&inter_pred_params, bw, bh, mi_y >> pd->subsampling_y, + mi_x >> pd->subsampling_x, pd->subsampling_x, + pd->subsampling_y, xd->bd, is_cur_buf_hbd(xd), 0, + xd->block_ref_scale_factors[ref], &pd->pre[ref], + mi->interp_filters); inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd); - av1_init_warp_params(&inter_pred_params, &pd->pre[ref], &warp_types, ref, - xd, mi); + av1_init_warp_params(&inter_pred_params, &warp_types, ref, xd, mi); - const struct buf_2d *const pre_buf = &pd->pre[ref]; uint8_t *const dst = get_buf_by_bd(xd, ext_dst[plane]); const MV mv = mi->mv[ref].as_mv; - av1_build_inter_predictor(pre_buf->buf, pre_buf->stride, dst, - ext_dst_stride[plane], &mv, mi_x, mi_y, - &inter_pred_params); + av1_enc_build_one_inter_predictor(dst, ext_dst_stride[plane], &mv, + &inter_pred_params); } } diff --git a/media/libaom/src/av1/encoder/reconinter_enc.h b/media/libaom/src/av1/encoder/reconinter_enc.h index a2c580ef50..fdc1f31c84 100644 --- a/media/libaom/src/av1/encoder/reconinter_enc.h +++ b/media/libaom/src/av1/encoder/reconinter_enc.h @@ -13,88 +13,50 @@ #define AOM_AV1_ENCODER_RECONINTER_ENC_H_ #include "aom/aom_integer.h" -#include "av1/common/filter.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" -#include "av1/common/onyxc_int.h" #include "av1/common/convolve.h" -#include "av1/common/warped_motion.h" +#include "av1/common/filter.h" #include "av1/common/reconinter.h" +#include "av1/common/warped_motion.h" #ifdef __cplusplus extern "C" { #endif +// Build single or compound reference inter predictors for all planes. +// Can build inter-intra predictors, masked predictors etc as well. void av1_enc_build_inter_predictor(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col, const BUFFER_SET *ctx, BLOCK_SIZE bsize, int plane_from, int plane_to); -void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, - int dst_stride, const MV *src_mv, int x, int y, - InterPredParams *inter_pred_params); +void av1_enc_build_inter_predictor_y(MACROBLOCKD *xd, int mi_row, int mi_col); -// Detect if the block have sub-pixel level motion vectors -// per component. -#define CHECK_SUBPEL 0 -static INLINE int has_subpel_mv_component(const MB_MODE_INFO *const mbmi, - const MACROBLOCKD *const xd, - int dir) { -#if CHECK_SUBPEL - const BLOCK_SIZE bsize = mbmi->sb_type; - int plane; - int ref = (dir >> 1); - - if (dir & 0x01) { - if (mbmi->mv[ref].as_mv.col & SUBPEL_MASK) return 1; - } else { - if (mbmi->mv[ref].as_mv.row & SUBPEL_MASK) return 1; - } - - return 0; -#else - (void)mbmi; - (void)xd; - (void)dir; - return 1; -#endif -} - -static INLINE int av1_is_interp_search_needed(const MACROBLOCKD *const xd) { - MB_MODE_INFO *const mi = xd->mi[0]; - const int is_compound = has_second_ref(mi); - int ref; - for (ref = 0; ref < 1 + is_compound; ++ref) { - int row_col; - for (row_col = 0; row_col < 2; ++row_col) { - const int dir = (ref << 1) + row_col; - if (has_subpel_mv_component(mi, xd, dir)) { - return 1; - } - } - } - return 0; -} +// Build one inter predictor. It is called for building predictor for single +// reference case, or just the 1st or 2nd reference in compound reference case. +// Can build both regular and masked predictors. +void av1_enc_build_one_inter_predictor(uint8_t *dst, int dst_stride, + const MV *src_mv, + InterPredParams *inter_pred_params); void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]); void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col, uint8_t *tmp_buf[MAX_MB_PLANE], int tmp_width[MAX_MB_PLANE], int tmp_height[MAX_MB_PLANE], int tmp_stride[MAX_MB_PLANE]); -void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, - int mi_row, int mi_col); +void av1_build_obmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd); void av1_build_inter_predictors_for_planes_single_buf( - MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane_from, int plane_to, int mi_row, - int mi_col, int ref, uint8_t *ext_dst[3], int ext_dst_stride[3]); + MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane_from, int plane_to, int ref, + uint8_t *ext_dst[3], int ext_dst_stride[3]); void av1_build_wedge_inter_predictor_from_buf(MACROBLOCKD *xd, BLOCK_SIZE bsize, int plane_from, int plane_to, diff --git a/media/libaom/src/av1/encoder/segmentation.c b/media/libaom/src/av1/encoder/segmentation.c index 9c1ede11b5..0c029c0e6e 100644 --- a/media/libaom/src/av1/encoder/segmentation.c +++ b/media/libaom/src/av1/encoder/segmentation.c @@ -49,16 +49,15 @@ static void count_segs(const AV1_COMMON *cm, MACROBLOCKD *xd, unsigned (*temporal_predictor_count)[2], unsigned *t_unpred_seg_counts, int bw, int bh, int mi_row, int mi_col) { - int segment_id; - - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; xd->mi = mi; - segment_id = xd->mi[0]->segment_id; - - set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols); + set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, mi_params->mi_rows, + mi_params->mi_cols); // Count the number of hits on each segment with no prediction + const int segment_id = xd->mi[0]->segment_id; no_pred_segcounts[segment_id]++; // Temporal prediction not allowed on key frames @@ -67,7 +66,8 @@ static void count_segs(const AV1_COMMON *cm, MACROBLOCKD *xd, // Test to see if the segment id matches the predicted value. const int pred_segment_id = cm->last_frame_seg_map - ? get_segment_id(cm, cm->last_frame_seg_map, bsize, mi_row, mi_col) + ? get_segment_id(mi_params, cm->last_frame_seg_map, bsize, mi_row, + mi_col) : 0; const int pred_flag = pred_segment_id == segment_id; const int pred_context = av1_get_pred_context_seg_id(xd); @@ -88,12 +88,13 @@ static void count_segs_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, unsigned (*temporal_predictor_count)[2], unsigned *t_unpred_seg_counts, int mi_row, int mi_col, BLOCK_SIZE bsize) { - const int mis = cm->mi_stride; + const CommonModeInfoParams *const mi_params = &cm->mi_params; + const int mis = mi_params->mi_stride; const int bs = mi_size_wide[bsize], hbs = bs / 2; PARTITION_TYPE partition; const int qbs = bs / 4; - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) return; #define CSEGS(cs_bw, cs_bh, cs_rowoff, cs_coloff) \ count_segs(cm, xd, tile, mi + mis * (cs_rowoff) + (cs_coloff), \ @@ -138,14 +139,14 @@ static void count_segs_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, CSEGS(bs, qbs, 0, 0); CSEGS(bs, qbs, qbs, 0); CSEGS(bs, qbs, 2 * qbs, 0); - if (mi_row + 3 * qbs < cm->mi_rows) CSEGS(bs, qbs, 3 * qbs, 0); + if (mi_row + 3 * qbs < mi_params->mi_rows) CSEGS(bs, qbs, 3 * qbs, 0); break; case PARTITION_VERT_4: CSEGS(qbs, bs, 0, 0); CSEGS(qbs, bs, 0, qbs); CSEGS(qbs, bs, 0, 2 * qbs); - if (mi_col + 3 * qbs < cm->mi_cols) CSEGS(qbs, bs, 0, 3 * qbs); + if (mi_col + 3 * qbs < mi_params->mi_cols) CSEGS(qbs, bs, 0, 3 * qbs); break; case PARTITION_SPLIT: { @@ -183,17 +184,18 @@ void av1_choose_segmap_coding_method(AV1_COMMON *cm, MACROBLOCKD *xd) { // First of all generate stats regarding how well the last segment map // predicts this one if (!scale_up) { - for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) { + for (tile_row = 0; tile_row < cm->tiles.rows; tile_row++) { TileInfo tile_info; av1_tile_set_row(&tile_info, cm, tile_row); - for (tile_col = 0; tile_col < cm->tile_cols; tile_col++) { + for (tile_col = 0; tile_col < cm->tiles.cols; tile_col++) { MB_MODE_INFO **mi_ptr; av1_tile_set_col(&tile_info, cm, tile_col); - mi_ptr = cm->mi_grid_base + tile_info.mi_row_start * cm->mi_stride + + mi_ptr = cm->mi_params.mi_grid_base + + tile_info.mi_row_start * cm->mi_params.mi_stride + tile_info.mi_col_start; for (mi_row = tile_info.mi_row_start; mi_row < tile_info.mi_row_end; mi_row += cm->seq_params.mib_size, - mi_ptr += cm->seq_params.mib_size * cm->mi_stride) { + mi_ptr += cm->seq_params.mib_size * cm->mi_params.mi_stride) { MB_MODE_INFO **mi = mi_ptr; for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end; mi_col += cm->seq_params.mib_size, @@ -214,7 +216,7 @@ void av1_choose_segmap_coding_method(AV1_COMMON *cm, MACROBLOCKD *xd) { no_pred_cost += no_pred_segcounts[i] * seg_id_cost[i]; // Frames without past dependency cannot use temporal prediction - if (cm->primary_ref_frame != PRIMARY_REF_NONE) { + if (cm->features.primary_ref_frame != PRIMARY_REF_NONE) { int pred_flag_cost[SEG_TEMPORAL_PRED_CTXS][2]; for (int i = 0; i < SEG_TEMPORAL_PRED_CTXS; ++i) av1_cost_tokens_from_cdf(pred_flag_cost[i], segp->pred_cdf[i], NULL); @@ -231,7 +233,7 @@ void av1_choose_segmap_coding_method(AV1_COMMON *cm, MACROBLOCKD *xd) { // Now choose which coding method to use. if (t_pred_cost < no_pred_cost) { - assert(!cm->error_resilient_mode); + assert(!cm->features.error_resilient_mode); seg->temporal_update = 1; } else { seg->temporal_update = 0; diff --git a/media/libaom/src/av1/encoder/speed_features.c b/media/libaom/src/av1/encoder/speed_features.c index 22f355fa9d..e03faeccc6 100644 --- a/media/libaom/src/av1/encoder/speed_features.c +++ b/media/libaom/src/av1/encoder/speed_features.c @@ -31,9 +31,6 @@ static MESH_PATTERN { { 64, 16 }, { 24, 8 }, { 12, 4 }, { 7, 1 } }, { { 64, 16 }, { 24, 8 }, { 12, 4 }, { 7, 1 } }, }; -static unsigned char good_quality_max_mesh_pct[MAX_MESH_SPEED + 1] = { 50, 50, - 25, 15, - 5, 1 }; // TODO(huisu@google.com): These settings are pretty relaxed, tune them for // each speed setting @@ -45,8 +42,6 @@ static MESH_PATTERN intrabc_mesh_patterns[MAX_MESH_SPEED + 1][MAX_MESH_STEP] = { { { 64, 4 }, { 16, 1 }, { 0, 0 }, { 0, 0 } }, { { 64, 4 }, { 16, 1 }, { 0, 0 }, { 0, 0 } }, }; -static uint8_t intrabc_max_mesh_pct[MAX_MESH_SPEED + 1] = { 100, 100, 100, - 25, 25, 10 }; // Threshold values to be used for pruning the txfm_domain_distortion // based on block MSE @@ -69,18 +64,23 @@ static unsigned int tx_domain_dist_types[3][MODE_EVAL_TYPES] = { { 0, 2, 0 }, { 2, 2, 0 } }; // Threshold values to be used for disabling coeff RD-optimization -// based on block MSE -// TODO(any): Experiment the threshold logic based on variance metric +// based on block MSE / qstep^2. +// TODO(any): Experiment the threshold logic based on variance metric. +// For each row, the indices are as follows. // Index 0: Default mode evaluation, Winner mode processing is not applicable -// (Eg : IntraBc) Index 1: Mode evaluation. Index 2: Winner mode evaluation. +// (Eg : IntraBc) +// Index 1: Mode evaluation. +// Index 2: Winner mode evaluation. // Index 1 and 2 are applicable when enable_winner_mode_for_coeff_opt speed // feature is ON -static unsigned int coeff_opt_dist_thresholds[5][MODE_EVAL_TYPES] = { +// There are 6 levels with increasing speed, mapping to vertical indices. +static unsigned int coeff_opt_dist_thresholds[6][MODE_EVAL_TYPES] = { { UINT_MAX, UINT_MAX, UINT_MAX }, - { 442413, 36314, UINT_MAX }, - { 162754, 36314, UINT_MAX }, - { 22026, 22026, UINT_MAX }, - { 22026, 22026, UINT_MAX } + { 3200, 250, UINT_MAX }, + { 1728, 142, UINT_MAX }, + { 864, 142, UINT_MAX }, + { 432, 86, UINT_MAX }, + { 216, 86, UINT_MAX } }; // Transform size to be used for default, mode and winner mode evaluation @@ -94,10 +94,16 @@ static TX_SIZE_SEARCH_METHOD tx_size_search_methods[3][MODE_EVAL_TYPES] = { { USE_LARGESTALL, USE_LARGESTALL, USE_FULL_RD } }; -// scaling values to be used for gating wedge/compound segment based on best -// approximate rd -static int comp_type_rd_threshold_mul[3] = { 1, 11, 12 }; -static int comp_type_rd_threshold_div[3] = { 3, 16, 16 }; +// Predict transform skip levels to be used for default, mode and winner mode +// evaluation. Index 0: Default mode evaluation, Winner mode processing is not +// applicable. Index 1: Mode evaluation, Index 2: Winner mode evaluation +// Values indicate the aggressiveness of skip flag prediction. +// 0 : no early skip prediction +// 1 : conservative early skip prediction using DCT_DCT +// 2 : early skip prediction based on SSE +static unsigned int predict_skip_levels[3][MODE_EVAL_TYPES] = { { 0, 0, 0 }, + { 1, 1, 1 }, + { 1, 2, 1 } }; // Intra only frames, golden frames (except alt ref overlays) and // alt ref frames tend to be coded at a higher than ambient quality @@ -125,89 +131,110 @@ static void set_good_speed_feature_framesize_dependent( const int is_4k_or_larger = AOMMIN(cm->width, cm->height) >= 2160; if (is_480p_or_larger) { - sf->use_square_partition_only_threshold = BLOCK_128X128; + sf->part_sf.use_square_partition_only_threshold = BLOCK_128X128; if (is_720p_or_larger) - sf->auto_max_partition_based_on_simple_motion = ADAPT_PRED; + sf->part_sf.auto_max_partition_based_on_simple_motion = ADAPT_PRED; else - sf->auto_max_partition_based_on_simple_motion = RELAXED_PRED; + sf->part_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; + sf->part_sf.use_square_partition_only_threshold = BLOCK_64X64; + sf->part_sf.auto_max_partition_based_on_simple_motion = DIRECT_PRED; } if (is_4k_or_larger) { - sf->default_min_partition_size = BLOCK_8X8; + sf->part_sf.default_min_partition_size = BLOCK_8X8; } // TODO(huisu@google.com): train models for 720P and above. if (!is_720p_or_larger) { - sf->ml_partition_search_breakout_thresh[0] = 200; // BLOCK_8X8 - sf->ml_partition_search_breakout_thresh[1] = 250; // BLOCK_16X16 - sf->ml_partition_search_breakout_thresh[2] = 300; // BLOCK_32X32 - sf->ml_partition_search_breakout_thresh[3] = 500; // BLOCK_64X64 - sf->ml_partition_search_breakout_thresh[4] = -1; // BLOCK_128X128 - sf->ml_early_term_after_part_split_level = 1; + sf->part_sf.ml_partition_search_breakout_thresh[0] = 200; // BLOCK_8X8 + sf->part_sf.ml_partition_search_breakout_thresh[1] = 250; // BLOCK_16X16 + sf->part_sf.ml_partition_search_breakout_thresh[2] = 300; // BLOCK_32X32 + sf->part_sf.ml_partition_search_breakout_thresh[3] = 500; // BLOCK_64X64 + sf->part_sf.ml_partition_search_breakout_thresh[4] = -1; // BLOCK_128X128 + sf->part_sf.ml_early_term_after_part_split_level = 1; } if (speed >= 1) { if (is_720p_or_larger) { - sf->use_square_partition_only_threshold = BLOCK_128X128; + sf->part_sf.use_square_partition_only_threshold = BLOCK_128X128; } else if (is_480p_or_larger) { - sf->use_square_partition_only_threshold = BLOCK_64X64; + sf->part_sf.use_square_partition_only_threshold = BLOCK_64X64; } else { - sf->use_square_partition_only_threshold = BLOCK_32X32; + sf->part_sf.use_square_partition_only_threshold = BLOCK_32X32; } if (!is_720p_or_larger) { - sf->ml_partition_search_breakout_thresh[0] = 200; // BLOCK_8X8 - sf->ml_partition_search_breakout_thresh[1] = 250; // BLOCK_16X16 - 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->part_sf.ml_partition_search_breakout_thresh[0] = 200; // BLOCK_8X8 + sf->part_sf.ml_partition_search_breakout_thresh[1] = 250; // BLOCK_16X16 + sf->part_sf.ml_partition_search_breakout_thresh[2] = 300; // BLOCK_32X32 + sf->part_sf.ml_partition_search_breakout_thresh[3] = 300; // BLOCK_64X64 + sf->part_sf.ml_partition_search_breakout_thresh[4] = -1; // BLOCK_128X128 } - sf->ml_early_term_after_part_split_level = 2; + sf->part_sf.ml_early_term_after_part_split_level = 2; } if (speed >= 2) { if (is_720p_or_larger) { - sf->use_square_partition_only_threshold = BLOCK_64X64; + sf->part_sf.use_square_partition_only_threshold = BLOCK_64X64; } else if (is_480p_or_larger) { - sf->use_square_partition_only_threshold = BLOCK_32X32; + sf->part_sf.use_square_partition_only_threshold = BLOCK_32X32; } else { - sf->use_square_partition_only_threshold = BLOCK_32X32; + sf->part_sf.use_square_partition_only_threshold = BLOCK_32X32; } if (is_720p_or_larger) { - sf->partition_search_breakout_dist_thr = (1 << 24); - sf->partition_search_breakout_rate_thr = 120; + sf->part_sf.partition_search_breakout_dist_thr = (1 << 24); + sf->part_sf.partition_search_breakout_rate_thr = 120; } else { - sf->partition_search_breakout_dist_thr = (1 << 22); - sf->partition_search_breakout_rate_thr = 100; + sf->part_sf.partition_search_breakout_dist_thr = (1 << 22); + sf->part_sf.partition_search_breakout_rate_thr = 100; } - if (is_480p_or_larger) sf->tx_type_search.prune_tx_type_using_stats = 1; + if (is_720p_or_larger) { + sf->inter_sf.prune_obmc_prob_thresh = 16; + } else { + sf->inter_sf.prune_obmc_prob_thresh = 8; + } + + if (is_480p_or_larger) { + sf->tx_sf.tx_type_search.prune_tx_type_using_stats = 1; + } } if (speed >= 3) { - sf->ml_early_term_after_part_split_level = 0; + sf->part_sf.ml_early_term_after_part_split_level = 0; + if (is_720p_or_larger) { - sf->partition_search_breakout_dist_thr = (1 << 25); - sf->partition_search_breakout_rate_thr = 200; + sf->part_sf.partition_search_breakout_dist_thr = (1 << 25); + sf->part_sf.partition_search_breakout_rate_thr = 200; } else { - sf->max_intra_bsize = BLOCK_32X32; - sf->partition_search_breakout_dist_thr = (1 << 23); - sf->partition_search_breakout_rate_thr = 120; + sf->part_sf.max_intra_bsize = BLOCK_32X32; + sf->part_sf.partition_search_breakout_dist_thr = (1 << 23); + sf->part_sf.partition_search_breakout_rate_thr = 120; } } if (speed >= 4) { if (is_720p_or_larger) { - sf->partition_search_breakout_dist_thr = (1 << 26); + sf->part_sf.partition_search_breakout_dist_thr = (1 << 26); } else { - sf->partition_search_breakout_dist_thr = (1 << 24); + sf->part_sf.partition_search_breakout_dist_thr = (1 << 24); } - if (is_480p_or_larger) sf->tx_type_search.prune_tx_type_using_stats = 2; + if (is_480p_or_larger) { + sf->tx_sf.tx_type_search.prune_tx_type_using_stats = 2; + } + + sf->inter_sf.prune_obmc_prob_thresh = 16; + } + + if (speed >= 5) { + if (is_720p_or_larger) { + sf->inter_sf.prune_warped_prob_thresh = 16; + } else if (is_480p_or_larger) { + sf->inter_sf.prune_warped_prob_thresh = 8; + } } } @@ -217,13 +244,30 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi, const AV1_COMMON *const cm = &cpi->common; const int is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720; const int is_480p_or_larger = AOMMIN(cm->width, cm->height) >= 480; + const int is_360p_or_larger = AOMMIN(cm->width, cm->height) >= 360; (void)is_720p_or_larger; // Not used so far - if (!is_480p_or_larger) { + if (!is_360p_or_larger) { + if (speed >= 6) sf->rt_sf.force_tx_search_off = 1; if (speed >= 8) { - sf->mv.subpel_search_method = SUBPEL_TREE; - sf->estimate_motion_for_var_based_partition = 1; + sf->rt_sf.use_modeled_non_rd_cost = 0; + sf->rt_sf.use_nonrd_filter_search = 0; + } + } + if (is_360p_or_larger) { + if (speed >= 7) { + sf->interp_sf.disable_filter_search_var_thresh = 0; + } + } + if (!is_480p_or_larger) { + if (speed == 7) { + sf->rt_sf.nonrd_check_partition_merge_mode = 2; + } + if (speed >= 8) { + sf->mv_sf.subpel_search_method = SUBPEL_TREE; + + sf->rt_sf.estimate_motion_for_var_based_partition = 1; } } } @@ -235,215 +279,326 @@ static void set_good_speed_features_framesize_independent( const int boosted = frame_is_boosted(cpi); const int is_boosted_arf2_bwd_type = boosted || gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE; + const int allow_screen_content_tools = + cm->features.allow_screen_content_tools; + if (!cpi->oxcf.large_scale_tile) { + sf->hl_sf.high_precision_mv_usage = LAST_MV_DATA; + } // 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->simple_motion_search_prune_rect = 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->gm_sf.gm_disable_recode = 1; + sf->gm_sf.gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3; + sf->part_sf.less_rectangular_check_level = 1; + sf->part_sf.ml_prune_4_partition = 1; + sf->part_sf.ml_prune_ab_partition = 1; + sf->part_sf.ml_prune_rect_partition = 1; + sf->part_sf.prune_ext_partition_types_search_level = 1; + sf->part_sf.simple_motion_search_prune_rect = 1; + + sf->inter_sf.disable_wedge_search_edge_thresh = 0; + sf->inter_sf.disable_wedge_search_var_thresh = 0; // TODO(debargha): Test, tweak and turn on either 1 or 2 - sf->inter_mode_rd_model_estimation = 1; - sf->prune_compound_using_single_ref = 1; - - sf->prune_mode_search_simple_translation = 1; - sf->prune_ref_frame_for_rect_partitions = - (boosted || (cm->allow_screen_content_tools)) + sf->inter_sf.inter_mode_rd_model_estimation = 1; + sf->inter_sf.model_based_post_interp_filter_breakout = 1; + sf->inter_sf.prune_compound_using_single_ref = 1; + sf->inter_sf.prune_mode_search_simple_translation = 1; + sf->inter_sf.prune_motion_mode_level = 1; + sf->inter_sf.prune_ref_frame_for_rect_partitions = + (boosted || (allow_screen_content_tools)) ? 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; - sf->use_fast_interpolation_filter_search = 1; - sf->intra_tx_size_search_init_depth_sqr = 1; - sf->intra_angle_estimation = 1; - sf->tx_type_search.use_reduced_intra_txset = 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; + sf->inter_sf.prune_wedge_pred_diff_based = 1; + sf->inter_sf.reduce_inter_modes = 1; + sf->inter_sf.selective_ref_frame = 1; + sf->inter_sf.use_dist_wtd_comp_flag = DIST_WTD_COMP_SKIP_MV_SEARCH; + + sf->interp_sf.cb_pred_filter_search = 0; + sf->interp_sf.use_fast_interpolation_filter_search = 1; + + sf->intra_sf.intra_pruning_with_hog = 1; + sf->intra_sf.intra_pruning_with_hog_thresh = -1.2f; + + sf->tx_sf.adaptive_txb_search_level = 1; + sf->tx_sf.intra_tx_size_search_init_depth_sqr = 1; + sf->tx_sf.model_based_prune_tx_search_level = 1; + sf->tx_sf.tx_type_search.use_reduced_intra_txset = 1; + + sf->rt_sf.use_nonrd_pick_mode = 0; + sf->rt_sf.use_real_time_ref_set = 0; + + if (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) + sf->mv_sf.exhaustive_searches_thresh = (1 << 24); + else + sf->mv_sf.exhaustive_searches_thresh = (1 << 25); + + sf->rd_sf.perform_coeff_opt = 1; if (speed >= 1) { - sf->selective_ref_frame = 2; + sf->gm_sf.disable_adaptive_warp_error_thresh = 0; + sf->gm_sf.gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2; + sf->gm_sf.prune_ref_frame_for_gm_search = boosted ? 0 : 1; - sf->prune_ref_frame_for_gm_search = boosted ? 0 : 1; - sf->intra_tx_size_search_init_depth_rect = 1; - - sf->skip_repeat_interpolation_filter_search = 1; - sf->tx_type_search.skip_tx_search = 1; - sf->tx_type_search.ml_tx_split_thresh = 4000; - sf->adaptive_txb_search_level = 2; - sf->use_intra_txb_hash = 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; + sf->part_sf.intra_cnn_split = 1; + sf->part_sf.simple_motion_search_early_term_none = 1; // TODO(Venkat): Clean-up frame type dependency for // simple_motion_search_split in partition search function and set the // speed feature accordingly - sf->simple_motion_search_split = cm->allow_screen_content_tools ? 1 : 2; - sf->simple_motion_search_early_term_none = 1; + sf->part_sf.simple_motion_search_split = allow_screen_content_tools ? 1 : 2; - sf->disable_interinter_wedge_newmv_search = boosted ? 0 : 1; - 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->disable_adaptive_warp_error_thresh = 0; - sf->tx_domain_dist_level = boosted ? 1 : 2; - sf->tx_domain_dist_thres_level = 1; - sf->perform_coeff_opt = boosted ? 1 : 2; - sf->prune_ref_frame_for_rect_partitions = - (frame_is_intra_only(&cpi->common) || (cm->allow_screen_content_tools)) + sf->mv_sf.exhaustive_searches_thresh <<= 1; + sf->mv_sf.obmc_full_pixel_search_level = 1; + sf->mv_sf.use_accurate_subpel_search = USE_4_TAPS; + + sf->inter_sf.disable_interinter_wedge_newmv_search = boosted ? 0 : 1; + sf->inter_sf.prune_comp_search_by_single_result = boosted ? 2 : 1; + sf->inter_sf.prune_comp_type_by_comp_avg = 1; + sf->inter_sf.prune_comp_type_by_model_rd = boosted ? 0 : 1; + sf->inter_sf.prune_motion_mode_level = 2; + sf->inter_sf.prune_ref_frame_for_rect_partitions = + (frame_is_intra_only(&cpi->common) || (allow_screen_content_tools)) ? 0 : (boosted ? 1 : 2); - sf->intra_cnn_split = 1; + sf->inter_sf.reduce_inter_modes = boosted ? 1 : 2; + sf->inter_sf.reuse_inter_intra_mode = 1; + sf->inter_sf.selective_ref_frame = 2; + sf->inter_sf.skip_repeated_newmv = 1; - sf->enable_sgr_ep_pruning = 1; - sf->inter_tx_size_search_init_depth_rect = 1; - sf->inter_tx_size_search_init_depth_sqr = 1; - sf->cdef_pick_method = CDEF_FAST_SEARCH; - sf->cb_pred_filter_search = 0; - sf->model_based_prune_tx_search_level = 0; - sf->reduce_inter_modes = boosted ? 1 : 2; - sf->tx_type_search.prune_mode = PRUNE_2D_FAST; - sf->prune_comp_type_by_model_rd = boosted ? 0 : 1; - sf->adaptive_overlay_encoding = 1; + sf->interp_sf.cb_pred_filter_search = 0; + sf->interp_sf.use_interp_filter = 1; + sf->intra_sf.prune_palette_search_level = 1; + + sf->tx_sf.adaptive_txb_search_level = 2; + sf->tx_sf.inter_tx_size_search_init_depth_rect = 1; + sf->tx_sf.inter_tx_size_search_init_depth_sqr = 1; + sf->tx_sf.intra_tx_size_search_init_depth_rect = 1; + sf->tx_sf.model_based_prune_tx_search_level = 0; + sf->tx_sf.tx_type_search.ml_tx_split_thresh = 4000; + sf->tx_sf.tx_type_search.prune_mode = PRUNE_2D_FAST; + sf->tx_sf.tx_type_search.skip_tx_search = 1; + sf->tx_sf.use_intra_txb_hash = 1; + + sf->rd_sf.perform_coeff_opt = boosted ? 2 : 3; + sf->rd_sf.tx_domain_dist_level = boosted ? 1 : 2; + sf->rd_sf.tx_domain_dist_thres_level = 1; + + sf->lpf_sf.cdef_pick_method = CDEF_FAST_SEARCH_LVL1; + sf->lpf_sf.dual_sgr_penalty_level = 1; + sf->lpf_sf.enable_sgr_ep_pruning = 1; + + // TODO(any, yunqing): move this feature to speed 0. + sf->tpl_sf.skip_alike_starting_mv = 1; } if (speed >= 2) { - sf->gm_erroradv_type = GM_ERRORADV_TR_2; + sf->gm_sf.gm_erroradv_type = GM_ERRORADV_TR_2; - sf->selective_ref_frame = 3; + sf->part_sf.allow_partition_search_skip = 1; + + sf->mv_sf.auto_mv_step_size = 1; + sf->mv_sf.subpel_iters_per_step = 1; // TODO(chiyotsai@google.com): We can get 10% speed up if we move // adaptive_rd_thresh to speed 1. But currently it performs poorly on some // clips (e.g. 5% loss on dinner_1080p). We need to examine the sequence a // bit more closely to figure out why. - 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->inter_sf.adaptive_rd_thresh = 1; + sf->inter_sf.comp_inter_joint_search_thresh = BLOCK_SIZES_ALL; + sf->inter_sf.disable_interinter_wedge_newmv_search = 1; + sf->inter_sf.disable_wedge_search_edge_thresh = 0; + sf->inter_sf.disable_wedge_search_var_thresh = 100; + sf->inter_sf.fast_interintra_wedge_search = 1; + sf->inter_sf.fast_wedge_sign_estimate = 1; + sf->inter_sf.prune_comp_search_by_single_result = boosted ? 4 : 1; + sf->inter_sf.prune_compound_using_neighbors = 1; + sf->inter_sf.prune_comp_type_by_comp_avg = 2; + sf->inter_sf.prune_warp_using_wmtype = 1; + sf->inter_sf.selective_ref_frame = 3; + sf->inter_sf.use_dist_wtd_comp_flag = DIST_WTD_COMP_DISABLED; - sf->allow_partition_search_skip = 1; - sf->disable_wedge_search_var_thresh = 100; - sf->disable_wedge_search_edge_thresh = 0; - sf->disable_interinter_wedge_newmv_search = 1; - 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; // TODO(Sachin): Enable/Enhance this speed feature for speed 2 & 3 - sf->adaptive_interp_filter_search = 1; - sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 3; + sf->interp_sf.adaptive_interp_filter_search = 1; + sf->interp_sf.disable_dual_filter = 1; + sf->interp_sf.disable_filter_search_var_thresh = 100; - sf->prune_warp_using_wmtype = 1; - sf->disable_smooth_intra = + sf->intra_sf.disable_smooth_intra = !frame_is_intra_only(&cpi->common) || (cpi->rc.frames_to_key != 1); - // TODO(yunqing): need to test and turn it on for speed > 1. - sf->adaptive_overlay_encoding = 0; + sf->rd_sf.perform_coeff_opt = is_boosted_arf2_bwd_type ? 3 : 4; + + sf->lpf_sf.prune_wiener_based_on_src_var = 1; + sf->lpf_sf.prune_sgr_based_on_wiener = !allow_screen_content_tools; } if (speed >= 3) { - sf->less_rectangular_check_level = 2; + sf->hl_sf.high_precision_mv_usage = CURRENT_Q; + sf->hl_sf.recode_loop = ALLOW_RECODE_KFARFGF; + + sf->gm_sf.gm_search_type = GM_DISABLE_SEARCH; + + sf->part_sf.less_rectangular_check_level = 2; + sf->part_sf.simple_motion_search_prune_agg = 1; + sf->part_sf.prune_4_partition_using_split_info = + !allow_screen_content_tools; + // 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_accurate_subpel_search = USE_2_TAPS; - if (cpi->oxcf.enable_smooth_interintra) - sf->disable_smooth_interintra = boosted ? 0 : 1; - sf->gm_search_type = GM_DISABLE_SEARCH; - sf->prune_comp_search_by_single_result = boosted ? 4 : 2; - sf->prune_motion_mode_level = boosted ? 2 : 3; + // sf->mv_sf.adaptive_motion_search = 1; + sf->mv_sf.full_pixel_search_level = 1; + sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED; + sf->mv_sf.use_accurate_subpel_search = USE_2_TAPS; + sf->mv_sf.search_method = DIAMOND; + + sf->inter_sf.disable_sb_level_mv_cost_upd = 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; + sf->inter_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; - // TODO(any): Experiment on the dependency of this speed feature with - // use_intra_txb_hash, use_inter_txb_hash and use_mb_rd_hash speed features + sf->inter_sf.perform_best_rd_based_gating_for_chroma = 1; + sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 1; + sf->inter_sf.prune_comp_search_by_single_result = boosted ? 4 : 2; + sf->inter_sf.prune_motion_mode_level = boosted ? 2 : 3; + sf->inter_sf.selective_ref_frame = 4; + sf->inter_sf.skip_repeated_ref_mv = 1; + sf->inter_sf.skip_repeated_full_newmv = 1; + if (cpi->oxcf.enable_smooth_interintra) + sf->inter_sf.disable_smooth_interintra = boosted ? 0 : 1; + sf->inter_sf.reuse_compound_type_decision = 1; + sf->inter_sf.txfm_rd_gate_level = (boosted || allow_screen_content_tools) + ? 0 + : (is_boosted_arf2_bwd_type ? 1 : 2); + + sf->intra_sf.prune_palette_search_level = 2; + + sf->tpl_sf.skip_alike_starting_mv = 2; + sf->tpl_sf.prune_intra_modes = 1; + sf->tpl_sf.reduce_first_step_size = 6; + + sf->tx_sf.adaptive_txb_search_level = boosted ? 2 : 3; + sf->tx_sf.tx_type_search.use_skip_flag_prediction = + allow_screen_content_tools ? 1 : 2; + // TODO(any): Refactor the code related to following winner mode speed // features - sf->enable_winner_mode_for_coeff_opt = 1; + sf->winner_mode_sf.enable_winner_mode_for_coeff_opt = 1; // TODO(any): Experiment with this speed feature by enabling for key frames - sf->enable_winner_mode_for_tx_size_srch = + sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch = frame_is_intra_only(&cpi->common) ? 0 : 1; - sf->enable_winner_mode_for_use_tx_domain_dist = - cm->allow_screen_content_tools ? 0 : 1; - sf->reduce_wiener_window_size = is_boosted_arf2_bwd_type ? 0 : 1; - sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED; - sf->simple_motion_search_prune_agg = 1; - sf->disable_sb_level_mv_cost_upd = 1; + sf->winner_mode_sf.enable_winner_mode_for_use_tx_domain_dist = + !allow_screen_content_tools; + sf->winner_mode_sf.motion_mode_for_winner_cand = + boosted + ? 0 + : gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE ? 1 + : 2; + + // TODO(any): evaluate if these lpf features can be moved to speed 2. + sf->lpf_sf.prune_sgr_based_on_wiener = allow_screen_content_tools ? 0 : 2; + sf->lpf_sf.disable_loop_restoration_chroma = + (boosted || allow_screen_content_tools) ? 0 : 1; + sf->lpf_sf.reduce_wiener_window_size = !boosted; + sf->lpf_sf.prune_wiener_based_on_src_var = 2; + + sf->hl_sf.second_alt_ref_filtering = 0; } if (speed >= 4) { - sf->selective_ref_frame = 4; - sf->use_intra_txb_hash = 0; - sf->tx_type_search.fast_intra_tx_type_search = 1; - sf->disable_loop_restoration_chroma = - (boosted || cm->allow_screen_content_tools) ? 0 : 1; - sf->reduce_wiener_window_size = !boosted; - sf->cb_pred_filter_search = 1; - sf->adaptive_mode_search = 1; - sf->alt_ref_search_fp = 1; - sf->skip_sharp_interp_filter_search = 1; - sf->perform_coeff_opt = is_boosted_arf2_bwd_type ? 2 : 4; - sf->adaptive_txb_search_level = boosted ? 2 : 3; - sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; - sf->enable_winner_mode_for_tx_size_srch = 1; - // TODO(any): Extend multi-winner mode processing support for inter frames - sf->enable_multiwinner_mode_process = - frame_is_intra_only(&cpi->common) ? 1 : 0; + sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; + + sf->part_sf.simple_motion_search_prune_agg = 2; + sf->part_sf.prune_ab_partition_using_split_info = + !allow_screen_content_tools; + + sf->inter_sf.adaptive_mode_search = 1; + sf->inter_sf.alt_ref_search_fp = 1; + sf->inter_sf.prune_ref_mv_idx_search = 1; + sf->inter_sf.txfm_rd_gate_level = + (boosted || allow_screen_content_tools) ? 0 : 3; + + sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 2; + sf->inter_sf.prune_compound_using_neighbors = 2; + sf->inter_sf.disable_smooth_interintra = 1; + + sf->interp_sf.cb_pred_filter_search = 1; + sf->interp_sf.skip_sharp_interp_filter_search = 1; + sf->interp_sf.use_interp_filter = 2; + sf->interp_sf.adaptive_interp_filter_search = 2; + + sf->intra_sf.intra_uv_mode_mask[TX_16X16] = UV_INTRA_DC_H_V_CFL; + sf->intra_sf.intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_H_V_CFL; + sf->intra_sf.intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC_H_V_CFL; + sf->intra_sf.intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V; + sf->intra_sf.intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V; + sf->intra_sf.intra_y_mode_mask[TX_64X64] = INTRA_DC_H_V; // TODO(any): Experiment with this speed feature set to 2 for higher quality // presets as well - sf->skip_intra_in_interframe = 2; + sf->intra_sf.skip_intra_in_interframe = 2; - 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_sf.tx_type_search.enable_winner_mode_tx_type_pruning = 1; + sf->tx_sf.tx_type_search.fast_intra_tx_type_search = 1; + sf->tx_sf.tx_type_search.prune_mode = PRUNE_2D_MORE; + sf->tx_sf.tx_type_search.prune_tx_type_est_rd = 1; + // TODO(any): Experiment with enabling of this speed feature as hash state + // is reset during winner mode processing + sf->tx_sf.use_intra_txb_hash = 0; - sf->tx_type_search.prune_mode = PRUNE_2D_MORE; + sf->rd_sf.perform_coeff_opt = is_boosted_arf2_bwd_type ? 3 : 5; + sf->rd_sf.tx_domain_dist_thres_level = 2; + + // TODO(any): Extend multi-winner mode processing support for inter frames + sf->winner_mode_sf.enable_multiwinner_mode_process = + frame_is_intra_only(&cpi->common) ? 1 : 0; + sf->winner_mode_sf.enable_winner_mode_for_tx_size_srch = 1; + + sf->lpf_sf.cdef_pick_method = allow_screen_content_tools + ? CDEF_FAST_SEARCH_LVL1 + : CDEF_FAST_SEARCH_LVL2; // TODO(any): The following features have no impact on quality and speed, // and are disabled. - // sf->disable_filter_search_var_thresh = 200; - // sf->use_fast_coef_costing = 1; - // sf->partition_search_breakout_rate_thr = 300; + // sf->part_sf.partition_search_breakout_rate_thr = 300; + // sf->interp_sf.disable_filter_search_var_thresh = 200; + // sf->rd_sf.use_fast_coef_costing = 1; // TODO(any): The following features give really bad quality/speed trade // off. Needs to be re-worked. - // sf->tx_size_search_method = USE_LARGESTALL; - // sf->mv.search_method = BIGDIA; - // sf->adaptive_rd_thresh = 4; - // sf->mode_search_skip_flags = + // sf->mv_sf.search_method = BIGDIA; + // sf->inter_sf.adaptive_rd_thresh = 4; + // sf->rd_sf.tx_domain_dist_level = 2; + // sf->rt_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->tx_domain_dist_level = 2; - sf->tx_domain_dist_thres_level = 2; - sf->simple_motion_search_prune_agg = 2; - sf->prune_obmc_using_stats = 1; + } + + if (speed >= 5) { + sf->part_sf.simple_motion_search_prune_agg = 3; + sf->part_sf.ext_partition_eval_thresh = + allow_screen_content_tools ? BLOCK_8X8 : BLOCK_16X16; + + sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 3; + sf->inter_sf.disable_interinter_wedge = 1; + sf->inter_sf.disable_obmc = 1; + sf->inter_sf.disable_onesided_comp = 1; + sf->inter_sf.txfm_rd_gate_level = + (boosted || allow_screen_content_tools) ? 0 : 4; + sf->inter_sf.prune_inter_modes_if_skippable = 1; + + sf->lpf_sf.lpf_pick = LPF_PICK_FROM_FULL_IMAGE_NON_DUAL; + sf->lpf_sf.disable_lr_filter = 1; + + sf->mv_sf.simple_motion_subpel_force_stop = QUARTER_PEL; + sf->mv_sf.prune_mesh_search = 1; + sf->mv_sf.reduce_search_range = 1; + + sf->tpl_sf.subpel_force_stop = QUARTER_PEL; + } + + if (speed >= 6) { } } @@ -458,247 +613,510 @@ static void set_rt_speed_features_framesize_independent(AV1_COMP *cpi, 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->gm_sf.gm_disable_recode = 1; + sf->gm_sf.gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3; + + sf->part_sf.less_rectangular_check_level = 1; + sf->part_sf.ml_prune_4_partition = 1; + sf->part_sf.ml_prune_ab_partition = 1; + sf->part_sf.ml_prune_rect_partition = 1; + sf->part_sf.prune_ext_partition_types_search_level = 1; // TODO(debargha): Test, tweak and turn on either 1 or 2 - sf->inter_mode_rd_model_estimation = 0; - sf->prune_compound_using_single_ref = 0; - sf->prune_mode_search_simple_translation = 1; + sf->inter_sf.inter_mode_rd_model_estimation = 0; + sf->inter_sf.disable_wedge_search_edge_thresh = 0; + sf->inter_sf.disable_wedge_search_var_thresh = 0; + sf->inter_sf.model_based_post_interp_filter_breakout = 1; + sf->inter_sf.prune_compound_using_single_ref = 0; + sf->inter_sf.prune_mode_search_simple_translation = 1; + sf->inter_sf.prune_motion_mode_level = 1; + sf->inter_sf.prune_ref_frame_for_rect_partitions = !boosted; + sf->inter_sf.prune_wedge_pred_diff_based = 1; + sf->inter_sf.reduce_inter_modes = 1; + sf->inter_sf.selective_ref_frame = 1; + sf->inter_sf.use_dist_wtd_comp_flag = DIST_WTD_COMP_SKIP_MV_SEARCH; - 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->tx_type_search.use_reduced_intra_txset = 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; - sf->use_fast_nonrd_pick_mode = 0; - sf->reuse_inter_pred_nonrd = 0; - sf->estimate_motion_for_var_based_partition = 1; - sf->use_comp_ref_nonrd = 1; - sf->check_intra_pred_nonrd = 1; - sf->use_nonrd_filter_search = 1; - sf->nonrd_use_blockyrd_interp_filter = 0; + sf->interp_sf.cb_pred_filter_search = 0; + sf->interp_sf.use_fast_interpolation_filter_search = 1; + + sf->intra_sf.intra_pruning_with_hog = 1; + sf->intra_sf.intra_pruning_with_hog_thresh = -1.2f; + + sf->mv_sf.full_pixel_search_level = 1; + sf->mv_sf.exhaustive_searches_thresh = INT_MAX; + + sf->rt_sf.check_intra_pred_nonrd = 1; + sf->rt_sf.estimate_motion_for_var_based_partition = 1; + sf->rt_sf.hybrid_intra_pickmode = 0; + sf->rt_sf.nonrd_prune_ref_frame_search = 0; + sf->rt_sf.reuse_inter_pred_nonrd = 0; + sf->rt_sf.use_comp_ref_nonrd = 1; + sf->rt_sf.use_nonrd_filter_search = 1; + sf->rt_sf.use_nonrd_pick_mode = 0; + sf->rt_sf.use_real_time_ref_set = 0; + sf->tx_sf.adaptive_txb_search_level = 1; + sf->tx_sf.intra_tx_size_search_init_depth_sqr = 1; + sf->tx_sf.model_based_prune_tx_search_level = 1; + sf->tx_sf.tx_type_search.use_reduced_intra_txset = 1; if (speed >= 1) { - sf->gm_erroradv_type = GM_ERRORADV_TR_1; - sf->selective_ref_frame = 2; + sf->gm_sf.gm_erroradv_type = GM_ERRORADV_TR_1; + sf->gm_sf.gm_search_type = GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2; - 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 = 4000; - 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(jianj): 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->part_sf.prune_ext_partition_types_search_level = 2; + sf->part_sf.simple_motion_search_prune_rect = 1; - sf->simple_motion_search_prune_rect = 1; + sf->mv_sf.obmc_full_pixel_search_level = 1; + sf->mv_sf.use_accurate_subpel_search = USE_4_TAPS; - 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->tx_domain_dist_level = boosted ? 0 : 1; - sf->tx_domain_dist_thres_level = 1; + sf->inter_sf.prune_comp_search_by_single_result = 1; + sf->inter_sf.reuse_inter_intra_mode = 1; + sf->inter_sf.selective_ref_frame = 2; + sf->inter_sf.skip_repeated_newmv = 1; + sf->inter_sf.disable_wedge_search_var_thresh = 0; + sf->inter_sf.disable_wedge_search_edge_thresh = 0; + sf->inter_sf.prune_comp_type_by_comp_avg = 1; + sf->inter_sf.prune_motion_mode_level = 2; + sf->inter_sf.prune_single_motion_modes_by_simple_trans = 1; + + sf->interp_sf.cb_pred_filter_search = 1; + sf->interp_sf.use_interp_filter = 1; + + sf->tx_sf.adaptive_txb_search_level = 2; + sf->tx_sf.intra_tx_size_search_init_depth_rect = 1; + sf->tx_sf.tx_size_search_lgr_block = 1; + sf->tx_sf.tx_type_search.ml_tx_split_thresh = 4000; + sf->tx_sf.tx_type_search.skip_tx_search = 1; + sf->tx_sf.use_intra_txb_hash = 1; + + sf->rd_sf.optimize_b_precheck = 1; + sf->rd_sf.tx_domain_dist_level = boosted ? 0 : 1; + sf->rd_sf.tx_domain_dist_thres_level = 1; + + sf->lpf_sf.dual_sgr_penalty_level = 1; } if (speed >= 2) { - sf->gm_erroradv_type = GM_ERRORADV_TR_2; + sf->gm_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->cdef_pick_method = CDEF_FAST_SEARCH; + sf->part_sf.allow_partition_search_skip = 1; + sf->part_sf.partition_search_breakout_rate_thr = 80; - 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->mv_sf.auto_mv_step_size = 1; + sf->mv_sf.subpel_iters_per_step = 1; - 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; - sf->model_based_prune_tx_search_level = 0; + sf->inter_sf.adaptive_rd_thresh = 1; + sf->inter_sf.comp_inter_joint_search_thresh = BLOCK_SIZES_ALL; + sf->inter_sf.disable_wedge_search_edge_thresh = 0; + sf->inter_sf.disable_wedge_search_var_thresh = 100; + sf->inter_sf.fast_wedge_sign_estimate = 1; + sf->inter_sf.prune_comp_type_by_comp_avg = 2; + sf->inter_sf.selective_ref_frame = 3; + sf->inter_sf.use_dist_wtd_comp_flag = DIST_WTD_COMP_DISABLED; + + sf->interp_sf.adaptive_interp_filter_search = 1; + sf->interp_sf.cb_pred_filter_search = 0; + sf->interp_sf.disable_dual_filter = 1; + sf->interp_sf.disable_filter_search_var_thresh = 100; + + sf->tx_sf.inter_tx_size_search_init_depth_rect = 1; + sf->tx_sf.inter_tx_size_search_init_depth_sqr = 1; + sf->tx_sf.model_based_prune_tx_search_level = 0; + + sf->lpf_sf.cdef_pick_method = CDEF_FAST_SEARCH_LVL1; } if (speed >= 3) { - sf->selective_ref_frame = 4; - sf->tx_size_search_level = boosted ? 0 : 2; - sf->less_rectangular_check_level = 2; + sf->hl_sf.recode_loop = ALLOW_RECODE_KFARFGF; + + sf->gm_sf.gm_search_type = GM_DISABLE_SEARCH; + + sf->part_sf.less_rectangular_check_level = 2; + + sf->mv_sf.use_accurate_subpel_search = USE_2_TAPS; // 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->tx_domain_dist_level = 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; + // sf->mv_sf.adaptive_motion_search = 1; + + sf->inter_sf.adaptive_rd_thresh = 2; + sf->inter_sf.disable_sb_level_mv_cost_upd = 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; - sf->disable_sb_level_mv_cost_upd = 1; + sf->inter_sf.disable_wedge_interintra_search = 1; + sf->inter_sf.prune_comp_search_by_single_result = 2; + sf->inter_sf.prune_motion_mode_level = boosted ? 2 : 3; + sf->inter_sf.prune_warp_using_wmtype = 1; + sf->inter_sf.selective_ref_frame = 4; + + sf->tx_sf.tx_type_search.prune_mode = PRUNE_2D_FAST; + + sf->rd_sf.tx_domain_dist_level = 1; + + sf->winner_mode_sf.tx_size_search_level = boosted ? 0 : 2; } 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_level = frame_is_intra_only(cm) ? 0 : 2; - sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED; - sf->adaptive_mode_search = 1; - sf->alt_ref_search_fp = 1; - sf->skip_sharp_interp_filter_search = 1; + sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED; + + sf->inter_sf.adaptive_mode_search = 1; + sf->inter_sf.alt_ref_search_fp = 1; + + sf->interp_sf.skip_sharp_interp_filter_search = 1; + + sf->tx_sf.tx_type_search.fast_inter_tx_type_search = 1; + sf->tx_sf.tx_type_search.fast_intra_tx_type_search = 1; + sf->tx_sf.use_intra_txb_hash = 0; + + sf->rd_sf.use_mb_rd_hash = 0; + + sf->winner_mode_sf.tx_size_search_level = frame_is_intra_only(cm) ? 0 : 2; } 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_level = 2; - sf->mv.search_method = BIGDIA; - sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; - sf->adaptive_rd_thresh = 4; - sf->mode_search_skip_flags = + sf->hl_sf.recode_loop = ALLOW_RECODE_KFMAXBW; + + sf->inter_sf.adaptive_rd_thresh = 4; + sf->interp_sf.disable_filter_search_var_thresh = 200; + + sf->rd_sf.use_fast_coef_costing = 1; + sf->rd_sf.tx_domain_dist_level = 2; + sf->rd_sf.tx_domain_dist_thres_level = 2; + sf->winner_mode_sf.tx_size_search_level = 1; + + sf->rt_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->tx_domain_dist_level = 2; - sf->tx_domain_dist_thres_level = 2; + sf->hl_sf.frame_parameter_update = 0; + + sf->part_sf.default_max_partition_size = BLOCK_128X128; + sf->part_sf.default_min_partition_size = BLOCK_8X8; + sf->part_sf.max_intra_bsize = BLOCK_32X32; + sf->part_sf.partition_search_breakout_rate_thr = 500; + sf->part_sf.partition_search_type = VAR_BASED_PARTITION; + sf->part_sf.adjust_var_based_rd_partitioning = 2; + + sf->mv_sf.search_method = FAST_DIAMOND; + sf->mv_sf.subpel_force_stop = QUARTER_PEL; + sf->mv_sf.use_fullpel_costlist = 1; + sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; + + sf->inter_sf.adaptive_mode_search = 2; + sf->inter_sf.inter_mode_rd_model_estimation = 2; + + for (int i = 0; i < TX_SIZES; ++i) { + sf->intra_sf.intra_y_mode_mask[i] = INTRA_DC; + sf->intra_sf.intra_uv_mode_mask[i] = UV_INTRA_DC_CFL; + } + + sf->tx_sf.tx_type_search.prune_mode = PRUNE_2D_MORE; + sf->tx_sf.use_inter_txb_hash = 0; + sf->tx_sf.refine_fast_tx_search_results = 0; + + sf->rd_sf.optimize_coefficients = NO_TRELLIS_OPT; + sf->rd_sf.simple_model_rd_from_var = 1; + + sf->lpf_sf.cdef_pick_method = CDEF_PICK_FROM_Q; + sf->lpf_sf.lpf_pick = LPF_PICK_FROM_Q; + + sf->rt_sf.mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH; + sf->rt_sf.num_inter_modes_for_tx_search = 5; + sf->rt_sf.skip_interp_filter_search = 1; + sf->rt_sf.use_comp_ref_nonrd = 0; + sf->rt_sf.use_real_time_ref_set = 1; + sf->rt_sf.use_simple_rd_model = 1; } if (speed >= 6) { - sf->optimize_coefficients = NO_TRELLIS_OPT; - sf->mv.search_method = HEX; - for (int 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; - sf->lpf_pick = LPF_PICK_FROM_Q; - sf->mv.subpel_force_stop = QUARTER_PEL; - sf->default_max_partition_size = BLOCK_128X128; - sf->default_min_partition_size = BLOCK_8X8; - sf->frame_parameter_update = 0; - sf->mv.search_method = FAST_DIAMOND; - sf->partition_search_type = VAR_BASED_PARTITION; - sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH; - sf->use_real_time_ref_set = 1; - sf->tx_type_search.prune_mode = PRUNE_2D_MORE; - // Can't use LARGEST TX mode with pre-calculated partition - // and disabled TX64 - if (!cpi->oxcf.enable_tx64) sf->tx_size_search_level = 1; - sf->use_comp_ref_nonrd = 0; - sf->inter_mode_rd_model_estimation = 2; - sf->cdef_pick_method = CDEF_PICK_FROM_Q; - sf->max_intra_bsize = BLOCK_16X16; - sf->use_inter_txb_hash = 0; - sf->skip_interp_filter_search = 1; -#if 0 - // Turning this off until we agree that tradeoff qualuty vs speed is good. - sf->force_tx_search_off = 1; - sf->num_inter_modes_for_tx_search = 2; -#endif + sf->part_sf.adjust_var_based_rd_partitioning = 1; } - if (speed >= 7) { - sf->lpf_pick = LPF_PICK_FROM_Q; - sf->mv.subpel_force_stop = QUARTER_PEL; - sf->default_max_partition_size = BLOCK_128X128; - sf->default_min_partition_size = BLOCK_8X8; - sf->frame_parameter_update = 0; - sf->mv.search_method = FAST_DIAMOND; - sf->partition_search_type = VAR_BASED_PARTITION; - sf->mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH; - 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_level = 1; - sf->use_nonrd_pick_mode = 1; - sf->use_comp_ref_nonrd = 0; - sf->inter_mode_rd_model_estimation = 2; - sf->cdef_pick_method = CDEF_PICK_FROM_Q; - sf->max_intra_bsize = BLOCK_16X16; - sf->skip_interp_filter_search = 0; - } - if (speed >= 8) { - sf->use_fast_nonrd_pick_mode = 1; - sf->mv.subpel_search_method = SUBPEL_TREE_PRUNED_MORE; - sf->tx_size_search_level = 1; - sf->estimate_motion_for_var_based_partition = 0; - sf->short_circuit_low_temp_var = 3; - sf->reuse_inter_pred_nonrd = 1; - sf->max_intra_bsize = BLOCK_32X32; - // This gives ~2% bdrate improvement but with 5-10% slowdown. - // sf->nonrd_use_blockyrd_interp_filter = 1; -// TODO(kyslov) Enable when better model is available -// It gives +5% speedup and 11% overall BDRate degradation -// So, can not enable now until better CurvFit is there -#if 0 - sf->use_modeled_non_rd_cost = 1; -#endif -// TODO(kyslov) Currently enabling ALTREF leads to 10% -// slowdown with ~3% BDRate gain with current heuristics -// We need to refine it before enabling ALTREF -#if 0 - sf->use_nonrd_altref_frame = 1; -#endif + if (speed >= 7) { + sf->hl_sf.frame_parameter_update = 0; + + sf->part_sf.default_max_partition_size = BLOCK_128X128; + sf->part_sf.default_min_partition_size = BLOCK_8X8; + sf->part_sf.partition_search_type = VAR_BASED_PARTITION; + + sf->mv_sf.search_method = FAST_DIAMOND; + sf->mv_sf.subpel_force_stop = QUARTER_PEL; + sf->mv_sf.subpel_search_method = SUBPEL_TREE_PRUNED; + + sf->inter_sf.inter_mode_rd_model_estimation = 2; + + sf->lpf_sf.cdef_pick_method = CDEF_PICK_FROM_Q; + sf->lpf_sf.lpf_pick = LPF_PICK_FROM_Q; + + sf->rt_sf.mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH; + sf->rt_sf.nonrd_prune_ref_frame_search = 1; + sf->rt_sf.reuse_inter_pred_nonrd = 0; + sf->rt_sf.short_circuit_low_temp_var = 0; + sf->rt_sf.skip_interp_filter_search = 0; + sf->rt_sf.use_comp_ref_nonrd = 0; + sf->rt_sf.use_nonrd_altref_frame = 1; + sf->rt_sf.use_nonrd_pick_mode = 1; + sf->rt_sf.nonrd_check_partition_merge_mode = 1; + sf->rt_sf.nonrd_check_partition_split = 0; + sf->rt_sf.hybrid_intra_pickmode = 1; } + + if (speed >= 8) { + sf->rt_sf.estimate_motion_for_var_based_partition = 0; + sf->rt_sf.short_circuit_low_temp_var = 1; + sf->rt_sf.reuse_inter_pred_nonrd = 1; + sf->rt_sf.use_nonrd_altref_frame = 0; + sf->rt_sf.nonrd_prune_ref_frame_search = 2; + sf->rt_sf.nonrd_check_partition_merge_mode = 0; + sf->rt_sf.nonrd_check_partition_split = 0; + sf->rt_sf.use_modeled_non_rd_cost = 1; + sf->rt_sf.source_metrics_sb_nonrd = 1; + sf->interp_sf.cb_pred_filter_search = 1; + } +} + +static AOM_INLINE void init_hl_sf(HIGH_LEVEL_SPEED_FEATURES *hl_sf) { + // best quality defaults + hl_sf->frame_parameter_update = 1; + hl_sf->recode_loop = ALLOW_RECODE; + hl_sf->disable_overlay_frames = 0; + hl_sf->adaptive_overlay_encoding = 1; + // Recode loop tolerance %. + hl_sf->recode_tolerance = 25; + hl_sf->high_precision_mv_usage = CURRENT_Q; + hl_sf->second_alt_ref_filtering = 1; +} + +static AOM_INLINE void init_tpl_sf(TPL_SPEED_FEATURES *tpl_sf) { + tpl_sf->prune_intra_modes = 0; + tpl_sf->reduce_first_step_size = 0; + tpl_sf->skip_alike_starting_mv = 0; + tpl_sf->subpel_force_stop = EIGHTH_PEL; +} + +static AOM_INLINE void init_gm_sf(GLOBAL_MOTION_SPEED_FEATURES *gm_sf) { + gm_sf->gm_erroradv_type = GM_ERRORADV_TR_0; + gm_sf->disable_adaptive_warp_error_thresh = 1; + gm_sf->selective_ref_gm = 1; + gm_sf->gm_search_type = GM_FULL_SEARCH; + gm_sf->gm_disable_recode = 0; + gm_sf->prune_ref_frame_for_gm_search = 0; +} + +static AOM_INLINE void init_part_sf(PARTITION_SPEED_FEATURES *part_sf) { + part_sf->partition_search_type = SEARCH_PARTITION; + part_sf->less_rectangular_check_level = 0; + part_sf->use_square_partition_only_threshold = BLOCK_128X128; + part_sf->auto_max_partition_based_on_simple_motion = NOT_IN_USE; + part_sf->auto_min_partition_based_on_simple_motion = 0; + part_sf->default_max_partition_size = BLOCK_LARGEST; + part_sf->default_min_partition_size = BLOCK_4X4; + part_sf->adjust_var_based_rd_partitioning = 0; + part_sf->allow_partition_search_skip = 0; + part_sf->max_intra_bsize = BLOCK_LARGEST; + // This setting only takes effect when partition_search_type is set + // to FIXED_PARTITION. + part_sf->always_this_block_size = BLOCK_16X16; + // Recode loop tolerance %. + part_sf->partition_search_breakout_dist_thr = 0; + part_sf->partition_search_breakout_rate_thr = 0; + part_sf->prune_ext_partition_types_search_level = 0; + part_sf->ml_prune_rect_partition = 0; + part_sf->ml_prune_ab_partition = 0; + part_sf->ml_prune_4_partition = 0; + part_sf->ml_early_term_after_part_split_level = 0; + for (int i = 0; i < PARTITION_BLOCK_SIZES; ++i) { + part_sf->ml_partition_search_breakout_thresh[i] = + -1; // -1 means not enabled. + } + part_sf->simple_motion_search_prune_agg = 0; + part_sf->simple_motion_search_split = 0; + part_sf->simple_motion_search_prune_rect = 0; + part_sf->simple_motion_search_early_term_none = 0; + part_sf->intra_cnn_split = 0; + part_sf->ext_partition_eval_thresh = BLOCK_8X8; + part_sf->prune_4_partition_using_split_info = 0; + part_sf->prune_ab_partition_using_split_info = 0; +} + +static AOM_INLINE void init_mv_sf(MV_SPEED_FEATURES *mv_sf) { + mv_sf->full_pixel_search_level = 0; + mv_sf->adaptive_motion_search = 0; + mv_sf->auto_mv_step_size = 0; + mv_sf->exhaustive_searches_thresh = 0; + mv_sf->obmc_full_pixel_search_level = 0; + mv_sf->prune_mesh_search = 0; + mv_sf->reduce_search_range = 0; + mv_sf->search_method = NSTEP; + mv_sf->simple_motion_subpel_force_stop = EIGHTH_PEL; + mv_sf->subpel_force_stop = EIGHTH_PEL; + mv_sf->subpel_iters_per_step = 2; + mv_sf->subpel_search_method = SUBPEL_TREE; + mv_sf->use_accurate_subpel_search = USE_8_TAPS; + mv_sf->use_fullpel_costlist = 0; +} + +static AOM_INLINE void init_inter_sf(INTER_MODE_SPEED_FEATURES *inter_sf) { + inter_sf->comp_inter_joint_search_thresh = BLOCK_4X4; + inter_sf->adaptive_rd_thresh = 0; + inter_sf->model_based_post_interp_filter_breakout = 0; + inter_sf->reduce_inter_modes = 0; + inter_sf->adaptive_mode_search = 0; + inter_sf->alt_ref_search_fp = 0; + inter_sf->selective_ref_frame = 0; + inter_sf->prune_ref_frame_for_rect_partitions = 0; + inter_sf->disable_wedge_search_edge_thresh = 0; + inter_sf->disable_wedge_search_var_thresh = 0; + inter_sf->fast_wedge_sign_estimate = 0; + inter_sf->prune_wedge_pred_diff_based = 0; + inter_sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_ENABLED; + inter_sf->reuse_inter_intra_mode = 0; + inter_sf->disable_sb_level_coeff_cost_upd = 0; + inter_sf->disable_sb_level_mv_cost_upd = 0; + inter_sf->prune_inter_modes_based_on_tpl = 0; + inter_sf->prune_comp_search_by_single_result = 0; + inter_sf->skip_repeated_ref_mv = 0; + inter_sf->skip_repeated_newmv = 0; + inter_sf->skip_repeated_full_newmv = 0; + inter_sf->prune_single_motion_modes_by_simple_trans = 0; + inter_sf->inter_mode_rd_model_estimation = 0; + inter_sf->prune_compound_using_single_ref = 0; + inter_sf->prune_compound_using_neighbors = 0; + inter_sf->disable_onesided_comp = 0; + inter_sf->prune_mode_search_simple_translation = 0; + inter_sf->prune_comp_type_by_comp_avg = 0; + inter_sf->disable_interinter_wedge_newmv_search = 0; + inter_sf->enable_interinter_diffwtd_newmv_search = 0; + inter_sf->disable_smooth_interintra = 0; + inter_sf->prune_motion_mode_level = 0; + inter_sf->prune_warp_using_wmtype = 0; + inter_sf->disable_wedge_interintra_search = 0; + inter_sf->fast_interintra_wedge_search = 0; + inter_sf->prune_comp_type_by_model_rd = 0; + inter_sf->perform_best_rd_based_gating_for_chroma = 0; + inter_sf->prune_obmc_prob_thresh = 0; + inter_sf->disable_obmc = 0; + inter_sf->disable_interinter_wedge = 0; + inter_sf->prune_ref_mv_idx_search = 0; + inter_sf->prune_warped_prob_thresh = 0; + inter_sf->reuse_compound_type_decision = 0; + inter_sf->txfm_rd_gate_level = 0; + inter_sf->prune_inter_modes_if_skippable = 0; +} + +static AOM_INLINE void init_interp_sf(INTERP_FILTER_SPEED_FEATURES *interp_sf) { + interp_sf->disable_filter_search_var_thresh = 0; + interp_sf->adaptive_interp_filter_search = 0; + interp_sf->use_fast_interpolation_filter_search = 0; + interp_sf->disable_dual_filter = 0; + interp_sf->use_interp_filter = 0; + interp_sf->skip_sharp_interp_filter_search = 0; +} + +static AOM_INLINE void init_intra_sf(INTRA_MODE_SPEED_FEATURES *intra_sf) { + intra_sf->skip_intra_in_interframe = 1; + intra_sf->intra_pruning_with_hog = 0; + intra_sf->src_var_thresh_intra_skip = 1; + intra_sf->prune_palette_search_level = 0; + + for (int i = 0; i < TX_SIZES; i++) { + intra_sf->intra_y_mode_mask[i] = INTRA_ALL; + intra_sf->intra_uv_mode_mask[i] = UV_INTRA_ALL; + } + intra_sf->disable_smooth_intra = 0; +} + +static AOM_INLINE void init_tx_sf(TX_SPEED_FEATURES *tx_sf) { + tx_sf->inter_tx_size_search_init_depth_sqr = 0; + tx_sf->inter_tx_size_search_init_depth_rect = 0; + tx_sf->intra_tx_size_search_init_depth_rect = 0; + tx_sf->intra_tx_size_search_init_depth_sqr = 0; + tx_sf->tx_size_search_lgr_block = 0; + tx_sf->model_based_prune_tx_search_level = 0; + tx_sf->tx_type_search.prune_mode = PRUNE_2D_ACCURATE; + tx_sf->tx_type_search.ml_tx_split_thresh = 8500; + tx_sf->tx_type_search.use_skip_flag_prediction = 1; + tx_sf->tx_type_search.use_reduced_intra_txset = 0; + tx_sf->tx_type_search.fast_intra_tx_type_search = 0; + tx_sf->tx_type_search.fast_inter_tx_type_search = 0; + tx_sf->tx_type_search.skip_tx_search = 0; + tx_sf->tx_type_search.prune_tx_type_using_stats = 0; + tx_sf->tx_type_search.prune_tx_type_est_rd = 0; + tx_sf->tx_type_search.enable_winner_mode_tx_type_pruning = 0; + tx_sf->txb_split_cap = 1; + tx_sf->adaptive_txb_search_level = 0; + tx_sf->use_intra_txb_hash = 0; + tx_sf->use_inter_txb_hash = 1; + tx_sf->refine_fast_tx_search_results = 1; +} + +static AOM_INLINE void init_rd_sf(RD_CALC_SPEED_FEATURES *rd_sf, + const AV1_COMP *cpi) { + if (cpi->oxcf.disable_trellis_quant == 3) { + rd_sf->optimize_coefficients = !is_lossless_requested(&cpi->oxcf) + ? NO_ESTIMATE_YRD_TRELLIS_OPT + : NO_TRELLIS_OPT; + } else if (cpi->oxcf.disable_trellis_quant == 2) { + rd_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)) { + rd_sf->optimize_coefficients = NO_TRELLIS_OPT; + } else { + rd_sf->optimize_coefficients = FULL_TRELLIS_OPT; + } + } else if (cpi->oxcf.disable_trellis_quant == 1) { + rd_sf->optimize_coefficients = NO_TRELLIS_OPT; + } else { + assert(0 && "Invalid disable_trellis_quant value"); + } + // TODO(sarahparker) Pair this with a speed setting once experiments are done + rd_sf->trellis_eob_fast = 0; + rd_sf->use_mb_rd_hash = 1; + rd_sf->optimize_b_precheck = 0; + rd_sf->use_fast_coef_costing = 0; + rd_sf->simple_model_rd_from_var = 0; + rd_sf->tx_domain_dist_level = 0; + rd_sf->tx_domain_dist_thres_level = 0; + rd_sf->use_hash_based_trellis = 0; + rd_sf->perform_coeff_opt = 0; +} + +static AOM_INLINE void init_winner_mode_sf( + WINNER_MODE_SPEED_FEATURES *winner_mode_sf) { + winner_mode_sf->motion_mode_for_winner_cand = 0; + // Set this at the appropriate speed levels + winner_mode_sf->tx_size_search_level = USE_FULL_RD; + winner_mode_sf->enable_winner_mode_for_coeff_opt = 0; + winner_mode_sf->enable_winner_mode_for_tx_size_srch = 0; + winner_mode_sf->enable_winner_mode_for_use_tx_domain_dist = 0; + winner_mode_sf->enable_multiwinner_mode_process = 0; +} + +static AOM_INLINE void init_lpf_sf(LOOP_FILTER_SPEED_FEATURES *lpf_sf) { + lpf_sf->disable_loop_restoration_chroma = 0; + lpf_sf->prune_wiener_based_on_src_var = 0; + lpf_sf->prune_sgr_based_on_wiener = 0; + lpf_sf->enable_sgr_ep_pruning = 0; + lpf_sf->reduce_wiener_window_size = 0; + lpf_sf->lpf_pick = LPF_PICK_FROM_FULL_IMAGE; + lpf_sf->cdef_pick_method = CDEF_FULL_SEARCH; + // Set decoder side speed feature to use less dual sgr modes + lpf_sf->dual_sgr_penalty_level = 0; + lpf_sf->disable_lr_filter = 0; +} + +static AOM_INLINE void init_rt_sf(REAL_TIME_SPEED_FEATURES *rt_sf) { + rt_sf->mode_search_skip_flags = 0; + rt_sf->skip_interp_filter_search = 0; + rt_sf->force_tx_search_off = 0; + rt_sf->num_inter_modes_for_tx_search = INT_MAX; + rt_sf->use_simple_rd_model = 0; + rt_sf->nonrd_check_partition_merge_mode = 0; + rt_sf->nonrd_check_partition_split = 0; } void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) { @@ -713,15 +1131,15 @@ void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) { // 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; + cpi->mv_search_params.find_fractional_mv_step = av1_return_max_sub_pixel_mv; else if (cpi->oxcf.motion_vector_unit_test == 2) - cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv; + cpi->mv_search_params.find_fractional_mv_step = av1_return_min_sub_pixel_mv; MACROBLOCK *const x = &cpi->td.mb; AV1_COMMON *const cm = &cpi->common; - x->min_partition_size = AOMMAX(sf->default_min_partition_size, + x->min_partition_size = AOMMAX(sf->part_sf.default_min_partition_size, dim_to_size(cpi->oxcf.min_partition_size)); - x->max_partition_size = AOMMIN(sf->default_max_partition_size, + x->max_partition_size = AOMMIN(sf->part_sf.default_max_partition_size, dim_to_size(cpi->oxcf.max_partition_size)); x->min_partition_size = AOMMIN(x->min_partition_size, cm->seq_params.sb_size); x->max_partition_size = AOMMIN(x->max_partition_size, cm->seq_params.sb_size); @@ -731,180 +1149,23 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { AV1_COMMON *const cm = &cpi->common; SPEED_FEATURES *const sf = &cpi->sf; MACROBLOCK *const x = &cpi->td.mb; + WinnerModeParams *const winner_mode_params = &cpi->winner_mode_params; const AV1EncoderConfig *const oxcf = &cpi->oxcf; int i; - // best quality defaults - sf->frame_parameter_update = 1; - sf->mv.search_method = NSTEP; - sf->recode_loop = ALLOW_RECODE; - sf->mv.subpel_search_method = SUBPEL_TREE; - sf->mv.subpel_iters_per_step = 2; - sf->mv.subpel_force_stop = EIGHTH_PEL; - 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 { - assert(0 && "Invalid disable_trellis_quant value"); - } - sf->gm_erroradv_type = GM_ERRORADV_TR_0; - sf->disable_adaptive_warp_error_thresh = 1; - 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; - // TODO(sarahparker) Pair this with a speed setting once experiments are done - sf->trellis_eob_fast = 0; - 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; - sf->intra_tx_size_search_init_depth_sqr = 0; - sf->tx_size_search_lgr_block = 0; - sf->model_based_prune_tx_search_level = 0; - sf->model_based_post_interp_filter_breakout = 0; - sf->reduce_inter_modes = 0; - sf->selective_ref_gm = 1; - sf->adaptive_motion_search = 0; - sf->adaptive_mode_search = 0; - sf->alt_ref_search_fp = 0; - sf->partition_search_type = SEARCH_PARTITION; - sf->tx_type_search.prune_mode = PRUNE_2D_ACCURATE; - sf->tx_type_search.ml_tx_split_thresh = 8500; - sf->tx_type_search.use_skip_flag_prediction = 1; - sf->tx_type_search.use_reduced_intra_txset = 0; - sf->tx_type_search.fast_intra_tx_type_search = 0; - sf->tx_type_search.fast_inter_tx_type_search = 0; - sf->tx_type_search.skip_tx_search = 0; - sf->tx_type_search.prune_tx_type_using_stats = 0; - sf->selective_ref_frame = 0; - sf->less_rectangular_check_level = 0; - sf->use_square_partition_only_threshold = BLOCK_128X128; - sf->prune_ref_frame_for_rect_partitions = 0; - sf->auto_max_partition_based_on_simple_motion = NOT_IN_USE; - sf->auto_min_partition_based_on_simple_motion = 0; - sf->default_max_partition_size = BLOCK_LARGEST; - sf->default_min_partition_size = BLOCK_4X4; - sf->adjust_partitioning_from_last_frame = 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->disable_wedge_search_var_thresh = 0; - sf->disable_loop_restoration_chroma = 0; - sf->enable_sgr_ep_pruning = 0; - sf->reduce_wiener_window_size = 0; - sf->fast_wedge_sign_estimate = 0; - sf->prune_wedge_pred_diff_based = 0; - sf->drop_ref = 0; - sf->skip_intra_in_interframe = 1; - sf->txb_split_cap = 1; - sf->adaptive_txb_search_level = 0; - sf->use_intra_txb_hash = 0; - sf->use_inter_txb_hash = 1; - sf->use_mb_rd_hash = 1; - sf->optimize_b_precheck = 0; - sf->use_dist_wtd_comp_flag = DIST_WTD_COMP_ENABLED; - sf->reuse_inter_intra_mode = 0; - sf->intra_angle_estimation = 0; - sf->skip_obmc_in_uniform_mv_field = 0; - sf->skip_wm_in_uniform_mv_field = 0; - sf->adaptive_interp_filter_search = 0; - sf->interp_filter_search_mask = ALLOW_ALL_INTERP_FILT_MASK; - sf->src_var_thresh_intra_skip = 1; - sf->reduce_high_precision_mv_usage = 0; - sf->disable_sb_level_coeff_cost_upd = 0; - sf->disable_sb_level_mv_cost_upd = 0; - sf->disable_overlay_frames = 0; - // TODO(yunqing): turn it on for speed 0 if there is gain. - sf->adaptive_overlay_encoding = 0; - sf->skip_interp_filter_search = 0; - sf->force_tx_search_off = 0; - sf->num_inter_modes_for_tx_search = INT_MAX; - - for (i = 0; i < TX_SIZES; i++) { - sf->intra_y_mode_mask[i] = INTRA_ALL; - sf->intra_uv_mode_mask[i] = UV_INTRA_ALL; - } - sf->lpf_pick = LPF_PICK_FROM_FULL_IMAGE; - sf->cdef_pick_method = CDEF_FULL_SEARCH; - sf->use_fast_coef_costing = 0; - sf->max_intra_bsize = BLOCK_LARGEST; - // This setting only takes effect when partition_search_type is set - // to FIXED_PARTITION. - sf->always_this_block_size = BLOCK_16X16; - // Recode loop tolerance %. - sf->recode_tolerance = 25; - sf->partition_search_breakout_dist_thr = 0; - sf->partition_search_breakout_rate_thr = 0; - sf->simple_model_rd_from_var = 0; - sf->prune_ext_partition_types_search_level = 0; - sf->ml_prune_rect_partition = 0; - sf->ml_prune_ab_partition = 0; - sf->ml_prune_4_partition = 0; - sf->ml_early_term_after_part_split_level = 0; - for (i = 0; i < PARTITION_BLOCK_SIZES; ++i) { - sf->ml_partition_search_breakout_thresh[i] = -1; // -1 means not enabled. - } - sf->simple_motion_search_prune_agg = 0; - sf->simple_motion_search_split = 0; - sf->simple_motion_search_prune_rect = 0; - sf->simple_motion_search_early_term_none = 0; - sf->intra_cnn_split = 0; - - // Set this at the appropriate speed levels - sf->tx_size_search_level = cpi->oxcf.tx_size_search_method; - sf->tx_domain_dist_level = 0; - sf->tx_domain_dist_thres_level = 0; - sf->gm_search_type = GM_FULL_SEARCH; - sf->gm_disable_recode = 0; - sf->prune_ref_frame_for_gm_search = 0; - sf->use_fast_interpolation_filter_search = 0; - sf->disable_dual_filter = 0; - sf->skip_repeat_interpolation_filter_search = 0; - sf->use_hash_based_trellis = 0; - sf->prune_comp_search_by_single_result = 0; - sf->skip_repeated_newmv = 0; - // TODO(any) Cleanup this speed feature - sf->prune_single_motion_modes_by_simple_trans = 0; - - // Set decoder side speed feature to use less dual sgr modes - sf->dual_sgr_penalty_level = 0; - - sf->inter_mode_rd_model_estimation = 0; - sf->prune_compound_using_single_ref = 0; - - sf->prune_mode_search_simple_translation = 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->enable_interinter_diffwtd_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->enable_winner_mode_for_coeff_opt = 0; - sf->enable_winner_mode_for_tx_size_srch = 0; - sf->enable_winner_mode_for_use_tx_domain_dist = 0; - sf->enable_multiwinner_mode_process = 0; - sf->prune_comp_type_by_model_rd = 0; - sf->disable_smooth_intra = 0; - sf->perform_best_rd_based_gating_for_chroma = 0; - sf->prune_obmc_using_stats = 0; + init_hl_sf(&sf->hl_sf); + init_tpl_sf(&sf->tpl_sf); + init_gm_sf(&sf->gm_sf); + init_part_sf(&sf->part_sf); + init_mv_sf(&sf->mv_sf); + init_inter_sf(&sf->inter_sf); + init_interp_sf(&sf->interp_sf); + init_intra_sf(&sf->intra_sf); + init_tx_sf(&sf->tx_sf); + init_rd_sf(&sf->rd_sf, cpi); + init_winner_mode_sf(&sf->winner_mode_sf); + init_lpf_sf(&sf->lpf_sf); + init_rt_sf(&sf->rt_sf); if (oxcf->mode == GOOD) set_good_speed_features_framesize_independent(cpi, sf, speed); @@ -912,32 +1173,23 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { 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; + cpi->common.seq_params.enable_dual_filter &= + !sf->interp_sf.disable_dual_filter; + cpi->common.seq_params.enable_restoration &= !sf->lpf_sf.disable_lr_filter; } - // sf->partition_search_breakout_dist_thr is set assuming max 64x64 + // sf->part_sf.partition_search_breakout_dist_thr is set assuming max 64x64 // blocks. Normalise this if the blocks are bigger. if (MAX_SB_SIZE_LOG2 > 6) { - sf->partition_search_breakout_dist_thr <<= 2 * (MAX_SB_SIZE_LOG2 - 6); + sf->part_sf.partition_search_breakout_dist_thr <<= + 2 * (MAX_SB_SIZE_LOG2 - 6); } - cpi->diamond_search_sad = av1_diamond_search_sad; - - sf->allow_exhaustive_searches = 1; - const int mesh_speed = AOMMIN(speed, MAX_MESH_SPEED); - if (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION) - sf->exhaustive_searches_thresh = (1 << 24); - else - sf->exhaustive_searches_thresh = (1 << 25); - sf->max_exhaustive_pct = good_quality_max_mesh_pct[mesh_speed]; - if (mesh_speed > 0) - sf->exhaustive_searches_thresh = sf->exhaustive_searches_thresh << 1; - for (i = 0; i < MAX_MESH_STEP; ++i) { - sf->mesh_patterns[i].range = + sf->mv_sf.mesh_patterns[i].range = good_quality_mesh_patterns[mesh_speed][i].range; - sf->mesh_patterns[i].interval = + sf->mv_sf.mesh_patterns[i].interval = good_quality_mesh_patterns[mesh_speed][i].interval; } @@ -945,85 +1197,126 @@ void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) { // Though intraBC mesh pattern is populated for all frame types, it is used // only for intra frames of screen contents for (i = 0; i < MAX_MESH_STEP; ++i) { - sf->intrabc_mesh_patterns[i].range = + sf->mv_sf.intrabc_mesh_patterns[i].range = intrabc_mesh_patterns[mesh_speed][i].range; - sf->intrabc_mesh_patterns[i].interval = + sf->mv_sf.intrabc_mesh_patterns[i].interval = intrabc_mesh_patterns[mesh_speed][i].interval; } - sf->intrabc_max_exhaustive_pct = intrabc_max_mesh_pct[mesh_speed]; // Slow quant, dct and trellis not worthwhile for first pass // so make sure they are always turned off. - if (oxcf->pass == 1) sf->optimize_coefficients = NO_TRELLIS_OPT; + if (is_stat_generation_stage(cpi)) + sf->rd_sf.optimize_coefficients = NO_TRELLIS_OPT; // No recode or trellis for 1 pass. - if (oxcf->pass == 0) sf->recode_loop = DISALLOW_RECODE; + if (oxcf->pass == 0) sf->hl_sf.recode_loop = DISALLOW_RECODE; - if (sf->mv.subpel_search_method == SUBPEL_TREE) { - cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree; - } else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED) { - cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned; - } else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_MORE) { - cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned_more; - } else if (sf->mv.subpel_search_method == SUBPEL_TREE_PRUNED_EVENMORE) { - cpi->find_fractional_mv_step = av1_find_best_sub_pixel_tree_pruned_evenmore; + MotionVectorSearchParams *const mv_search_params = &cpi->mv_search_params; + if (sf->mv_sf.subpel_search_method == SUBPEL_TREE) { + mv_search_params->find_fractional_mv_step = av1_find_best_sub_pixel_tree; + } else if (sf->mv_sf.subpel_search_method == SUBPEL_TREE_PRUNED) { + mv_search_params->find_fractional_mv_step = + av1_find_best_sub_pixel_tree_pruned; + } else if (sf->mv_sf.subpel_search_method == SUBPEL_TREE_PRUNED_MORE) { + mv_search_params->find_fractional_mv_step = + av1_find_best_sub_pixel_tree_pruned_more; + } else if (sf->mv_sf.subpel_search_method == SUBPEL_TREE_PRUNED_EVENMORE) { + mv_search_params->find_fractional_mv_step = + av1_find_best_sub_pixel_tree_pruned_evenmore; } - x->min_partition_size = AOMMAX(sf->default_min_partition_size, + x->min_partition_size = AOMMAX(sf->part_sf.default_min_partition_size, dim_to_size(cpi->oxcf.min_partition_size)); - x->max_partition_size = AOMMIN(sf->default_max_partition_size, + x->max_partition_size = AOMMIN(sf->part_sf.default_max_partition_size, dim_to_size(cpi->oxcf.max_partition_size)); x->min_partition_size = AOMMIN(x->min_partition_size, cm->seq_params.sb_size); x->max_partition_size = AOMMIN(x->max_partition_size, cm->seq_params.sb_size); // 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; + mv_search_params->find_fractional_mv_step = av1_return_max_sub_pixel_mv; else if (cpi->oxcf.motion_vector_unit_test == 2) - cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv; - cpi->max_comp_type_rd_threshold_mul = - comp_type_rd_threshold_mul[sf->prune_comp_type_by_comp_avg]; - cpi->max_comp_type_rd_threshold_div = - comp_type_rd_threshold_div[sf->prune_comp_type_by_comp_avg]; + mv_search_params->find_fractional_mv_step = av1_return_min_sub_pixel_mv; // assert ensures that tx_domain_dist_level is accessed correctly - assert(cpi->sf.tx_domain_dist_thres_level >= 0 && - cpi->sf.tx_domain_dist_thres_level < 3); - memcpy(cpi->tx_domain_dist_threshold, - tx_domain_dist_thresholds[cpi->sf.tx_domain_dist_thres_level], - sizeof(cpi->tx_domain_dist_threshold)); + assert(cpi->sf.rd_sf.tx_domain_dist_thres_level >= 0 && + cpi->sf.rd_sf.tx_domain_dist_thres_level < 3); + memcpy(winner_mode_params->tx_domain_dist_threshold, + tx_domain_dist_thresholds[cpi->sf.rd_sf.tx_domain_dist_thres_level], + sizeof(winner_mode_params->tx_domain_dist_threshold)); - assert(cpi->sf.tx_domain_dist_level >= 0 && cpi->sf.tx_domain_dist_level < 3); - memcpy(cpi->use_transform_domain_distortion, - tx_domain_dist_types[cpi->sf.tx_domain_dist_level], - sizeof(cpi->use_transform_domain_distortion)); + assert(cpi->sf.rd_sf.tx_domain_dist_level >= 0 && + cpi->sf.rd_sf.tx_domain_dist_level < 3); + memcpy(winner_mode_params->use_transform_domain_distortion, + tx_domain_dist_types[cpi->sf.rd_sf.tx_domain_dist_level], + sizeof(winner_mode_params->use_transform_domain_distortion)); // assert ensures that coeff_opt_dist_thresholds is accessed correctly - assert(cpi->sf.perform_coeff_opt >= 0 && cpi->sf.perform_coeff_opt < 5); - memcpy(cpi->coeff_opt_dist_threshold, - coeff_opt_dist_thresholds[cpi->sf.perform_coeff_opt], - sizeof(cpi->coeff_opt_dist_threshold)); + assert(cpi->sf.rd_sf.perform_coeff_opt >= 0 && + cpi->sf.rd_sf.perform_coeff_opt < 6); + memcpy(winner_mode_params->coeff_opt_dist_threshold, + coeff_opt_dist_thresholds[cpi->sf.rd_sf.perform_coeff_opt], + sizeof(winner_mode_params->coeff_opt_dist_threshold)); + + // assert ensures that predict_skip_levels is accessed correctly + assert(cpi->sf.tx_sf.tx_type_search.use_skip_flag_prediction >= 0 && + cpi->sf.tx_sf.tx_type_search.use_skip_flag_prediction < 3); + memcpy(winner_mode_params->predict_skip_level, + predict_skip_levels[cpi->sf.tx_sf.tx_type_search + .use_skip_flag_prediction], + sizeof(winner_mode_params->predict_skip_level)); - // Override speed feature setting for user config - if (cpi->oxcf.tx_size_search_method != USE_FULL_RD) { - cpi->sf.enable_winner_mode_for_tx_size_srch = 0; - cpi->sf.tx_size_search_level = cpi->oxcf.tx_size_search_method; - } // assert ensures that tx_size_search_level is accessed correctly - assert(cpi->sf.tx_size_search_level >= 0 && cpi->sf.tx_size_search_level < 3); - memcpy(cpi->tx_size_search_methods, - tx_size_search_methods[cpi->sf.tx_size_search_level], - sizeof(cpi->tx_size_search_methods)); + assert(cpi->sf.winner_mode_sf.tx_size_search_level >= 0 && + cpi->sf.winner_mode_sf.tx_size_search_level < 3); + memcpy(winner_mode_params->tx_size_search_methods, + tx_size_search_methods[cpi->sf.winner_mode_sf.tx_size_search_level], + sizeof(winner_mode_params->tx_size_search_methods)); -#if CONFIG_DIST_8X8 - if (sf->tx_domain_dist_level > 0) cpi->oxcf.using_dist_8x8 = 0; - - if (cpi->oxcf.using_dist_8x8) x->min_partition_size = BLOCK_8X8; -#endif // CONFIG_DIST_8X8 if (cpi->oxcf.row_mt == 1 && (cpi->oxcf.max_threads > 1)) { - if (sf->inter_mode_rd_model_estimation == 1) { + if (sf->inter_sf.inter_mode_rd_model_estimation == 1) { // Revert to type 2 - sf->inter_mode_rd_model_estimation = 2; + sf->inter_sf.inter_mode_rd_model_estimation = 2; + } + } +} + +// Override some speed features based on qindex +void av1_set_speed_features_qindex_dependent(AV1_COMP *cpi, int speed) { + AV1_COMMON *const cm = &cpi->common; + SPEED_FEATURES *const sf = &cpi->sf; + WinnerModeParams *const winner_mode_params = &cpi->winner_mode_params; + const int boosted = frame_is_boosted(cpi); + const int is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720; + if (is_720p_or_larger && cpi->oxcf.mode == GOOD && speed == 0) { + if (cm->quant_params.base_qindex <= 80) { + sf->rd_sf.perform_coeff_opt = 2; + memcpy(winner_mode_params->coeff_opt_dist_threshold, + coeff_opt_dist_thresholds[sf->rd_sf.perform_coeff_opt], + sizeof(winner_mode_params->coeff_opt_dist_threshold)); + sf->part_sf.simple_motion_search_split = + cm->features.allow_screen_content_tools ? 1 : 2; + sf->tx_sf.inter_tx_size_search_init_depth_rect = 1; + sf->tx_sf.inter_tx_size_search_init_depth_sqr = 1; + sf->tx_sf.intra_tx_size_search_init_depth_rect = 1; + } + } + + if (cpi->oxcf.mode == GOOD && speed >= 3) { + // Disable extended partitions for lower quantizers + if (cm->quant_params.base_qindex <= 100 && + !cm->features.allow_screen_content_tools && !boosted) { + sf->part_sf.ext_partition_eval_thresh = BLOCK_128X128; + } + } + + if (cpi->oxcf.mode == GOOD && speed >= 4) { + // Disable extended partitions for lower quantizers + const int qindex_thresh = boosted ? 80 : 120; + if (cm->quant_params.base_qindex <= qindex_thresh && + !cm->features.allow_screen_content_tools && + !frame_is_intra_only(&cpi->common)) { + sf->part_sf.ext_partition_eval_thresh = BLOCK_128X128; } } } diff --git a/media/libaom/src/av1/encoder/speed_features.h b/media/libaom/src/av1/encoder/speed_features.h index 7cb63c6d59..d12c3c02e1 100644 --- a/media/libaom/src/av1/encoder/speed_features.h +++ b/media/libaom/src/av1/encoder/speed_features.h @@ -18,6 +18,38 @@ extern "C" { #endif +#define MAX_MESH_STEP 4 + +typedef struct MESH_PATTERN { + int range; + int interval; +} MESH_PATTERN; + +enum { + GM_FULL_SEARCH, + GM_REDUCED_REF_SEARCH_SKIP_L2_L3, + GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2, + GM_DISABLE_SEARCH +} UENUM1BYTE(GM_SEARCH_TYPE); + +enum { + GM_ERRORADV_TR_0, + GM_ERRORADV_TR_1, + GM_ERRORADV_TR_2, + GM_ERRORADV_TR_TYPES, +} UENUM1BYTE(GM_ERRORADV_TYPE); + +enum { + FULL_TXFM_RD, + LOW_TXFM_RD, +} UENUM1BYTE(TXFM_RD_MODEL); + +enum { + DIST_WTD_COMP_ENABLED, + DIST_WTD_COMP_SKIP_MV_SEARCH, + DIST_WTD_COMP_DISABLED, +} UENUM1BYTE(DIST_WTD_COMP_FLAG); + enum { INTRA_ALL = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED) | (1 << D45_PRED) | (1 << D135_PRED) | (1 << D113_PRED) | (1 << D157_PRED) | @@ -84,16 +116,6 @@ enum { RESERVE_3_SF = 128, } UENUM1BYTE(DEV_SPEED_FEATURES); -enum { - DIAMOND = 0, - NSTEP = 1, - HEX = 2, - BIGDIA = 3, - SQUARE = 4, - FAST_HEX = 5, - FAST_DIAMOND = 6 -} UENUM1BYTE(SEARCH_METHODS); - enum { // No recode. DISALLOW_RECODE = 0, @@ -122,6 +144,8 @@ enum { enum { // Try the full image with different values. LPF_PICK_FROM_FULL_IMAGE, + // Try the full image filter search with non-dual filter only. + LPF_PICK_FROM_FULL_IMAGE_NON_DUAL, // Try a small portion of the image with different values. LPF_PICK_FROM_SUBIMAGE, // Estimate the level based on quantizer and frame type @@ -132,8 +156,10 @@ enum { enum { CDEF_FULL_SEARCH, - CDEF_FAST_SEARCH, // Search among a subset of all possible filters. - CDEF_PICK_FROM_Q // Estimate filter strength based on quantizer. + CDEF_FAST_SEARCH_LVL1, // Search among a subset of all possible filters. + CDEF_FAST_SEARCH_LVL2, // Search reduced subset of filters than Level 1. + CDEF_PICK_FROM_Q, // Estimate filter strength based on quantizer. + CDEF_PICK_METHODS } UENUM1BYTE(CDEF_PICK_METHOD); enum { @@ -163,6 +189,8 @@ enum { // similar, but applies much more aggressive pruning to get better speed-up PRUNE_2D_FAST = 2, PRUNE_2D_MORE = 3, + // More aggressive pruning based on tx type score and allowed tx count + PRUNE_2D_AGGRESSIVE = 4, } UENUM1BYTE(TX_TYPE_PRUNE_MODE); typedef struct { @@ -186,6 +214,14 @@ typedef struct { // Prune tx type search using previous frame stats. int prune_tx_type_using_stats; + // Prune tx type search using estimated RDcost + int prune_tx_type_est_rd; + + // Flag used to control the winner mode processing for tx type pruning for + // inter blocks. It enables further tx type mode pruning based on ML model for + // mode evaluation and disables tx type mode pruning for winner mode + // processing. + int enable_winner_mode_tx_type_pruning; } TX_TYPE_SEARCH; enum { @@ -200,13 +236,6 @@ enum { VAR_BASED_PARTITION } UENUM1BYTE(PARTITION_SEARCH_TYPE); -enum { - EIGHTH_PEL, - QUARTER_PEL, - HALF_PEL, - FULL_PEL -} UENUM1BYTE(SUBPEL_FORCE_STOP); - enum { NOT_IN_USE, DIRECT_PRED, @@ -214,86 +243,35 @@ enum { 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; - - // This parameter controls which step in the n-step process we start at. - // It's changed adaptively based on circumstances. - int reduce_first_step_size; - - // If this is set to 1, we limit the motion search range to 2 times the - // largest motion vector found in the last frame. - int auto_mv_step_size; - - // Subpel_search_method can only be subpel_tree which does a subpixel - // logarithmic search that keeps stepping at 1/2 pixel units until - // you stop getting a gain, and then goes on to 1/4 and repeats - // the same process. Along the way it skips many diagonals. - SUBPEL_SEARCH_METHODS subpel_search_method; - - // Maximum number of steps in logarithmic subpel search before giving up. - int subpel_iters_per_step; - - // When to stop subpel search. - SUBPEL_FORCE_STOP subpel_force_stop; -} MV_SPEED_FEATURES; - -#define MAX_MESH_STEP 4 - -typedef struct MESH_PATTERN { - int range; - int interval; -} MESH_PATTERN; - enum { - GM_FULL_SEARCH, - GM_REDUCED_REF_SEARCH_SKIP_L2_L3, - GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2, - GM_DISABLE_SEARCH -} UENUM1BYTE(GM_SEARCH_TYPE); - -enum { - GM_ERRORADV_TR_0, - GM_ERRORADV_TR_1, - GM_ERRORADV_TR_2, - GM_ERRORADV_TR_TYPES, -} 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_ESTIMATE_YRD_TRELLIS_OPT // Disable trellis in estimate_yrd_for_sb -} UENUM1BYTE(TRELLIS_OPT_TYPE); - -enum { - FULL_TXFM_RD, - LOW_TXFM_RD, -} UENUM1BYTE(TXFM_RD_MODEL); - -enum { - DIST_WTD_COMP_ENABLED, - DIST_WTD_COMP_SKIP_MV_SEARCH, - DIST_WTD_COMP_DISABLED, -} UENUM1BYTE(DIST_WTD_COMP_FLAG); - -typedef struct SPEED_FEATURES { - MV_SPEED_FEATURES mv; + LAST_MV_DATA, + CURRENT_Q, + QTR_ONLY, +} UENUM1BYTE(MV_PREC_LOGIC); +typedef struct HIGH_LEVEL_SPEED_FEATURES { // Frame level coding parameter update int frame_parameter_update; RECODE_LOOP_TYPE recode_loop; - // Trellis (dynamic programming) optimization of quantized values - TRELLIS_OPT_TYPE optimize_coefficients; + // This feature controls the tolerence vs target used in deciding whether to + // recode a frame. It has no meaning if recode is disabled. + int recode_tolerance; - // Global motion warp error threshold - GM_ERRORADV_TYPE gm_erroradv_type; + // Determine how motion vector precision is chosen. The possibilities are: + // LAST_MV_DATA: use the mv data from the last coded frame + // CURRENT_Q: use the current q as a threshold + // QTR_ONLY: use quarter pel precision only. + MV_PREC_LOGIC high_precision_mv_usage; - // Disable adaptive threshold for global motion warp error - int disable_adaptive_warp_error_thresh; + // Whether to disable overlay frames for filtered Altref frames, + // overiding oxcf->enable_overlay flag set as 1. + int disable_overlay_frames; + + // Enable/disable adaptively deciding whether or not to encode ALTREF overlay + // frame. + int adaptive_overlay_encoding; // Always set to 0. If on it enables 0 cost background transmission // (except for the initial transmission of the segmentation). The feature is @@ -302,67 +280,58 @@ typedef struct SPEED_FEATURES { // adds overhead. int static_segmentation; - // Limit the inter mode tested in the RD loop - int reduce_inter_modes; + // Enable/disable second_alt_ref temporal filtering. + int second_alt_ref_filtering; +} HIGH_LEVEL_SPEED_FEATURES; + +typedef struct TPL_SPEED_FEATURES { + // Prune the intra modes search by tpl. + // If set to 0, we will search all intra modes from DC_PRED to PAETH_PRED. + // If set to 1, we only search DC_PRED, V_PRED, and H_PRED. + int prune_intra_modes; + // This parameter controls which step in the n-step process we start at. + int reduce_first_step_size; + // Skip motion estimation based on the precision of center MVs and the + // difference between center MVs. + // If set to 0, motion estimation is skipped for duplicate center MVs + // (default). If set to 1, motion estimation is skipped for duplicate + // full-pixel center MVs. If set to 2, motion estimation is skipped if the + // difference between center MVs is less than the threshold. + int skip_alike_starting_mv; + + // When to stop subpel search. + SUBPEL_FORCE_STOP subpel_force_stop; +} TPL_SPEED_FEATURES; + +typedef struct GLOBAL_MOTION_SPEED_FEATURES { + // Global motion warp error threshold + GM_ERRORADV_TYPE gm_erroradv_type; + + // Disable adaptive threshold for global motion warp error + int disable_adaptive_warp_error_thresh; // Do not compute the global motion parameters for a LAST2_FRAME or // LAST3_FRAME if the GOLDEN_FRAME is closer and it has a non identity // global model. int selective_ref_gm; - // If 1 we iterate finding a best reference for 2 ref frames together - via - // a log search that iterates 4 times (check around mv for last for best - // error of combined predictor then check around mv for alt). If 0 we - // we just use the best motion vector found for each frame by itself. - BLOCK_SIZE comp_inter_joint_search_thresh; + GM_SEARCH_TYPE gm_search_type; - // This variable is used to cap the maximum number of times we skip testing a - // mode to be evaluated. A high value means we will be faster. - int adaptive_rd_thresh; + // whether to disable the global motion recode loop + int gm_disable_recode; - // Init search depth for square and rectangular transform partitions. - // Values: - // 0 - search full tree, 1: search 1 level, 2: search the highest level only - int inter_tx_size_search_init_depth_sqr; - int inter_tx_size_search_init_depth_rect; - int intra_tx_size_search_init_depth_sqr; - int intra_tx_size_search_init_depth_rect; - // If any dimension of a coding block size above 64, always search the - // largest transform only, since the largest transform block size is 64x64. - int tx_size_search_lgr_block; + // During global motion estimation, prune remaining reference frames in a + // given direction(past/future), if the evaluated ref_frame in that direction + // yields gm_type as INVALID/TRANSLATION/IDENTITY + int prune_ref_frame_for_gm_search; +} GLOBAL_MOTION_SPEED_FEATURES; +typedef struct PARTITION_SPEED_FEATURES { PARTITION_SEARCH_TYPE partition_search_type; - TX_TYPE_SEARCH tx_type_search; - - // Skip split transform block partition when the collocated bigger block - // is selected as all zero coefficients. - int txb_split_cap; - - // Shortcut the transform block partition and type search when the target - // rdcost is relatively lower. - // Values are 0 (not used) , or 1 - 2 with progressively increasing - // aggressiveness - int adaptive_txb_search_level; - - // Prune level for tx_size_type search for inter based on rd model - // 0: no pruning - // 1-2: progressively increasing aggressiveness of pruning - int model_based_prune_tx_search_level; - - // Model based breakout after interpolation filter search - // 0: no breakout - // 1: use model based rd breakout - int model_based_post_interp_filter_breakout; - // Used if partition_search_type = FIXED_SIZE_PARTITION BLOCK_SIZE always_this_block_size; - // Drop less likely to be picked reference frames in the RD search. - // Has five levels for now: 0, 1, 2, 3 and 4, where higher levels prune more - // aggressively than lower ones. (0 means no pruning). - int selective_ref_frame; - // Prune extended partition types search // Can take values 0 - 2, 0 referring to no pruning, and 1 - 2 increasing // aggressiveness of pruning in order. @@ -390,12 +359,6 @@ typedef struct SPEED_FEATURES { // Use square partition only beyond this block size. 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; - // Sets min and max square partition levels for this superblock based on // motion vector and prediction error distribution produced from 16x16 // simple motion search @@ -407,83 +370,11 @@ typedef struct SPEED_FEATURES { BLOCK_SIZE default_min_partition_size; BLOCK_SIZE default_max_partition_size; - // Whether or not we allow partitions one smaller or one greater than the last - // frame's partitioning. Only used if use_lastframe_partitioning is set. - int adjust_partitioning_from_last_frame; - - // 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. - int adaptive_motion_search; - - // Flag for allowing some use of exhaustive searches; - int allow_exhaustive_searches; - - // Threshold for allowing exhaistive motion search. - int exhaustive_searches_thresh; - - // Maximum number of exhaustive searches for a frame (except for intraBC ME). - int max_exhaustive_pct; - - // Maximum number of exhaustive searches in a frame for intraBC ME. - int intrabc_max_exhaustive_pct; - - // Pattern to be used for any exhaustive mesh searches (except intraBC ME). - MESH_PATTERN mesh_patterns[MAX_MESH_STEP]; - - // Pattern to be used for exhaustive mesh searches of intraBC ME. - MESH_PATTERN intrabc_mesh_patterns[MAX_MESH_STEP]; - - // Adaptive prediction mode search - int adaptive_mode_search; - - int alt_ref_search_fp; - - // Implements various heuristics to skip searching modes - // The heuristics selected are based on flags - // defined in the MODE_SEARCH_SKIP_HEURISTICS enum - unsigned int mode_search_skip_flags; - - // A source variance threshold below which filter search is disabled - // Choose a very large value (UINT_MAX) to use 8-tap always - unsigned int disable_filter_search_var_thresh; - - // Only enable wedge search if the edge strength is greater than - // this threshold. A value of 0 signals that this check is disabled. - unsigned int disable_wedge_search_edge_thresh; - - // Only enable wedge search if the variance is above this threshold. - unsigned int disable_wedge_search_var_thresh; - - // Whether fast wedge sign estimate is used - int fast_wedge_sign_estimate; - - // Whether to prune wedge search based on predictor difference - int prune_wedge_pred_diff_based; - - // These bit masks allow you to enable or disable intra modes for each - // transform size separately. - int intra_y_mode_mask[TX_SIZES]; - int intra_uv_mode_mask[TX_SIZES]; - - // This feature controls how the loop filter level is determined. - LPF_PICK_METHOD lpf_pick; - - // Control how the CDEF strength is determined. - CDEF_PICK_METHOD cdef_pick_method; - - // This feature controls whether we do the expensive context update and - // calculation in the rd coefficient costing loop. - int use_fast_coef_costing; - - // This feature controls the tolerence vs target used in deciding whether to - // recode a frame. It has no meaning if recode is disabled. - int recode_tolerance; - - // This variable controls the maximum block size where intra blocks can be - // used in inter frames. - // TODO(aconverse): Fold this into one of the other many mode skips - BLOCK_SIZE max_intra_bsize; + // Sets level of adjustmet of variace-based partitioning during + // rd_use_partition 0 - no partition adjusment, 1 - try to merge partitions + // for small blocks and high QP, 2 - always try to merge leaf partitions, 3 - + // try to merge and split leaf partitions + int adjust_var_based_rd_partitioning; // Partition search early breakout thresholds. int64_t partition_search_breakout_dist_thr; @@ -495,154 +386,6 @@ typedef struct SPEED_FEATURES { // Allow skipping partition search for still image frame int allow_partition_search_skip; - // Fast approximation of av1_model_rd_from_var_lapndz - int simple_model_rd_from_var; - - // If true, sub-pixel search uses the exact convolve function used for final - // encoding and decoding; otherwise, it uses bilinear interpolation. - SUBPEL_SEARCH_TYPE use_accurate_subpel_search; - - // Whether to compute distortion in the image domain (slower but - // more accurate), or in the transform domain (faster but less acurate). - // 0: use image domain - // 1: use transform domain in tx_type search, and use image domain for - // RD_STATS - // 2: use transform domain - int tx_domain_dist_level; - - // Transform domain distortion threshold level - int tx_domain_dist_thres_level; - - GM_SEARCH_TYPE gm_search_type; - - // whether to disable the global motion recode loop - int gm_disable_recode; - - // During global motion estimation, prune remaining reference frames in a - // given direction(past/future), if the evaluated ref_frame in that direction - // yields gm_type as INVALID/TRANSLATION/IDENTITY - int prune_ref_frame_for_gm_search; - - // Do limited interpolation filter search for dual filters, since best choice - // usually includes EIGHTTAP_REGULAR. - int use_fast_interpolation_filter_search; - - // Disable dual filter - int disable_dual_filter; - - // Save results of interpolation_filter_search for a block - // Check mv and ref_frames before search, if they are same with previous - // saved results, it can be skipped. - int skip_repeat_interpolation_filter_search; - - // Use a hash table to store previously computed optimized qcoeffs from - // expensive calls to optimize_txb. - int use_hash_based_trellis; - - // flag to drop some ref frames in compound motion search - int drop_ref; - - // flag to allow skipping intra mode for inter frame prediction - int skip_intra_in_interframe; - - // variance threshold for intra mode gating when inter turned out to be skip - // in inter frame prediction - unsigned int src_var_thresh_intra_skip; - - // Use hash table to store intra(keyframe only) txb transform search results - // to avoid repeated search on the same residue signal. - int use_intra_txb_hash; - - // Use hash table to store inter txb transform search results - // to avoid repeated search on the same residue signal. - int use_inter_txb_hash; - - // Use hash table to store macroblock RD search results - // to avoid repeated search on the same residue signal. - int use_mb_rd_hash; - - // Calculate RD cost before doing optimize_b, and skip if the cost is large. - int optimize_b_precheck; - - // Decide when and how to use joint_comp. - DIST_WTD_COMP_FLAG use_dist_wtd_comp_flag; - - // Decoder side speed feature to add penalty for use of dual-sgr filters. - // Takes values 0 - 10, 0 indicating no penalty and each additional level - // adding a penalty of 1% - int dual_sgr_penalty_level; - - // 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: - // 0: not used - // 1: used with online dynamic rd model - // 2: used with static rd model - int inter_mode_rd_model_estimation; - - // Skip some ref frames in compound motion search by single motion search - // result. Has three levels for now: 0 referring to no skipping, and 1 - 3 - // increasing aggressiveness of skipping in order. - // Note: The search order might affect the result. It assumes that the single - // reference modes are searched before compound modes. It is better to search - // same single inter mode as a group. - int prune_comp_search_by_single_result; - - // Skip certain motion modes (OBMC, warped, interintra) for single reference - // motion search, using the results of single ref SIMPLE_TRANSLATION - int prune_single_motion_modes_by_simple_trans; - - // Reuse the inter_intra_mode search result from NEARESTMV mode to other - // single ref modes - int reuse_inter_intra_mode; - - // Set the full pixel search level of obmc - // 0: obmc_full_pixel_diamond - // 1: obmc_refining_search_sad (faster) - int obmc_full_pixel_search_level; - - // flag to skip NEWMV mode in drl if the motion search result is the same - int skip_repeated_newmv; - - // Prune intra mode candidates based on source block gradient stats. - int intra_angle_estimation; - - // Skip obmc or warped motion mode when neighborhood motion field is - // identical - int skip_obmc_in_uniform_mv_field; - int skip_wm_in_uniform_mv_field; - - // Enable/disable ME for interinter wedge search. - int disable_interinter_wedge_newmv_search; - - // Enable/disable ME for interinter diffwtd search. PSNR BD-rate gain of - // ~0.1 on the lowres test set, but ~15% slower computation. - int enable_interinter_diffwtd_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; - - // prune wedge and compound segment approximate rd evaluation based on - // compound average rd/ref_best_rd - int prune_comp_type_by_comp_avg; - - // Prune/gate motion mode evaluation based on token based rd - // during transform search for inter blocks - // Values are 0 (not used) , 1 - 3 with progressively increasing - // aggressiveness - int prune_motion_mode_level; - - // prune sgr ep using binary search like mechanism - int enable_sgr_ep_pruning; - - // Gate warp evaluation for motions of type IDENTITY, - // TRANSLATION and AFFINE(based on number of warp neighbors) - int prune_warp_using_wmtype; - // The aggresiveness of pruning with simple_motion_search. // Currently 0 is the lowest, and 2 the highest. int simple_motion_search_prune_agg; @@ -662,26 +405,415 @@ typedef struct SPEED_FEATURES { // partition after PARTITION_NONE int simple_motion_search_early_term_none; - int cb_pred_filter_search; + // This variable controls the maximum block size where intra blocks can be + // used in inter frames. + // TODO(aconverse): Fold this into one of the other many mode skips + BLOCK_SIZE max_intra_bsize; - // adaptive interp_filter search to allow skip of certain filter types. - int adaptive_interp_filter_search; + // Use CNN with luma pixels on source frame on each of the 64x64 subblock to + // perform split/no_split decision on intra-frames. + int intra_cnn_split; + + // Disable extended partition search for lower block sizes. + int ext_partition_eval_thresh; + + // Prune 1:4 partition search based on winner info from split partitions + int prune_4_partition_using_split_info; + + // Prune AB partition search using split and HORZ/VERT info + int prune_ab_partition_using_split_info; +} PARTITION_SPEED_FEATURES; + +typedef struct MV_SPEED_FEATURES { + // Motion search method (Diamond, NSTEP, Hex, Big Diamond, Square, etc). + SEARCH_METHODS search_method; + + // If this is set to 1, we limit the motion search range to 2 times the + // largest motion vector found in the last frame. + int auto_mv_step_size; + + // Subpel_search_method can only be subpel_tree which does a subpixel + // logarithmic search that keeps stepping at 1/2 pixel units until + // you stop getting a gain, and then goes on to 1/4 and repeats + // the same process. Along the way it skips many diagonals. + SUBPEL_SEARCH_METHODS subpel_search_method; + + // Maximum number of steps in logarithmic subpel search before giving up. + int subpel_iters_per_step; + + // When to stop subpel search. + SUBPEL_FORCE_STOP subpel_force_stop; + + // When to stop subpel search in simple motion search. + SUBPEL_FORCE_STOP simple_motion_subpel_force_stop; + + // If true, sub-pixel search uses the exact convolve function used for final + // encoding and decoding; otherwise, it uses bilinear interpolation. + SUBPEL_SEARCH_TYPE use_accurate_subpel_search; + + // 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. + int adaptive_motion_search; + + // Threshold for allowing exhaustive motion search. + int exhaustive_searches_thresh; + + // Pattern to be used for any exhaustive mesh searches (except intraBC ME). + MESH_PATTERN mesh_patterns[MAX_MESH_STEP]; + + // Pattern to be used for exhaustive mesh searches of intraBC ME. + MESH_PATTERN intrabc_mesh_patterns[MAX_MESH_STEP]; + + // Reduce single motion search range based on MV result of prior ref_mv_idx. + int reduce_search_range; + + // Prune mesh search. + int prune_mesh_search; + + // Use the rd cost around the best FULLPEL_MV to speed up subpel search + int use_fullpel_costlist; + + // Set the full pixel search level of obmc + // 0: obmc_full_pixel_diamond + // 1: obmc_refining_search_sad (faster) + int obmc_full_pixel_search_level; + + // Accurate full pixel motion search based on TPL stats. + int full_pixel_search_level; +} MV_SPEED_FEATURES; + +typedef struct INTER_MODE_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: + // 0: not used + // 1: used with online dynamic rd model + // 2: used with static rd model + int inter_mode_rd_model_estimation; + + // Bypass transform search based on skip rd + int txfm_rd_gate_level; + + // Limit the inter mode tested in the RD loop + int reduce_inter_modes; + + // Adaptive prediction mode search + int adaptive_mode_search; + + // This variable is used to cap the maximum number of times we skip testing a + // mode to be evaluated. A high value means we will be faster. + int adaptive_rd_thresh; + + // Aggressively prune inter modes when best mode is skippable. + int prune_inter_modes_if_skippable; + + // Drop less likely to be picked reference frames in the RD search. + // Has five levels for now: 0, 1, 2, 3 and 4, where higher levels prune more + // aggressively than lower ones. (0 means no pruning). + int selective_ref_frame; + + // 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; + + int alt_ref_search_fp; + + // flag to skip NEWMV mode in drl if the motion search result is the same + int skip_repeated_newmv; + + // Skip the current ref_mv in NEW_MV mode if we have already encountered + // another ref_mv in the drl such that: + // 1. The other drl has the same fullpel_mv during the SIMPLE_TRANSLATION + // search process as the current fullpel_mv. + // 2. The rate needed to encode the current fullpel_mv is larger than that + // for the other ref_mv. + int skip_repeated_full_newmv; + + // This speed feature checks duplicate ref MVs among NEARESTMV, NEARMV, + // GLOBALMV and skips NEARMV or GLOBALMV (in order) if a duplicate is found + // TODO(any): Instead of skipping repeated ref mv, use the recalculated + // rd-cost based on mode rate and skip the mode evaluation + int skip_repeated_ref_mv; // Flag used to control the ref_best_rd based gating for chroma int perform_best_rd_based_gating_for_chroma; + // Skip certain motion modes (OBMC, warped, interintra) for single reference + // motion search, using the results of single ref SIMPLE_TRANSLATION + int prune_single_motion_modes_by_simple_trans; + + // Reuse the inter_intra_mode search result from NEARESTMV mode to other + // single ref modes + int reuse_inter_intra_mode; + + // prune wedge and compound segment approximate rd evaluation based on + // compound average modeled rd + int prune_comp_type_by_model_rd; + + // prune wedge and compound segment approximate rd evaluation based on + // compound average rd/ref_best_rd + int prune_comp_type_by_comp_avg; + + // Skip some ref frames in compound motion search by single motion search + // result. Has three levels for now: 0 referring to no skipping, and 1 - 3 + // increasing aggressiveness of skipping in order. + // Note: The search order might affect the result. It assumes that the single + // reference modes are searched before compound modes. It is better to search + // same single inter mode as a group. + int prune_comp_search_by_single_result; + + // If 1 we iterate finding a best reference for 2 ref frames together - via + // a log search that iterates 4 times (check around mv for last for best + // error of combined predictor then check around mv for alt). If 0 we + // we just use the best motion vector found for each frame by itself. + BLOCK_SIZE comp_inter_joint_search_thresh; + + // Instead of performing a full MV search, do a simple translation first + // and only perform a full MV search on the motion vectors that performed + // well. + int prune_mode_search_simple_translation; + + // Only search compound modes with at least one "good" reference frame. + // A reference frame is good if, after looking at its performance among + // the single reference modes, it is one of the two best performers. + int prune_compound_using_single_ref; + + // Skip extended compound mode using ref frames of above and left neighbor + // blocks. + // 0 : no pruning + // 1 : prune extended compound mode (less aggressiveness) + // 2 : prune extended compound mode (high aggressiveness) + int prune_compound_using_neighbors; + + // Based on previous ref_mv_idx search result, prune the following search. + int prune_ref_mv_idx_search; + + // Disable one sided compound modes. + int disable_onesided_comp; + + // Prune/gate motion mode evaluation based on token based rd + // during transform search for inter blocks + // Values are 0 (not used) , 1 - 3 with progressively increasing + // aggressiveness + int prune_motion_mode_level; + + // Prune obmc search using previous frame stats. + int prune_obmc_prob_thresh; + + // Disable obmc. + int disable_obmc; + + // Gate warp evaluation for motions of type IDENTITY, + // TRANSLATION and AFFINE(based on number of warp neighbors) + int prune_warp_using_wmtype; + + // Prune warped motion search using previous frame stats. + int prune_warped_prob_thresh; + // Enable/disable interintra wedge search. int disable_wedge_interintra_search; - // Disable loop restoration for Chroma plane - int disable_loop_restoration_chroma; + // De-couple wedge and mode search during interintra RDO. + int fast_interintra_wedge_search; - // Reduce the wiener filter win size for luma - int reduce_wiener_window_size; + // Only enable wedge search if the edge strength is greater than + // this threshold. A value of 0 signals that this check is disabled. + unsigned int disable_wedge_search_edge_thresh; + + // Only enable wedge search if the variance is above this threshold. + unsigned int disable_wedge_search_var_thresh; + + // Whether fast wedge sign estimate is used + int fast_wedge_sign_estimate; + + // Whether to prune wedge search based on predictor difference + int prune_wedge_pred_diff_based; + + // Enable/disable ME for interinter wedge search. + int disable_interinter_wedge_newmv_search; + + // Enable/disable ME for interinter diffwtd search. PSNR BD-rate gain of + // ~0.1 on the lowres test set, but ~15% slower computation. + int enable_interinter_diffwtd_newmv_search; + + // Enable/disable smooth inter-intra mode + int disable_smooth_interintra; + + // Disable interinter_wedge + int disable_interinter_wedge; + + // Decide when and how to use joint_comp. + DIST_WTD_COMP_FLAG use_dist_wtd_comp_flag; + + // Whether to override and disable sb level coeff cost updates, if + // cpi->oxcf.coeff_cost_upd_freq = COST_UPD_SB (i.e. set at SB level) + int disable_sb_level_coeff_cost_upd; + + // Whether to override and disable sb level mv cost updates, if + // cpi->oxcf.coeff_cost_upd_freq = COST_UPD_SB (i.e. set at SB level) + int disable_sb_level_mv_cost_upd; + + // Prune inter modes based on tpl stats + // 0 : no pruning + // 1 - 3 indicate increasing aggressiveness in order. + int prune_inter_modes_based_on_tpl; + + // Model based breakout after interpolation filter search + // 0: no breakout + // 1: use model based rd breakout + int model_based_post_interp_filter_breakout; + + // Reuse compound type rd decision when exact match is found + // 0: No reuse + // 1: Reuse the compound type decision + int reuse_compound_type_decision; +} INTER_MODE_SPEED_FEATURES; + +typedef struct INTERP_FILTER_SPEED_FEATURES { + // A source variance threshold below which filter search is disabled + // Choose a very large value (UINT_MAX) to use 8-tap always + unsigned int disable_filter_search_var_thresh; + + // Do limited interpolation filter search for dual filters, since best choice + // usually includes EIGHTTAP_REGULAR. + int use_fast_interpolation_filter_search; + + // Disable dual filter + int disable_dual_filter; + + // Save results of av1_interpolation_filter_search for a block + // Check mv and ref_frames before search, if they are very close with previous + // saved results, filter search can be skipped. + int use_interp_filter; + + // skip sharp_filter evaluation based on regular and smooth filter rd for + // dual_filter=0 case + int skip_sharp_interp_filter_search; + + int cb_pred_filter_search; + + // adaptive interp_filter search to allow skip of certain filter types. + int adaptive_interp_filter_search; +} INTERP_FILTER_SPEED_FEATURES; + +typedef struct INTRA_MODE_SPEED_FEATURES { + // These bit masks allow you to enable or disable intra modes for each + // transform size separately. + int intra_y_mode_mask[TX_SIZES]; + int intra_uv_mode_mask[TX_SIZES]; + + // flag to allow skipping intra mode for inter frame prediction + int skip_intra_in_interframe; + + // variance threshold for intra mode gating when inter turned out to be skip + // in inter frame prediction + unsigned int src_var_thresh_intra_skip; + + // Prune intra mode candidates based on source block histogram of gradient. + int intra_pruning_with_hog; + + // TODO(anyone): tune intra_pruning_with_hog_thresh for various speeds. + float intra_pruning_with_hog_thresh; + + // Enable/disable smooth intra modes. + int disable_smooth_intra; + + // prune palette search + // 0: No pruning + // 1: Perform coarse search to prune the palette colors. For winner colors, + // neighbors are also evaluated using a finer search. + // 2: Perform 2 way palette search from max colors to min colors (and min + // colors to remaining colors) and terminate the search if current number of + // palette colors is not the winner. + int prune_palette_search_level; +} INTRA_MODE_SPEED_FEATURES; + +typedef struct TX_SPEED_FEATURES { + // Init search depth for square and rectangular transform partitions. + // Values: + // 0 - search full tree, 1: search 1 level, 2: search the highest level only + int inter_tx_size_search_init_depth_sqr; + int inter_tx_size_search_init_depth_rect; + int intra_tx_size_search_init_depth_sqr; + int intra_tx_size_search_init_depth_rect; + + // If any dimension of a coding block size above 64, always search the + // largest transform only, since the largest transform block size is 64x64. + int tx_size_search_lgr_block; + + TX_TYPE_SEARCH tx_type_search; + + // Skip split transform block partition when the collocated bigger block + // is selected as all zero coefficients. + int txb_split_cap; + + // Shortcut the transform block partition and type search when the target + // rdcost is relatively lower. + // Values are 0 (not used) , or 1 - 2 with progressively increasing + // aggressiveness + int adaptive_txb_search_level; + + // Prune level for tx_size_type search for inter based on rd model + // 0: no pruning + // 1-2: progressively increasing aggressiveness of pruning + int model_based_prune_tx_search_level; + + // Use hash table to store intra(keyframe only) txb transform search results + // to avoid repeated search on the same residue signal. + int use_intra_txb_hash; + + // Use hash table to store inter txb transform search results + // to avoid repeated search on the same residue signal. + int use_inter_txb_hash; + + // Refine TX type after fast TX search. + int refine_fast_tx_search_results; +} TX_SPEED_FEATURES; + +typedef struct RD_CALC_SPEED_FEATURES { + // This feature controls whether we do the expensive context update and + // calculation in the rd coefficient costing loop. + int use_fast_coef_costing; + + // Fast approximation of av1_model_rd_from_var_lapndz + int simple_model_rd_from_var; + + // Whether to compute distortion in the image domain (slower but + // more accurate), or in the transform domain (faster but less acurate). + // 0: use image domain + // 1: use transform domain in tx_type search, and use image domain for + // RD_STATS + // 2: use transform domain + int tx_domain_dist_level; + + // Transform domain distortion threshold level + int tx_domain_dist_thres_level; + + // Trellis (dynamic programming) optimization of quantized values + TRELLIS_OPT_TYPE optimize_coefficients; + + // Use a hash table to store previously computed optimized qcoeffs from + // expensive calls to optimize_txb. + int use_hash_based_trellis; + + // Use hash table to store macroblock RD search results + // to avoid repeated search on the same residue signal. + int use_mb_rd_hash; + + // Flag used to control the speed of the eob selection in trellis. + int trellis_eob_fast; + + // Calculate RD cost before doing optimize_b, and skip if the cost is large. + int optimize_b_precheck; // Flag used to control the extent of coeff R-D optimization int perform_coeff_opt; +} RD_CALC_SPEED_FEATURES; +typedef struct WINNER_MODE_SPEED_FEATURES { // Flag used to control the winner mode processing for better R-D optimization // of quantized coeffs int enable_winner_mode_for_coeff_opt; @@ -704,109 +836,187 @@ typedef struct SPEED_FEATURES { // Flag used to enable processing of multiple winner modes int enable_multiwinner_mode_process; - // Flag used to control the speed of the eob selection in trellis. - int trellis_eob_fast; + // Motion mode for winner candidates: + // 0: speed feature OFF + // 1 / 2 : Use configured number of winner candidates + int motion_mode_for_winner_cand; +} WINNER_MODE_SPEED_FEATURES; - // This flag controls the use of non-RD mode decision. - int use_nonrd_pick_mode; +typedef struct LOOP_FILTER_SPEED_FEATURES { + // This feature controls how the loop filter level is determined. + LPF_PICK_METHOD lpf_pick; - // prune wedge and compound segment approximate rd evaluation based on - // compound average modeled rd - int prune_comp_type_by_model_rd; + // Control how the CDEF strength is determined. + CDEF_PICK_METHOD cdef_pick_method; - // Enable/disable smooth intra modes. - int disable_smooth_intra; + // Decoder side speed feature to add penalty for use of dual-sgr filters. + // Takes values 0 - 10, 0 indicating no penalty and each additional level + // adding a penalty of 1% + int dual_sgr_penalty_level; - // use reduced ref set for real-time mode - int use_real_time_ref_set; + // prune sgr ep using binary search like mechanism + int enable_sgr_ep_pruning; - // Perform a full TX search on some modes while using the - // inter-mode RD model for others. Currently not in use. - // TODO(any): Find out when we can actually skip tx_search on some modes. - int inter_mode_rd_model_estimation_adaptive; + // Disable loop restoration for Chroma plane + int disable_loop_restoration_chroma; - // Use very reduced set of inter mode checks and fast non-rd mode cost - // estimation. Only enabled when use_nonrd_pick_mode is != 0 - int use_fast_nonrd_pick_mode; + // Prune RESTORE_WIENER evaluation based on source variance + // 0 : no pruning + // 1 : conservative pruning + // 2 : aggressive pruning + int prune_wiener_based_on_src_var; - // Reuse inter prediction in fast non-rd mode. - int reuse_inter_pred_nonrd; + // Prune self-guided loop restoration based on wiener search results + // 0 : no pruning + // 1 : pruning based on rdcost ratio of RESTORE_WIENER and RESTORE_NONE + // 2 : pruning based on winner restoration type among RESTORE_WIENER and + // RESTORE_NONE + int prune_sgr_based_on_wiener; + + // Reduce the wiener filter win size for luma + int reduce_wiener_window_size; + + // Disable loop restoration filter + int disable_lr_filter; +} LOOP_FILTER_SPEED_FEATURES; + +typedef struct REAL_TIME_SPEED_FEATURES { + // check intra prediction for non-RD mode. + int check_intra_pred_nonrd; // Perform coarse ME before calculating variance in variance-based partition int estimate_motion_for_var_based_partition; - // Instead of performing a full MV search, do a simple translation first - // and only perform a full MV search on the motion vectors that performed - // well. - int prune_mode_search_simple_translation; + // For nonrd_use_partition: mode of extra check of leaf partition + // 0 - don't check merge + // 1 - always check merge + // 2 - check merge and prune checking final split + int nonrd_check_partition_merge_mode; + + // For nonrd_use_partition: check of leaf partition extra split + int nonrd_check_partition_split; + + // Implements various heuristics to skip searching modes + // The heuristics selected are based on flags + // defined in the MODE_SEARCH_SKIP_HEURISTICS enum + unsigned int mode_search_skip_flags; + + // For nonrd: Reduces ref frame search. + // 0 - low level of search prune in non last frames + // 1 - pruned search in non last frames + // 2 - more pruned search in non last frames + int nonrd_prune_ref_frame_search; + + // This flag controls the use of non-RD mode decision. + int use_nonrd_pick_mode; + + // Use ALTREF frame in non-RD mode decision. + int use_nonrd_altref_frame; // Use compound reference for non-RD mode. int use_comp_ref_nonrd; - // check intra prediction for non-RD mode. - int check_intra_pred_nonrd; - - // Only search compound modes with at least one "good" reference frame. - // A reference frame is good if, after looking at its performance among - // the single reference modes, it is one of the two best performers. - int prune_compound_using_single_ref; - - // Use CNN with luma pixels on source frame on each of the 64x64 subblock to - // perform split/no_split decision on intra-frames. - int intra_cnn_split; - - // Use modeled (currently CurvFit model) RDCost for fast non-RD mode - int use_modeled_non_rd_cost; - - // Filter mask to allow certain interp_filter type. - uint16_t interp_filter_search_mask; + // use reduced ref set for real-time mode + int use_real_time_ref_set; // Skip a number of expensive mode evaluations for blocks with very low // temporal variance. int short_circuit_low_temp_var; - // Use interpolation filter search in non-RD mode decision. - int use_nonrd_filter_search; + // Use modeled (currently CurvFit model) RDCost for fast non-RD mode + int use_modeled_non_rd_cost; - // Use reduced 1/8th pel mv usage, in the range 0 - 2, where - // 0: maximizes quality and does not reduce mv precision - // 1: more aggressive reduced usage of high precision MV - // 2: use only quarter pel motion - int reduce_high_precision_mv_usage; + // Reuse inter prediction in fast non-rd mode. + int reuse_inter_pred_nonrd; - // Whether to override and disable sb level coeff cost updates, if - // cpi->oxcf.coeff_cost_upd_freq = COST_UPD_SB (i.e. set at SB level) - int disable_sb_level_coeff_cost_upd; - - // Whether to override and disable sb level mv cost updates, if - // cpi->oxcf.coeff_cost_upd_freq = COST_UPD_SB (i.e. set at SB level) - int disable_sb_level_mv_cost_upd; - - // Whether to disable overlay frames for filtered Altref frames, - // overiding oxcf->enable_overlay flag set as 1. - int disable_overlay_frames; - - // Enable/disable adaptively deciding whether or not to encode ALTREF overlay - // frame. - int adaptive_overlay_encoding; - - // Prune obmc search using previous frame stats. - int prune_obmc_using_stats; - - // Use ALTREF frame in non-RD mode decision. - int use_nonrd_altref_frame; - - // If set forces interpolation filter to EIGHTTAP_REGULAR - int skip_interp_filter_search; - - // For nonrd: use block_yrd for rd cost in interpolation filter search. - int nonrd_use_blockyrd_interp_filter; + // Number of best inter modes to search transform. INT_MAX - search all. + int num_inter_modes_for_tx_search; // Forces TX search off for RDCost calulation. int force_tx_search_off; - // Number of best inter modes to search transform. INT_MAX - search all. - int num_inter_modes_for_tx_search; + // Use interpolation filter search in non-RD mode decision. + int use_nonrd_filter_search; + + // Use simplified RD model for interpolation search and Intra + int use_simple_rd_model; + + // If set forces interpolation filter to EIGHTTAP_REGULAR + int skip_interp_filter_search; + + // Use hybrid (rd for bsize < 16x16, otherwise nonrd) intra search for intra + // only frames. + int hybrid_intra_pickmode; + + // Compute variance/sse on source difference, prior to encoding superblock. + int source_metrics_sb_nonrd; +} REAL_TIME_SPEED_FEATURES; + +typedef struct SPEED_FEATURES { + /* + * Sequence/frame level speed features: + */ + HIGH_LEVEL_SPEED_FEATURES hl_sf; + + /* + * Speed features related to how tpl's searches are done. + */ + TPL_SPEED_FEATURES tpl_sf; + + /* + * Global motion speed features: + */ + GLOBAL_MOTION_SPEED_FEATURES gm_sf; + + /* + * Partition search speed features: + */ + PARTITION_SPEED_FEATURES part_sf; + + /* + * Motion search speed features: + */ + MV_SPEED_FEATURES mv_sf; + + /* + * Inter mode search speed features: + */ + INTER_MODE_SPEED_FEATURES inter_sf; + + /* + * Interpolation filter search speed features: + */ + INTERP_FILTER_SPEED_FEATURES interp_sf; + + /* + * Intra mode search speed features: + */ + INTRA_MODE_SPEED_FEATURES intra_sf; + + /* + * Transform size/type search speed features: + */ + TX_SPEED_FEATURES tx_sf; + + /* + * RD calculation speed features: + */ + RD_CALC_SPEED_FEATURES rd_sf; + + /* + * Two-pass mode evaluation features: + */ + WINNER_MODE_SPEED_FEATURES winner_mode_sf; + + /* + * In-loop filter speed features: + */ + LOOP_FILTER_SPEED_FEATURES lpf_sf; + + /* + * Real-time mode speed features: + */ + REAL_TIME_SPEED_FEATURES rt_sf; } SPEED_FEATURES; struct AV1_COMP; @@ -815,6 +1025,7 @@ void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi, int speed); void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi, int speed); +void av1_set_speed_features_qindex_dependent(struct AV1_COMP *cpi, int speed); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/encoder/svc_layercontext.c b/media/libaom/src/av1/encoder/svc_layercontext.c index 1564e31800..b72d8aa733 100644 --- a/media/libaom/src/av1/encoder/svc_layercontext.c +++ b/media/libaom/src/av1/encoder/svc_layercontext.c @@ -24,8 +24,8 @@ void av1_init_layer_context(AV1_COMP *const cpi) { AV1_COMMON *const cm = &cpi->common; const AV1EncoderConfig *const oxcf = &cpi->oxcf; SVC *const svc = &cpi->svc; - int mi_rows = cpi->common.mi_rows; - int mi_cols = cpi->common.mi_cols; + int mi_rows = cpi->common.mi_params.mi_rows; + int mi_cols = cpi->common.mi_params.mi_cols; svc->base_framerate = 30.0; svc->current_superframe = 0; diff --git a/media/libaom/src/av1/encoder/svc_layercontext.h b/media/libaom/src/av1/encoder/svc_layercontext.h index bbbd07a08f..7cb85a3c93 100644 --- a/media/libaom/src/av1/encoder/svc_layercontext.h +++ b/media/libaom/src/av1/encoder/svc_layercontext.h @@ -50,6 +50,9 @@ typedef struct SVC { int number_temporal_layers; int external_ref_frame_config; int non_reference_frame; + // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3), + // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). + int reference[INTER_REFS_PER_FRAME]; int ref_idx[INTER_REFS_PER_FRAME]; int refresh[REF_FRAMES]; double base_framerate; diff --git a/media/libaom/src/av1/encoder/temporal_filter.c b/media/libaom/src/av1/encoder/temporal_filter.c index 23079967bf..a637df559e 100644 --- a/media/libaom/src/av1/encoder/temporal_filter.c +++ b/media/libaom/src/av1/encoder/temporal_filter.c @@ -12,1625 +12,1326 @@ #include #include -#include "av1/common/blockd.h" #include "config/aom_config.h" #include "av1/common/alloccommon.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" +#include "av1/common/odintrin.h" #include "av1/common/quant_common.h" #include "av1/common/reconinter.h" -#include "av1/common/odintrin.h" #include "av1/encoder/av1_quantize.h" +#include "av1/encoder/encoder.h" #include "av1/encoder/extend.h" #include "av1/encoder/firstpass.h" #include "av1/encoder/mcomp.h" -#include "av1/encoder/encoder.h" #include "av1/encoder/ratectrl.h" #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/segmentation.h" #include "av1/encoder/temporal_filter.h" #include "aom_dsp/aom_dsp_common.h" #include "aom_mem/aom_mem.h" -#include "aom_ports/mem.h" #include "aom_ports/aom_timer.h" +#include "aom_ports/mem.h" #include "aom_ports/system_state.h" #include "aom_scale/aom_scale.h" -#define EXPERIMENT_TEMPORAL_FILTER 1 -#define WINDOW_LENGTH 2 -#define WINDOW_SIZE 25 -#define SCALE 1000 +// NOTE: All `tf` in this file means `temporal filtering`. -static unsigned int index_mult[14] = { 0, 0, 0, 0, 49152, - 39322, 32768, 28087, 24576, 21846, - 19661, 17874, 0, 15124 }; +// Does motion search for blocks in temporal filtering. This is the first step +// for temporal filtering. More specifically, given a frame to be filtered and +// another frame as reference, this function searches the reference frame to +// find out the most alike block as that from the frame to be filtered. This +// found block will be further used for weighted averaging. +// NOTE: Besides doing motion search for the entire block, this function will +// also do motion search for each 1/4 sub-block to get more precise prediction. +// Inputs: +// cpi: Pointer to the composed information of input video. +// frame_to_filter: Pointer to the frame to be filtered. +// ref_frame: Pointer to the reference frame. +// block_size: Block size used for motion search. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// ref_mv: Reference motion vector, which is commonly inherited from the +// motion search result of previous frame. +// subblock_mvs: Pointer to the result motion vectors for 4 sub-blocks. +// subblock_mses: Pointer to the search errors (MSE) for 4 sub-blocks. +// Returns: +// Search error (MSE) of the entire block. +static int tf_motion_search(AV1_COMP *cpi, + const YV12_BUFFER_CONFIG *frame_to_filter, + const YV12_BUFFER_CONFIG *ref_frame, + const BLOCK_SIZE block_size, const int mb_row, + const int mb_col, MV *ref_mv, MV *subblock_mvs, + int *subblock_mses) { + // Frame information + const int min_frame_size = AOMMIN(cpi->common.width, cpi->common.height); -static int64_t highbd_index_mult[14] = { 0U, 0U, 0U, - 0U, 3221225472U, 2576980378U, - 2147483648U, 1840700270U, 1610612736U, - 1431655766U, 1288490189U, 1171354718U, - 0U, 991146300U }; + // Block information (ONLY Y-plane is used for motion search). + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int y_stride = frame_to_filter->y_stride; + assert(y_stride == ref_frame->y_stride); + const int y_offset = mb_row * mb_height * y_stride + mb_col * mb_width; -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, - uint8_t *pred, struct scale_factors *scale, int x, int y, int num_planes, - MV *blk_mvs, int use_32x32) { - int uv_stride; + // Save input state. + MACROBLOCK *const mb = &cpi->td.mb; + MACROBLOCKD *const mbd = &mb->e_mbd; + const struct buf_2d ori_src_buf = mb->plane[0].src; + const struct buf_2d ori_pre_buf = mbd->plane[0].pre[0]; + const MV_COST_TYPE ori_mv_cost_type = mb->mv_cost_type; + + // Parameters used for motion search. + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + + const search_site_config ss_cfg = + cpi->mv_search_params.ss_cfg[SS_CFG_LOOKAHEAD]; + const SEARCH_METHODS full_search_method = NSTEP; + const int step_param = av1_init_search_range( + AOMMAX(frame_to_filter->y_crop_width, frame_to_filter->y_crop_height)); + const SUBPEL_SEARCH_TYPE subpel_search_type = USE_8_TAPS; + const int force_integer_mv = cpi->common.features.cur_frame_force_integer_mv; + const MV_COST_TYPE mv_cost_type = + min_frame_size >= 720 + ? MV_COST_L1_HDRES + : (min_frame_size >= 480 ? MV_COST_L1_MIDRES : MV_COST_L1_LOWRES); + + // Starting position for motion search. + FULLPEL_MV start_mv = get_fullmv_from_mv(ref_mv); + // Baseline position for motion search (used for rate distortion comparison). + const MV baseline_mv = kZeroMv; + + // Setup. + mb->plane[0].src.buf = frame_to_filter->y_buffer + y_offset; + mb->plane[0].src.stride = y_stride; + mbd->plane[0].pre[0].buf = ref_frame->y_buffer + y_offset; + mbd->plane[0].pre[0].stride = y_stride; + // Unused intermediate results for motion search. + unsigned int sse, error; + int distortion; + int cost_list[5]; + + // Do motion search. + // NOTE: In `av1_full_pixel_search()` and `find_fractional_mv_step()`, the + // searched result will be stored in `mb->best_mv`. + int_mv best_mv; + int block_mse = INT_MAX; + mb->mv_cost_type = mv_cost_type; + + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, mb, block_size, + &baseline_mv, &ss_cfg); + full_ms_params.run_mesh_search = 1; + full_ms_params.search_method = full_search_method; + av1_full_pixel_search(start_mv, &full_ms_params, step_param, + cond_cost_list(cpi, cost_list), &best_mv.as_fullmv, + NULL); + + // Since we are merely refining the result from full pixel search, we don't + // need regularization for subpel search + mb->mv_cost_type = MV_COST_NONE; + if (force_integer_mv == 1) { // Only do full search on the entire block. + const int mv_row = best_mv.as_mv.row; + const int mv_col = best_mv.as_mv.col; + best_mv.as_mv.row = GET_MV_SUBPEL(mv_row); + best_mv.as_mv.col = GET_MV_SUBPEL(mv_col); + const int mv_offset = mv_row * y_stride + mv_col; + error = cpi->fn_ptr[block_size].vf( + ref_frame->y_buffer + y_offset + mv_offset, y_stride, + frame_to_filter->y_buffer + y_offset, y_stride, &sse); + block_mse = DIVIDE_AND_ROUND(error, mb_pels); + mb->e_mbd.mi[0]->mv[0] = best_mv; + } else { // Do fractional search on the entire block and all sub-blocks. + av1_make_default_subpel_ms_params(&ms_params, cpi, mb, block_size, + &baseline_mv, cost_list); + ms_params.forced_stop = EIGHTH_PEL; + ms_params.var_params.subpel_search_type = subpel_search_type; + MV subpel_start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + error = cpi->mv_search_params.find_fractional_mv_step( + &mb->e_mbd, &cpi->common, &ms_params, subpel_start_mv, &best_mv.as_mv, + &distortion, &sse, NULL); + block_mse = DIVIDE_AND_ROUND(error, mb_pels); + mb->e_mbd.mi[0]->mv[0] = best_mv; + *ref_mv = best_mv.as_mv; + // On 4 sub-blocks. + const BLOCK_SIZE subblock_size = ss_size_lookup[block_size][1][1]; + const int subblock_height = block_size_high[subblock_size]; + const int subblock_width = block_size_wide[subblock_size]; + const int subblock_pels = subblock_height * subblock_width; + start_mv = get_fullmv_from_mv(ref_mv); + + int subblock_idx = 0; + for (int i = 0; i < mb_height; i += subblock_height) { + for (int j = 0; j < mb_width; j += subblock_width) { + const int offset = i * y_stride + j; + mb->plane[0].src.buf = frame_to_filter->y_buffer + y_offset + offset; + mbd->plane[0].pre[0].buf = ref_frame->y_buffer + y_offset + offset; + mb->mv_cost_type = mv_cost_type; + + av1_make_default_fullpel_ms_params( + &full_ms_params, cpi, mb, subblock_size, &baseline_mv, &ss_cfg); + full_ms_params.run_mesh_search = 1; + full_ms_params.search_method = full_search_method; + av1_full_pixel_search(start_mv, &full_ms_params, step_param, + cond_cost_list(cpi, cost_list), + &best_mv.as_fullmv, NULL); + + // Since we are merely refining the result from full pixel search, we + // don't need regularization for subpel search + mb->mv_cost_type = MV_COST_NONE; + av1_make_default_subpel_ms_params(&ms_params, cpi, mb, subblock_size, + &baseline_mv, cost_list); + ms_params.forced_stop = EIGHTH_PEL; + ms_params.var_params.subpel_search_type = subpel_search_type; + subpel_start_mv = get_mv_from_fullmv(&best_mv.as_fullmv); + error = cpi->mv_search_params.find_fractional_mv_step( + &mb->e_mbd, &cpi->common, &ms_params, subpel_start_mv, + &best_mv.as_mv, &distortion, &sse, NULL); + subblock_mses[subblock_idx] = DIVIDE_AND_ROUND(error, subblock_pels); + subblock_mvs[subblock_idx] = best_mv.as_mv; + ++subblock_idx; + } + } + } + + // Restore input state. + mb->plane[0].src = ori_src_buf; + mbd->plane[0].pre[0] = ori_pre_buf; + mb->mv_cost_type = ori_mv_cost_type; + + return block_mse; +} + +// Helper function to get weight according to thresholds. +static INLINE int get_weight_by_thresh(const int value, const int low, + const int high) { + return value < low ? 2 : value < high ? 1 : 0; +} + +// Gets filter weight for blocks in temporal filtering. The weights will be +// assigned based on the motion search errors. +// NOTE: Besides assigning filter weight for the block, this function will also +// determine whether to split the entire block into 4 sub-blocks for further +// filtering. +// TODO(any): Many magic numbers are used in this function. They may be tuned +// to improve the performance. +// Inputs: +// block_mse: Motion search error (MSE) for the entire block. +// subblock_mses: Pointer to the search errors (MSE) for 4 sub-blocks. +// is_second_arf: Whether the to-filter frame is the second ARF. This field +// will affect the filter weight for the to-filter frame. +// subblock_filter_weights: Pointer to the assigned filter weight for each +// sub-block. If not using sub-blocks, the first +// element will be used for the entire block. +// Returns: Whether to use 4 sub-blocks to replace the original block. +static int tf_get_filter_weight(const int block_mse, const int *subblock_mses, + const int is_second_arf, + int *subblock_filter_weights) { + // `block_mse` is initialized as INT_MAX and will be overwritten after the + // motion search with reference frame, therefore INT_MAX can ONLY be accessed + // by to-filter frame. + if (block_mse == INT_MAX) { + const int weight = TF_ENABLE_PLANEWISE_STRATEGY + ? TF_PLANEWISE_FILTER_WEIGHT_SCALE + : is_second_arf ? 64 : 32; + subblock_filter_weights[0] = subblock_filter_weights[1] = + subblock_filter_weights[2] = subblock_filter_weights[3] = weight; + return 0; + } + + const int thresh_low = is_second_arf ? 20 : 40; + const int thresh_high = is_second_arf ? 40 : 80; + + int min_subblock_mse = INT_MAX; + int max_subblock_mse = INT_MIN; + int sum_subblock_mse = 0; + for (int i = 0; i < 4; ++i) { + sum_subblock_mse += subblock_mses[i]; + min_subblock_mse = AOMMIN(min_subblock_mse, subblock_mses[i]); + max_subblock_mse = AOMMAX(max_subblock_mse, subblock_mses[i]); + subblock_filter_weights[i] = + get_weight_by_thresh(subblock_mses[i], thresh_low, thresh_high); + } + + if (((block_mse * 15 < sum_subblock_mse * 4) && + max_subblock_mse - min_subblock_mse < 48) || + ((block_mse * 14 < sum_subblock_mse * 4) && + max_subblock_mse - min_subblock_mse < 24)) { // No split. + const int weight = get_weight_by_thresh(block_mse, thresh_low, thresh_high); + subblock_filter_weights[0] = subblock_filter_weights[1] = + subblock_filter_weights[2] = subblock_filter_weights[3] = weight; + return 0; + } else { // Do split. + return 1; + } +} + +// Helper function to determine whether a frame is encoded with high bit-depth. +static INLINE int is_frame_high_bitdepth(const YV12_BUFFER_CONFIG *frame) { + return (frame->flags & YV12_FLAG_HIGHBITDEPTH) ? 1 : 0; +} + +// Builds predictor for blocks in temporal filtering. This is the second step +// for temporal filtering, which is to construct predictions from all reference +// frames INCLUDING the frame to be filtered itself. These predictors are built +// based on the motion search results (motion vector is set as 0 for the frame +// to be filtered), and will be futher used for weighted averaging. +// Inputs: +// ref_frame: Pointer to the reference frame (or the frame to be filtered). +// mbd: Pointer to the block for filtering. Besides containing the subsampling +// information of all planes, this field also gives the searched motion +// vector for the entire block, i.e., `mbd->mi[0]->mv[0]`. This vector +// should be 0 if the `ref_frame` itself is the frame to be filtered. +// block_size: Size of the block. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// num_planes: Number of planes in the frame. +// scale: Scaling factor. +// use_subblock: Whether to use 4 sub-blocks to replace the original block. +// subblock_mvs: The motion vectors for each sub-block (row-major order). +// pred: Pointer to the predictor to build. +// Returns: +// Nothing will be returned. But the content to which `pred` points will be +// modified. +static void tf_build_predictor(const YV12_BUFFER_CONFIG *ref_frame, + const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, + const int mb_col, const int num_planes, + const struct scale_factors *scale, + const int use_subblock, const MV *subblock_mvs, + uint8_t *pred) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + + // Information of the entire block. + const int mb_height = block_size_high[block_size]; // Height. + const int mb_width = block_size_wide[block_size]; // Width. + const int mb_pels = mb_height * mb_width; // Number of pixels. + const int mb_y = mb_height * mb_row; // Y-coord (Top-left). + const int mb_x = mb_width * mb_col; // X-coord (Top-left). + const int bit_depth = mbd->bd; // Bit depth. + const int is_intrabc = 0; // Is intra-copied? + const int mb_mv_row = mbd->mi[0]->mv[0].as_mv.row; // Motion vector (y). + const int mb_mv_col = mbd->mi[0]->mv[0].as_mv.col; // Motion vector (x). + const MV mb_mv = { (int16_t)mb_mv_row, (int16_t)mb_mv_col }; + const int is_high_bitdepth = is_frame_high_bitdepth(ref_frame); + + // Information of each sub-block (actually in use). + const int num_blocks = use_subblock ? 2 : 1; // Num of blocks on each side. + const int block_height = mb_height >> (num_blocks - 1); // Height. + const int block_width = mb_width >> (num_blocks - 1); // Width. + + // Default interpolation filters. const int_interpfilters interp_filters = av1_broadcast_interp_filter(MULTITAP_SHARP); - WarpTypesAllowed warp_types; - memset(&warp_types, 0, sizeof(WarpTypesAllowed)); - const int ssx = (uv_block_width == (BW >> 1)) ? 1 : 0; - if (ssx) { - uv_stride = (stride + 1) >> 1; - } else { - uv_stride = stride; - } + // Handle Y-plane, U-plane and V-plane (if needed) in sequence. + int plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const int subsampling_y = mbd->plane[plane].subsampling_y; + const int subsampling_x = mbd->plane[plane].subsampling_x; + // Information of each sub-block in current plane. + const int plane_h = mb_height >> subsampling_y; // Plane height. + const int plane_w = mb_width >> subsampling_x; // Plane width. + const int plane_y = mb_y >> subsampling_y; // Y-coord (Top-left). + const int plane_x = mb_x >> subsampling_x; // X-coord (Top-left). + const int h = block_height >> subsampling_y; // Sub-block height. + const int w = block_width >> subsampling_x; // Sub-block width. + const int is_y_plane = (plane == 0); // Is Y-plane? - InterPredParams inter_pred_params; + const struct buf_2d ref_buf = { NULL, ref_frame->buffers[plane], + ref_frame->widths[is_y_plane ? 0 : 1], + ref_frame->heights[is_y_plane ? 0 : 1], + ref_frame->strides[is_y_plane ? 0 : 1] }; - av1_init_inter_params(&inter_pred_params, BW, BH, x, y, 0, 0, xd->bd, - is_cur_buf_hbd(xd), 0, scale, interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); + // Handle entire block or sub-blocks if needed. + int subblock_idx = 0; + for (int i = 0; i < plane_h; i += h) { + for (int j = 0; j < plane_w; j += w) { + // Choose proper motion vector. + const MV mv = use_subblock ? subblock_mvs[subblock_idx] : mb_mv; + assert(mv.row >= INT16_MIN && mv.row <= INT16_MAX && + mv.col >= INT16_MIN && mv.col <= INT16_MAX); - if (use_32x32) { - 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 }; + const int y = plane_y + i; + const int x = plane_x + j; - av1_build_inter_predictor(y_mb_ptr, stride, &pred[0], BW, &mv, x, y, - &inter_pred_params); + // Build predictior for each sub-block on current plane. + InterPredParams inter_pred_params; + av1_init_inter_params(&inter_pred_params, w, h, y, x, subsampling_x, + subsampling_y, bit_depth, is_high_bitdepth, + is_intrabc, scale, &ref_buf, interp_filters); + inter_pred_params.conv_params = get_conv_params(0, plane, bit_depth); + av1_enc_build_one_inter_predictor(&pred[plane_offset + i * plane_w + j], + plane_w, &mv, &inter_pred_params); - if (num_planes > 1) { - av1_init_inter_params(&inter_pred_params, uv_block_width, uv_block_height, - x, y, xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y, xd->bd, - is_cur_buf_hbd(xd), 0, scale, interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 1, xd->bd); - av1_build_inter_predictor(u_mb_ptr, uv_stride, &pred[BLK_PELS], - uv_block_width, &mv, x, y, &inter_pred_params); - - inter_pred_params.conv_params = get_conv_params(0, 2, xd->bd); - av1_build_inter_predictor(v_mb_ptr, uv_stride, &pred[(BLK_PELS << 1)], - uv_block_width, &mv, x, y, &inter_pred_params); - } - - return; - } - - // While use_32x32 = 0, construct the 32x32 predictor using 4 16x16 - // predictors. - int i, j, k = 0, ys = (BH >> 1), xs = (BW >> 1); - // Y predictor - av1_init_inter_params(&inter_pred_params, xs, ys, x, y, 0, 0, xd->bd, - is_cur_buf_hbd(xd), 0, scale, interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - for (i = 0; i < BH; i += ys) { - for (j = 0; j < BW; j += xs) { - const MV mv = blk_mvs[k]; - const int y_offset = i * stride + j; - const int p_offset = i * BW + j; - - av1_build_inter_predictor(y_mb_ptr + y_offset, stride, &pred[p_offset], - BW, &mv, x, y, &inter_pred_params); - k++; - } - } - - // U and V predictors - if (num_planes > 1) { - ys = (uv_block_height >> 1); - xs = (uv_block_width >> 1); - k = 0; - - for (i = 0; i < uv_block_height; i += ys) { - for (j = 0; j < uv_block_width; j += xs) { - const MV mv = blk_mvs[k]; - const int uv_offset = i * uv_stride + j; - const int p_offset = i * uv_block_width + j; - - av1_init_inter_params(&inter_pred_params, xs, ys, x, y, - xd->plane[1].subsampling_x, - xd->plane[1].subsampling_y, xd->bd, - is_cur_buf_hbd(xd), 0, scale, interp_filters); - inter_pred_params.conv_params = get_conv_params(0, 1, xd->bd); - - av1_build_inter_predictor(u_mb_ptr + uv_offset, uv_stride, - &pred[BLK_PELS + p_offset], uv_block_width, - &mv, x, y, &inter_pred_params); - - inter_pred_params.conv_params = get_conv_params(0, 1, xd->bd); - av1_build_inter_predictor( - v_mb_ptr + uv_offset, uv_stride, &pred[(BLK_PELS << 1) + p_offset], - uv_block_width, &mv, x, y, &inter_pred_params); - k++; + ++subblock_idx; } } + plane_offset += mb_pels; } } -static void apply_temporal_filter_self(const uint8_t *pred, int buf_stride, - unsigned int block_width, - unsigned int block_height, - int filter_weight, uint32_t *accumulator, - uint16_t *count, - int use_new_temporal_mode) { - const int modifier = use_new_temporal_mode ? SCALE : filter_weight * 16; - unsigned int i, j, k = 0; - assert(filter_weight == 2); +// Computes temporal filter weights and accumulators for the frame to be +// filtered. More concretely, the filter weights for all pixels are the same. +// Inputs: +// mbd: Pointer to the block for filtering, which is ONLY used to get +// subsampling information of all planes as well as the bit-depth. +// block_size: Size of the block. +// num_planes: Number of planes in the frame. +// filter_weight: Weight used for filtering. +// pred: Pointer to the well-built predictors. +// accum: Pointer to the pixel-wise accumulator for filtering. +// count: Pointer to the pixel-wise counter fot filtering. +// Returns: +// Nothing will be returned. But the content to which `accum` and `pred` +// point will be modified. +void av1_apply_temporal_filter_self(const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, + const int num_planes, + const int filter_weight, + const uint8_t *pred, uint32_t *accum, + uint16_t *count) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); - for (i = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++) { - const int pixel_value = pred[i * buf_stride + j]; - count[k] += modifier; - accumulator[k] += modifier * pixel_value; - ++k; + // Block information. + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int is_high_bitdepth = is_cur_buf_hbd(mbd); + const uint16_t *pred16 = CONVERT_TO_SHORTPTR(pred); + + int plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const int subsampling_y = mbd->plane[plane].subsampling_y; + const int subsampling_x = mbd->plane[plane].subsampling_x; + const int h = mb_height >> subsampling_y; // Plane height. + const int w = mb_width >> subsampling_x; // Plane width. + + int pred_idx = 0; + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + const int idx = plane_offset + pred_idx; // Index with plane shift. + const int pred_value = is_high_bitdepth ? pred16[idx] : pred[idx]; + accum[idx] += filter_weight * pred_value; + count[idx] += filter_weight; + ++pred_idx; + } } + plane_offset += mb_pels; } } -static void highbd_apply_temporal_filter_self( - const uint8_t *pred8, int buf_stride, unsigned int block_width, - unsigned int block_height, int filter_weight, uint32_t *accumulator, - uint16_t *count, int use_new_temporal_mode) { - const int modifier = use_new_temporal_mode ? SCALE : filter_weight * 16; - const uint16_t *pred = CONVERT_TO_SHORTPTR(pred8); - unsigned int i, j, k = 0; - assert(filter_weight == 2); +// Function to compute pixel-wise squared difference between two buffers. +// Inputs: +// ref: Pointer to reference buffer. +// ref_offset: Start position of reference buffer for computation. +// ref_stride: Stride for reference buffer. +// tgt: Pointer to target buffer. +// tgt_offset: Start position of target buffer for computation. +// tgt_stride: Stride for target buffer. +// height: Height of block for computation. +// width: Width of block for computation. +// is_high_bitdepth: Whether the two buffers point to high bit-depth frames. +// square_diff: Pointer to save the squared differces. +// Returns: +// Nothing will be returned. But the content to which `square_diff` points +// will be modified. +static INLINE void compute_square_diff(const uint8_t *ref, const int ref_offset, + const int ref_stride, const uint8_t *tgt, + const int tgt_offset, + const int tgt_stride, const int height, + const int width, + const int is_high_bitdepth, + uint32_t *square_diff) { + const uint16_t *ref16 = CONVERT_TO_SHORTPTR(ref); + const uint16_t *tgt16 = CONVERT_TO_SHORTPTR(tgt); - for (i = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++) { - const int pixel_value = pred[i * buf_stride + j]; - count[k] += modifier; - accumulator[k] += modifier * pixel_value; - ++k; - } - } -} - -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; -} - -static INLINE void calculate_squared_errors(const uint8_t *s, int s_stride, - const uint8_t *p, int p_stride, - uint16_t *diff_sse, unsigned int w, - unsigned int h) { + int ref_idx = 0; + int tgt_idx = 0; int idx = 0; - unsigned int i, j; + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + const uint16_t ref_value = is_high_bitdepth ? ref16[ref_offset + ref_idx] + : ref[ref_offset + ref_idx]; + const uint16_t tgt_value = is_high_bitdepth ? tgt16[tgt_offset + tgt_idx] + : tgt[tgt_offset + tgt_idx]; + const uint32_t diff = (ref_value > tgt_value) ? (ref_value - tgt_value) + : (tgt_value - ref_value); + square_diff[idx] = diff * diff; - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++) { - const int16_t diff = s[i * s_stride + j] - p[i * p_stride + j]; - diff_sse[idx] = diff * diff; - idx++; + ++ref_idx; + ++tgt_idx; + ++idx; } + ref_idx += (ref_stride - width); + tgt_idx += (tgt_stride - width); } } -static INLINE int get_filter_weight(unsigned int i, unsigned int j, - unsigned int block_height, - unsigned int block_width, const int *blk_fw, - int use_32x32) { - if (use_32x32) - // blk_fw[0] ~ blk_fw[3] are the same. - return blk_fw[0]; - - int filter_weight = 0; - if (i < block_height / 2) { - if (j < block_width / 2) - filter_weight = blk_fw[0]; - else - filter_weight = blk_fw[1]; - } else { - if (j < block_width / 2) - filter_weight = blk_fw[2]; - else - filter_weight = blk_fw[3]; - } - return filter_weight; -} - -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, 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; - int modifier; +// Function to adjust the filter weight when use YUV strategy. +// Inputs: +// filter_weight: Original filter weight. +// sum_square_diff: Sum of squared difference between input frame and +// prediction. This field is computed pixel by pixel, and +// is used as a reference for the filter weight adjustment. +// num_ref_pixels: Number of pixels used to compute the `sum_square_diff`. +// This field should align with the above lookup tables +// `filter_weight_adjustment_lookup_table_yuv` and +// `highbd_filter_weight_adjustment_lookup_table_yuv`. +// strength: Strength for filter weight adjustment. +// Returns: +// Adjusted filter weight which will finally be used for filtering. +static INLINE int adjust_filter_weight_yuv(const int filter_weight, + const uint64_t sum_square_diff, + const int num_ref_pixels, + const int strength) { + int modifier = + (int)(AOMMIN(sum_square_diff * TF_YUV_FILTER_WEIGHT_SCALE, INT32_MAX)) / + num_ref_pixels; const int rounding = (1 << strength) >> 1; - const unsigned int uv_block_width = block_width >> ss_x; - const unsigned int uv_block_height = block_height >> ss_y; - DECLARE_ALIGNED(16, uint16_t, y_diff_sse[BLK_PELS]); - DECLARE_ALIGNED(16, uint16_t, u_diff_sse[BLK_PELS]); - DECLARE_ALIGNED(16, uint16_t, v_diff_sse[BLK_PELS]); + modifier = (modifier + rounding) >> strength; + return (modifier >= 16) ? 0 : (16 - modifier) * filter_weight; +} - int idx = 0, idy; +// Applies temporal filter with YUV strategy. +// Inputs: +// frame_to_filter: Pointer to the frame to be filtered, which is used as +// reference to compute squared differece from the predictor. +// mbd: Pointer to the block for filtering, which is ONLY used to get +// subsampling information of all YUV planes. +// block_size: Size of the block. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// num_planes: Number of planes in the frame. +// strength: Strength for filter weight adjustment. +// use_subblock: Whether to use 4 sub-blocks to replace the original block. +// subblock_filter_weights: The filter weights for each sub-block (row-major +// order). If `use_subblock` is set as 0, the first +// weight will be applied to the entire block. +// pred: Pointer to the well-built predictors. +// accum: Pointer to the pixel-wise accumulator for filtering. +// count: Pointer to the pixel-wise counter fot filtering. +// Returns: +// Nothing will be returned. But the content to which `accum` and `pred` +// point will be modified. +void av1_apply_temporal_filter_yuv_c( + const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const int strength, const int use_subblock, + const int *subblock_filter_weights, const uint8_t *pred, uint32_t *accum, + uint16_t *count) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); - memset(y_diff_sse, 0, BLK_PELS * sizeof(uint16_t)); - memset(u_diff_sse, 0, BLK_PELS * sizeof(uint16_t)); - memset(v_diff_sse, 0, BLK_PELS * sizeof(uint16_t)); + // Block information. + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int is_high_bitdepth = is_frame_high_bitdepth(frame_to_filter); + const uint16_t *pred16 = CONVERT_TO_SHORTPTR(pred); - // Calculate diff^2 for each pixel of the block. - // TODO(yunqing): the following code needs to be optimized. - calculate_squared_errors(y_frame1, y_stride, y_pred, y_buf_stride, y_diff_sse, - block_width, block_height); - calculate_squared_errors(u_frame1, uv_stride, u_pred, uv_buf_stride, - u_diff_sse, uv_block_width, uv_block_height); - calculate_squared_errors(v_frame1, uv_stride, v_pred, uv_buf_stride, - v_diff_sse, uv_block_width, uv_block_height); + // Allocate memory for pixel-wise squared differences for all planes. They, + // regardless of the subsampling, are assigned with memory of size `mb_pels`. + uint32_t *square_diff = + aom_memalign(16, num_planes * mb_pels * sizeof(uint32_t)); + memset(square_diff, 0, num_planes * mb_pels * sizeof(square_diff[0])); - for (i = 0, k = 0, m = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++) { - const int pixel_value = y_pred[i * y_buf_stride + j]; - int filter_weight = - get_filter_weight(i, j, block_height, block_width, blk_fw, use_32x32); + int plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + // Locate pixel on reference frame. + const int plane_h = mb_height >> mbd->plane[plane].subsampling_y; + const int plane_w = mb_width >> mbd->plane[plane].subsampling_x; + const int frame_stride = frame_to_filter->strides[plane == 0 ? 0 : 1]; + const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w; + const uint8_t *ref = frame_to_filter->buffers[plane]; + compute_square_diff(ref, frame_offset, frame_stride, pred, plane_offset, + plane_w, plane_h, plane_w, is_high_bitdepth, + square_diff + plane_offset); + plane_offset += mb_pels; + } - // non-local mean approach - int y_index = 0; + // Get window size for pixel-wise filtering. + assert(TF_YUV_FILTER_WINDOW_LENGTH % 2 == 1); + const int half_window = TF_YUV_FILTER_WINDOW_LENGTH >> 1; - const int uv_r = i >> ss_y; - const int uv_c = j >> ss_x; - modifier = 0; - - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - const int row = (int)i + idy; - const int col = (int)j + idx; - - if (row >= 0 && row < (int)block_height && col >= 0 && - col < (int)block_width) { - modifier += y_diff_sse[row * (int)block_width + col]; - ++y_index; - } - } - } - - assert(y_index > 0); - - modifier += u_diff_sse[uv_r * uv_block_width + uv_c]; - modifier += v_diff_sse[uv_r * uv_block_width + uv_c]; - - y_index += 2; - - modifier = - (int)mod_index(modifier, y_index, rounding, strength, filter_weight); - - y_count[k] += modifier; - y_accumulator[k] += modifier * pixel_value; - - ++k; - - // Process chroma component - if (!(i & ss_y) && !(j & ss_x)) { - const int u_pixel_value = u_pred[uv_r * uv_buf_stride + uv_c]; - const int v_pixel_value = v_pred[uv_r * uv_buf_stride + uv_c]; + // Handle planes in sequence. + plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const int subsampling_y = mbd->plane[plane].subsampling_y; + const int subsampling_x = mbd->plane[plane].subsampling_x; + const int h = mb_height >> subsampling_y; // Plane height. + const int w = mb_width >> subsampling_x; // Plane width. + // Perform filtering. + int pred_idx = 0; + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { // non-local mean approach - int cr_index = 0; - int u_mod = 0, v_mod = 0; - int y_diff = 0; + uint64_t sum_square_diff = 0; + int num_ref_pixels = 0; - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - const int row = uv_r + idy; - const int col = uv_c + idx; - - if (row >= 0 && row < (int)uv_block_height && col >= 0 && - col < (int)uv_block_width) { - u_mod += u_diff_sse[row * uv_block_width + col]; - v_mod += v_diff_sse[row * uv_block_width + col]; - ++cr_index; + for (int wi = -half_window; wi <= half_window; ++wi) { + for (int wj = -half_window; wj <= half_window; ++wj) { + const int y = i + wi; // Y-coord on the current plane. + const int x = j + wj; // X-coord on the current plane. + if (y >= 0 && y < h && x >= 0 && x < w) { + sum_square_diff += square_diff[plane_offset + y * w + x]; + ++num_ref_pixels; } } } - assert(cr_index > 0); - - for (idy = 0; idy < 1 + ss_y; ++idy) { - for (idx = 0; idx < 1 + ss_x; ++idx) { - const int row = (uv_r << ss_y) + idy; - const int col = (uv_c << ss_x) + idx; - y_diff += y_diff_sse[row * (int)block_width + col]; - ++cr_index; + if (plane == 0) { // Filter Y-plane using both U-plane and V-plane. + for (int p = 1; p < num_planes; ++p) { + const int ss_y_shift = mbd->plane[p].subsampling_y - subsampling_y; + const int ss_x_shift = mbd->plane[p].subsampling_x - subsampling_x; + const int yy = i >> ss_y_shift; // Y-coord on UV-plane. + const int xx = j >> ss_x_shift; // X-coord on UV-plane. + const int ww = w >> ss_x_shift; // Width of UV-plane. + sum_square_diff += square_diff[p * mb_pels + yy * ww + xx]; + ++num_ref_pixels; } - } - - u_mod += y_diff; - v_mod += y_diff; - - u_mod = - (int)mod_index(u_mod, cr_index, rounding, strength, filter_weight); - v_mod = - (int)mod_index(v_mod, cr_index, rounding, strength, filter_weight); - - u_count[m] += u_mod; - u_accumulator[m] += u_mod * u_pixel_value; - v_count[m] += v_mod; - v_accumulator[m] += v_mod * v_pixel_value; - - ++m; - } // Complete YUV pixel - } - } -} - -static INLINE void highbd_calculate_squared_errors( - const uint16_t *s, int s_stride, const uint16_t *p, int p_stride, - uint32_t *diff_sse, unsigned int w, unsigned int h) { - int idx = 0; - unsigned int i, j; - - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++) { - const int16_t diff = s[i * s_stride + j] - p[i * p_stride + j]; - diff_sse[idx] = diff * diff; - idx++; - } - } -} - -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, - 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; - const unsigned int uv_block_width = block_width >> ss_x; - const unsigned int uv_block_height = block_height >> ss_y; - DECLARE_ALIGNED(16, uint32_t, y_diff_sse[BLK_PELS]); - DECLARE_ALIGNED(16, uint32_t, u_diff_sse[BLK_PELS]); - DECLARE_ALIGNED(16, uint32_t, v_diff_sse[BLK_PELS]); - - const uint16_t *y_frame1 = CONVERT_TO_SHORTPTR(yf); - const uint16_t *u_frame1 = CONVERT_TO_SHORTPTR(uf); - const uint16_t *v_frame1 = CONVERT_TO_SHORTPTR(vf); - const uint16_t *y_pred = CONVERT_TO_SHORTPTR(yp); - const uint16_t *u_pred = CONVERT_TO_SHORTPTR(up); - const uint16_t *v_pred = CONVERT_TO_SHORTPTR(vp); - int idx = 0, idy; - - memset(y_diff_sse, 0, BLK_PELS * sizeof(uint32_t)); - memset(u_diff_sse, 0, BLK_PELS * sizeof(uint32_t)); - memset(v_diff_sse, 0, BLK_PELS * sizeof(uint32_t)); - - // Calculate diff^2 for each pixel of the block. - // TODO(yunqing): the following code needs to be optimized. - highbd_calculate_squared_errors(y_frame1, y_stride, y_pred, y_buf_stride, - y_diff_sse, block_width, block_height); - highbd_calculate_squared_errors(u_frame1, uv_stride, u_pred, uv_buf_stride, - u_diff_sse, uv_block_width, uv_block_height); - highbd_calculate_squared_errors(v_frame1, uv_stride, v_pred, uv_buf_stride, - v_diff_sse, uv_block_width, uv_block_height); - - for (i = 0, k = 0, m = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++) { - const int pixel_value = y_pred[i * y_buf_stride + j]; - int filter_weight = - get_filter_weight(i, j, block_height, block_width, blk_fw, use_32x32); - - // non-local mean approach - int y_index = 0; - - const int uv_r = i >> ss_y; - const int uv_c = j >> ss_x; - modifier = 0; - - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - const int row = (int)i + idy; - const int col = (int)j + idx; - - if (row >= 0 && row < (int)block_height && col >= 0 && - col < (int)block_width) { - modifier += y_diff_sse[row * (int)block_width + col]; - ++y_index; - } - } - } - - assert(y_index > 0); - - modifier += u_diff_sse[uv_r * uv_block_width + uv_c]; - modifier += v_diff_sse[uv_r * uv_block_width + uv_c]; - - y_index += 2; - - 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; - - ++k; - - // Process chroma component - if (!(i & ss_y) && !(j & ss_x)) { - const int u_pixel_value = u_pred[uv_r * uv_buf_stride + uv_c]; - const int v_pixel_value = v_pred[uv_r * uv_buf_stride + uv_c]; - - // non-local mean approach - int cr_index = 0; - int64_t u_mod = 0, v_mod = 0; - int y_diff = 0; - - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - const int row = uv_r + idy; - const int col = uv_c + idx; - - if (row >= 0 && row < (int)uv_block_height && col >= 0 && - col < (int)uv_block_width) { - u_mod += u_diff_sse[row * uv_block_width + col]; - v_mod += v_diff_sse[row * uv_block_width + col]; - ++cr_index; + } else { // Filter U-plane and V-plane using Y-plane. + const int ss_y_shift = subsampling_y - mbd->plane[0].subsampling_y; + const int ss_x_shift = subsampling_x - mbd->plane[0].subsampling_x; + for (int ii = 0; ii < (1 << ss_y_shift); ++ii) { + for (int jj = 0; jj < (1 << ss_x_shift); ++jj) { + const int yy = (i << ss_y_shift) + ii; // Y-coord on Y-plane. + const int xx = (j << ss_x_shift) + jj; // X-coord on Y-plane. + const int ww = w << ss_x_shift; // Width of Y-plane. + sum_square_diff += square_diff[yy * ww + xx]; + ++num_ref_pixels; } } } - assert(cr_index > 0); + // Base filter weight estimated by motion search error. + const int subblock_idx = + use_subblock ? (i >= h / 2) * 2 + (j >= w / 2) : 0; + const int filter_weight = subblock_filter_weights[subblock_idx]; - for (idy = 0; idy < 1 + ss_y; ++idy) { - for (idx = 0; idx < 1 + ss_x; ++idx) { - const int row = (uv_r << ss_y) + idy; - const int col = (uv_c << ss_x) + idx; - y_diff += y_diff_sse[row * (int)block_width + col]; - ++cr_index; + const int idx = plane_offset + pred_idx; // Index with plane shift. + const int pred_value = is_high_bitdepth ? pred16[idx] : pred[idx]; + const int adjusted_weight = adjust_filter_weight_yuv( + filter_weight, sum_square_diff, num_ref_pixels, strength); + accum[idx] += adjusted_weight * pred_value; + count[idx] += adjusted_weight; + + ++pred_idx; + } + } + plane_offset += mb_pels; + } + + aom_free(square_diff); +} + +// Applies temporal filter with plane-wise strategy. +// The strategy of filter weight adjustment is different from the function +// `av1_apply_temporal_filter_yuv_c()`. +// Inputs: +// frame_to_filter: Pointer to the frame to be filtered, which is used as +// reference to compute squared differece from the predictor. +// mbd: Pointer to the block for filtering, which is ONLY used to get +// subsampling information of all planes. +// block_size: Size of the block. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// num_planes: Number of planes in the frame. +// noise_levels: Pointer to the noise levels of the to-filter frame, estimated +// with each plane (in Y, U, V order). +// use_subblock: Whether to use 4 sub-blocks to replace the original block. +// block_mse: Motion search error (MSE) for the entire block. +// subblock_mses: Pointer to the search errors (MSE) for 4 sub-blocks. +// q_factor: Quantization factor. This is actually the `q` defined in libaom, +// which is converted from `qindex`. +// pred: Pointer to the well-built predictors. +// accum: Pointer to the pixel-wise accumulator for filtering. +// count: Pointer to the pixel-wise counter fot filtering. +// Returns: +// Nothing will be returned. But the content to which `accum` and `pred` +// point will be modified. +void av1_apply_temporal_filter_planewise_c( + const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_levels, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + const uint8_t *pred, uint32_t *accum, uint16_t *count) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + + // Block information. + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int is_high_bitdepth = is_frame_high_bitdepth(frame_to_filter); + const uint16_t *pred16 = CONVERT_TO_SHORTPTR(pred); + + // Allocate memory for pixel-wise squared differences for all planes. They, + // regardless of the subsampling, are assigned with memory of size `mb_pels`. + uint32_t *square_diff = + aom_memalign(16, num_planes * mb_pels * sizeof(uint32_t)); + memset(square_diff, 0, num_planes * mb_pels * sizeof(square_diff[0])); + + int plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + // Locate pixel on reference frame. + const int plane_h = mb_height >> mbd->plane[plane].subsampling_y; + const int plane_w = mb_width >> mbd->plane[plane].subsampling_x; + const int frame_stride = frame_to_filter->strides[plane == 0 ? 0 : 1]; + const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w; + const uint8_t *ref = frame_to_filter->buffers[plane]; + compute_square_diff(ref, frame_offset, frame_stride, pred, plane_offset, + plane_w, plane_h, plane_w, is_high_bitdepth, + square_diff + plane_offset); + plane_offset += mb_pels; + } + + // Get window size for pixel-wise filtering. + assert(TF_PLANEWISE_FILTER_WINDOW_LENGTH % 2 == 1); + const int half_window = TF_PLANEWISE_FILTER_WINDOW_LENGTH >> 1; + + // Hyper-parameter for filter weight adjustment. + const int frame_height = frame_to_filter->heights[0] + << mbd->plane[0].subsampling_y; + const int decay_control = frame_height >= 720 ? 4 : 3; + + // Handle planes in sequence. + plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const int subsampling_y = mbd->plane[plane].subsampling_y; + const int subsampling_x = mbd->plane[plane].subsampling_x; + const int h = mb_height >> subsampling_y; // Plane height. + const int w = mb_width >> subsampling_x; // Plane width. + + // Perform filtering. + int pred_idx = 0; + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + // non-local mean approach + uint64_t sum_square_diff = 0; + int num_ref_pixels = 0; + + for (int wi = -half_window; wi <= half_window; ++wi) { + for (int wj = -half_window; wj <= half_window; ++wj) { + const int y = CLIP(i + wi, 0, h - 1); // Y-coord on current plane. + const int x = CLIP(j + wj, 0, w - 1); // X-coord on current plane. + sum_square_diff += square_diff[plane_offset + y * w + x]; + ++num_ref_pixels; } } - u_mod += y_diff; - v_mod += y_diff; - - 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; - v_count[m] += final_v_mod; - v_accumulator[m] += final_v_mod * v_pixel_value; - - ++m; - } // Complete YUV pixel - } - } -} - -// Only used in single plane case -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, - const int *blk_fw, int use_32x32, - unsigned int *accumulator, uint16_t *count) { - unsigned int i, j, k; - int modifier; - int byte = 0; - const int rounding = strength > 0 ? 1 << (strength - 1) : 0; - - for (i = 0, k = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++, k++) { - int pixel_value = *frame2; - int filter_weight = - get_filter_weight(i, j, block_height, block_width, blk_fw, use_32x32); - - // non-local mean approach - int diff_sse[9] = { 0 }; - int idx, idy, index = 0; - - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - int row = (int)i + idy; - int col = (int)j + idx; - - if (row >= 0 && row < (int)block_height && col >= 0 && - col < (int)block_width) { - int diff = frame1[byte + idy * (int)stride + idx] - - frame2[idy * (int)block_width + idx]; - diff_sse[index] = diff * diff; - ++index; + // Filter U-plane and V-plane using Y-plane. This is because motion + // search is only done on Y-plane, so the information from Y-plane will + // be more accurate. + if (plane != 0) { + const int ss_y_shift = subsampling_y - mbd->plane[0].subsampling_y; + const int ss_x_shift = subsampling_x - mbd->plane[0].subsampling_x; + for (int ii = 0; ii < (1 << ss_y_shift); ++ii) { + for (int jj = 0; jj < (1 << ss_x_shift); ++jj) { + const int yy = (i << ss_y_shift) + ii; // Y-coord on Y-plane. + const int xx = (j << ss_x_shift) + jj; // X-coord on Y-plane. + const int ww = w << ss_x_shift; // Width of Y-plane. + sum_square_diff += square_diff[yy * ww + xx]; + ++num_ref_pixels; + } } } + + // Scale down the difference for high bit depth input. + if (mbd->bd > 8) sum_square_diff >>= (mbd->bd - 8) * (mbd->bd - 8); + const double window_error = (double)(sum_square_diff) / num_ref_pixels; + const int subblock_idx = (i >= h / 2) * 2 + (j >= w / 2); + const double block_error = + (double)(use_subblock ? subblock_mses[subblock_idx] : block_mse); + + // Control factor for non-local mean approach. + const double r = + (double)decay_control * (0.7 + log(noise_levels[plane] + 1.0)); + const double q = AOMMIN((double)(q_factor * q_factor) / 256.0, 1); + + // Compute filter weight. + const double scaled_diff = + AOMMAX(-(window_error + block_error / 10) / (2 * r * r * q), -15.0); + const int adjusted_weight = + (int)(exp(scaled_diff) * TF_PLANEWISE_FILTER_WEIGHT_SCALE); + + const int idx = plane_offset + pred_idx; // Index with plane shift. + const int pred_value = is_high_bitdepth ? pred16[idx] : pred[idx]; + accum[idx] += adjusted_weight * pred_value; + count[idx] += adjusted_weight; + + ++pred_idx; } - - assert(index > 0); - - modifier = 0; - for (idx = 0; idx < 9; ++idx) modifier += diff_sse[idx]; - - modifier *= 3; - modifier /= index; - - ++frame2; - - modifier += rounding; - modifier >>= strength; - - if (modifier > 16) modifier = 16; - - modifier = 16 - modifier; - modifier *= filter_weight; - - count[k] += modifier; - accumulator[k] += modifier * pixel_value; - - byte++; } - - byte += stride - block_width; + plane_offset += mb_pels; } + + aom_free(square_diff); } -// Only used in single plane case -void av1_highbd_temporal_filter_apply_c( - uint8_t *frame1_8, unsigned int stride, uint8_t *frame2_8, - unsigned int block_width, unsigned int block_height, int strength, - int *blk_fw, int use_32x32, unsigned int *accumulator, uint16_t *count) { - uint16_t *frame1 = CONVERT_TO_SHORTPTR(frame1_8); - uint16_t *frame2 = CONVERT_TO_SHORTPTR(frame2_8); - unsigned int i, j, k; - int modifier; - int byte = 0; - const int rounding = strength > 0 ? 1 << (strength - 1) : 0; +// Computes temporal filter weights and accumulators from all reference frames +// excluding the current frame to be filtered. +// Inputs: +// frame_to_filter: Pointer to the frame to be filtered, which is used as +// reference to compute squared differece from the predictor. +// mbd: Pointer to the block for filtering, which is ONLY used to get +// subsampling information of all planes and the bit-depth. +// block_size: Size of the block. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// num_planes: Number of planes in the frame. +// strength: Strength for filter weight adjustment. (Used in YUV strategy) +// use_subblock: Whether to use 4 sub-blocks to replace the original block. +// (Used in YUV strategy) +// subblock_filter_weights: The filter weights for each sub-block (row-major +// order). If `use_subblock` is set as 0, the first +// weight will be applied to the entire block. (Used +// in YUV strategy) +// noise_levels: Pointer to the noise levels of the to-filter frame, estimated +// with each plane (in Y, U, V order). (Used in plane-wise +// strategy) +// block_mse: Motion search error (MSE) for the entire block. +// subblock_mses: Pointer to the search errors (MSE) for 4 sub-blocks. +// q_factor: Quantization factor. +// pred: Pointer to the well-built predictors. +// accum: Pointer to the pixel-wise accumulator for filtering. +// count: Pointer to the pixel-wise counter fot filtering. +// Returns: +// Nothing will be returned. But the content to which `accum` and `pred` +// point will be modified. +void av1_apply_temporal_filter_others( + const YV12_BUFFER_CONFIG *frame_to_filter, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const int strength, const int use_subblock, + const int *subblock_filter_weights, const double *noise_levels, + const int block_mse, const int *subblock_mses, const int q_factor, + const uint8_t *pred, uint32_t *accum, uint16_t *count) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); - for (i = 0, k = 0; i < block_height; i++) { - for (j = 0; j < block_width; j++, k++) { - int pixel_value = *frame2; - int filter_weight = - get_filter_weight(i, j, block_height, block_width, blk_fw, use_32x32); - - // non-local mean approach - int diff_sse[9] = { 0 }; - int idx, idy, index = 0; - - for (idy = -1; idy <= 1; ++idy) { - for (idx = -1; idx <= 1; ++idx) { - int row = (int)i + idy; - int col = (int)j + idx; - - if (row >= 0 && row < (int)block_height && col >= 0 && - col < (int)block_width) { - int diff = frame1[byte + idy * (int)stride + idx] - - frame2[idy * (int)block_width + idx]; - diff_sse[index] = diff * diff; - ++index; - } - } - } - - assert(index > 0); - - modifier = 0; - for (idx = 0; idx < 9; ++idx) modifier += diff_sse[idx]; - - modifier *= 3; - modifier /= index; - - ++frame2; - - modifier += rounding; - modifier >>= strength; - - if (modifier > 16) modifier = 16; - - modifier = 16 - modifier; - modifier *= filter_weight; - - count[k] += modifier; - accumulator[k] += modifier * pixel_value; - - byte++; - } - - byte += stride - block_width; - } -} - -#if EXPERIMENT_TEMPORAL_FILTER -void av1_temporal_filter_plane_c(uint8_t *frame1, unsigned int stride, - uint8_t *frame2, unsigned int stride2, - int block_width, int block_height, - int strength, double sigma, int decay_control, - const int *blk_fw, int use_32x32, - unsigned int *accumulator, uint16_t *count) { - (void)strength; - (void)blk_fw; - (void)use_32x32; - const double decay = decay_control * exp(1 - sigma); - const double h = decay * sigma; - const double beta = 1.0; - for (int i = 0, k = 0; i < block_height; i++) { - for (int j = 0; j < block_width; j++, k++) { - const int pixel_value = frame2[i * stride2 + j]; - - int diff_sse = 0; - for (int idy = -WINDOW_LENGTH; idy <= WINDOW_LENGTH; ++idy) { - for (int idx = -WINDOW_LENGTH; idx <= WINDOW_LENGTH; ++idx) { - int row = i + idy; - int col = j + idx; - if (row < 0) row = 0; - if (row >= block_height) row = block_height - 1; - if (col < 0) col = 0; - if (col >= block_width) col = block_width - 1; - - int diff = frame1[row * (int)stride + col] - - frame2[row * (int)stride2 + col]; - diff_sse += diff * diff; - } - } - diff_sse /= WINDOW_SIZE; - - double scaled_diff = -diff_sse / (2 * beta * h * h); - // clamp the value to avoid underflow in exp() - if (scaled_diff < -15) scaled_diff = -15; - double w = exp(scaled_diff); - const int weight = (int)(w * SCALE); - - count[k] += weight; - accumulator[k] += weight * pixel_value; - } - } -} - -void av1_highbd_temporal_filter_plane_c( - uint8_t *frame1_8bit, unsigned int stride, uint8_t *frame2_8bit, - unsigned int stride2, int block_width, int block_height, int strength, - double sigma, int decay_control, const int *blk_fw, int use_32x32, - unsigned int *accumulator, uint16_t *count) { - (void)strength; - (void)blk_fw; - (void)use_32x32; - uint16_t *frame1 = CONVERT_TO_SHORTPTR(frame1_8bit); - uint16_t *frame2 = CONVERT_TO_SHORTPTR(frame2_8bit); - const double decay = decay_control * exp(1 - sigma); - const double h = decay * sigma; - const double beta = 1.0; - for (int i = 0, k = 0; i < block_height; i++) { - for (int j = 0; j < block_width; j++, k++) { - const int pixel_value = frame2[i * stride2 + j]; - - int diff_sse = 0; - for (int idy = -WINDOW_LENGTH; idy <= WINDOW_LENGTH; ++idy) { - for (int idx = -WINDOW_LENGTH; idx <= WINDOW_LENGTH; ++idx) { - int row = i + idy; - int col = j + idx; - if (row < 0) row = 0; - if (row >= block_height) row = block_height - 1; - if (col < 0) col = 0; - if (col >= block_width) col = block_width - 1; - - int diff = frame1[row * (int)stride + col] - - frame2[row * (int)stride2 + col]; - diff_sse += diff * diff; - } - } - diff_sse /= WINDOW_SIZE; - - double scaled_diff = -diff_sse / (2 * beta * h * h); - // clamp the value to avoid underflow in exp() - if (scaled_diff < -20) scaled_diff = -20; - double w = exp(scaled_diff); - const int weight = (int)(w * SCALE); - - count[k] += weight; - accumulator[k] += weight * pixel_value; - } - } -} - -void apply_temporal_filter_block(YV12_BUFFER_CONFIG *frame, MACROBLOCKD *mbd, - int mb_y_src_offset, int mb_uv_src_offset, - int mb_uv_width, int mb_uv_height, - int num_planes, uint8_t *predictor, - int frame_height, int strength, double sigma, - int *blk_fw, int use_32x32, - unsigned int *accumulator, uint16_t *count, - int use_new_temporal_mode) { - const int is_hbd = is_cur_buf_hbd(mbd); - // High bitdepth - if (is_hbd) { - if (use_new_temporal_mode) { - // Apply frame size dependent non-local means filtering. - int decay_control; - // The decay is obtained empirically, subject to better tuning. - if (frame_height >= 720) { - decay_control = 7; - } else if (frame_height >= 480) { - decay_control = 5; - } else { - decay_control = 3; - } - av1_highbd_temporal_filter_plane_c(frame->y_buffer + mb_y_src_offset, - frame->y_stride, predictor, BW, BW, BH, - strength, sigma, decay_control, blk_fw, - use_32x32, accumulator, count); - if (num_planes > 1) { - av1_highbd_temporal_filter_plane_c( - frame->u_buffer + mb_uv_src_offset, frame->uv_stride, - predictor + BLK_PELS, mb_uv_width, mb_uv_width, mb_uv_height, - strength, sigma, decay_control, blk_fw, use_32x32, - accumulator + BLK_PELS, count + BLK_PELS); - av1_highbd_temporal_filter_plane_c( - frame->v_buffer + mb_uv_src_offset, frame->uv_stride, - predictor + (BLK_PELS << 1), mb_uv_width, mb_uv_width, mb_uv_height, - strength, sigma, decay_control, blk_fw, use_32x32, - accumulator + (BLK_PELS << 1), count + (BLK_PELS << 1)); - } + if (TF_ENABLE_PLANEWISE_STRATEGY) { + // TODO(any): avx2 and sse2 version should be changed to align with C + // function before using. + if (is_frame_high_bitdepth(frame_to_filter) || block_size != BLOCK_32X32) { + av1_apply_temporal_filter_planewise_c( + frame_to_filter, mbd, block_size, mb_row, mb_col, num_planes, + noise_levels, use_subblock, block_mse, subblock_mses, q_factor, pred, + accum, count); } else { - // Apply original non-local means filtering for small resolution - const int adj_strength = strength + 2 * (mbd->bd - 8); - if (num_planes <= 1) { - // Single plane case - av1_highbd_temporal_filter_apply_c( - frame->y_buffer + mb_y_src_offset, frame->y_stride, predictor, BW, - BH, adj_strength, blk_fw, use_32x32, accumulator, count); - } else { - // Process 3 planes together. - av1_highbd_apply_temporal_filter( - frame->y_buffer + mb_y_src_offset, frame->y_stride, predictor, BW, - frame->u_buffer + mb_uv_src_offset, - frame->v_buffer + mb_uv_src_offset, frame->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_apply_temporal_filter_planewise( + frame_to_filter, mbd, block_size, mb_row, mb_col, num_planes, + noise_levels, use_subblock, block_mse, subblock_mses, q_factor, pred, + accum, count); + } + } else { // Commonly used for low-resolution video. + if (subblock_filter_weights[0] == 0 && subblock_filter_weights[1] == 0 && + subblock_filter_weights[2] == 0 && subblock_filter_weights[3] == 0) { + return; + } + const int adj_strength = strength + 2 * (mbd->bd - 8); + if (num_planes == 3 && TF_YUV_FILTER_WEIGHT_SCALE == 3 && + block_size != BLOCK_32X32) { + av1_apply_temporal_filter_yuv(frame_to_filter, mbd, block_size, mb_row, + mb_col, num_planes, adj_strength, + use_subblock, subblock_filter_weights, pred, + accum, count); + } else { + // TODO(any): sse4 version should be changed to align with C function + // before using. + av1_apply_temporal_filter_yuv_c(frame_to_filter, mbd, block_size, mb_row, + mb_col, num_planes, adj_strength, + use_subblock, subblock_filter_weights, + pred, accum, count); + } + } +} + +// Normalizes the accumulated filtering result to produce the filtered frame. +// Inputs: +// mbd: Pointer to the block for filtering, which is ONLY used to get +// subsampling information of all planes. +// block_size: Size of the block. +// mb_row: Row index of the block in the entire frame. +// mb_col: Column index of the block in the entire frame. +// num_planes: Number of planes in the frame. +// accum: Pointer to the pre-computed accumulator. +// count: Pointer to the pre-computed count. +// result_buffer: Pointer to result buffer. +// Returns: +// Nothing will be returned. But the content to which `result_buffer` point +// will be modified. +static void tf_normalize_filtered_frame( + const MACROBLOCKD *mbd, const BLOCK_SIZE block_size, const int mb_row, + const int mb_col, const int num_planes, const uint32_t *accum, + const uint16_t *count, YV12_BUFFER_CONFIG *result_buffer) { + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + + // Block information. + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int is_high_bitdepth = is_frame_high_bitdepth(result_buffer); + + int plane_offset = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const int plane_h = mb_height >> mbd->plane[plane].subsampling_y; + const int plane_w = mb_width >> mbd->plane[plane].subsampling_x; + const int frame_stride = result_buffer->strides[plane == 0 ? 0 : 1]; + const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w; + uint8_t *const buf = result_buffer->buffers[plane]; + uint16_t *const buf16 = CONVERT_TO_SHORTPTR(buf); + + int plane_idx = 0; // Pixel index on current plane (block-base). + int frame_idx = frame_offset; // Pixel index on the entire frame. + for (int i = 0; i < plane_h; ++i) { + for (int j = 0; j < plane_w; ++j) { + const int idx = plane_idx + plane_offset; + const uint16_t rounding = count[idx] >> 1; + if (is_high_bitdepth) { + buf16[frame_idx] = + (uint16_t)OD_DIVU(accum[idx] + rounding, count[idx]); + } else { + buf[frame_idx] = (uint8_t)OD_DIVU(accum[idx] + rounding, count[idx]); + } + ++plane_idx; + ++frame_idx; } + frame_idx += (frame_stride - plane_w); } - return; - } - - // Low bitdepth - if (use_new_temporal_mode) { - // Apply frame size dependent non-local means filtering. - int decay_control; - // The decay is obtained empirically, subject to better tuning. - if (frame_height >= 720) { - decay_control = 7; - } else if (frame_height >= 480) { - decay_control = 5; - } else { - decay_control = 3; - } - av1_temporal_filter_plane_c(frame->y_buffer + mb_y_src_offset, - frame->y_stride, predictor, BW, BW, BH, - strength, sigma, decay_control, blk_fw, - use_32x32, accumulator, count); - if (num_planes > 1) { - av1_temporal_filter_plane_c( - frame->u_buffer + mb_uv_src_offset, frame->uv_stride, - predictor + BLK_PELS, mb_uv_width, mb_uv_width, mb_uv_height, - strength, sigma, decay_control, blk_fw, use_32x32, - accumulator + BLK_PELS, count + BLK_PELS); - av1_temporal_filter_plane_c( - frame->v_buffer + mb_uv_src_offset, frame->uv_stride, - predictor + (BLK_PELS << 1), mb_uv_width, mb_uv_width, mb_uv_height, - strength, sigma, decay_control, blk_fw, use_32x32, - accumulator + (BLK_PELS << 1), count + (BLK_PELS << 1)); - } - } else { - // Apply original non-local means filtering for small resolution - if (num_planes <= 1) { - // Single plane case - av1_temporal_filter_apply_c(frame->y_buffer + mb_y_src_offset, - frame->y_stride, predictor, BW, BH, strength, - blk_fw, use_32x32, accumulator, count); - } else { - // Process 3 planes together. - av1_apply_temporal_filter( - frame->y_buffer + mb_y_src_offset, frame->y_stride, predictor, BW, - frame->u_buffer + mb_uv_src_offset, - frame->v_buffer + mb_uv_src_offset, frame->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)); - } + plane_offset += mb_pels; } } -#endif // EXPERIMENT_TEMPORAL_FILTER -static int temporal_filter_find_matching_mb_c( - AV1_COMP *cpi, uint8_t *arf_frame_buf, uint8_t *frame_ptr_buf, int stride, - int x_pos, int y_pos, MV *blk_mvs, int *blk_bestsme, MV *best_ref_mv1, - int step_param) { - MACROBLOCK *const x = &cpi->td.mb; - MACROBLOCKD *const xd = &x->e_mbd; - const MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv; - int sadpb = x->sadperbit16; - int bestsme = INT_MAX; - int distortion; - unsigned int sse; - int cost_list[5]; - MvLimits tmp_mv_limits = x->mv_limits; - MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */ - MV ref_mv = kZeroMv; - // Save input state - struct buf_2d src = x->plane[0].src; - struct buf_2d pre = xd->plane[0].pre[0]; - best_ref_mv1_full.col = best_ref_mv1->col >> 3; - best_ref_mv1_full.row = best_ref_mv1->row >> 3; - - // Setup frame pointers - x->plane[0].src.buf = arf_frame_buf; - x->plane[0].src.stride = stride; - xd->plane[0].pre[0].buf = frame_ptr_buf; - xd->plane[0].pre[0].stride = stride; - - av1_set_mv_search_range(&x->mv_limits, &ref_mv); - - // av1_full_pixel_search() parameters: best_ref_mv1_full is the start mv, and - // ref_mv is for mv rate calculation. The search result is stored in - // 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), &ref_mv, 0, 0, - x_pos, y_pos, 0, &cpi->ss_cfg[SS_CFG_LOOKAHEAD], 0); - x->mv_limits = tmp_mv_limits; - - // Ignore mv costing by sending NULL pointer instead of cost array - if (cpi->common.cur_frame_force_integer_mv == 1) { - const uint8_t *const src_address = x->plane[0].src.buf; - const int src_stride = x->plane[0].src.stride; - const uint8_t *const y = xd->plane[0].pre[0].buf; - const int y_stride = xd->plane[0].pre[0].stride; - const int offset = x->best_mv.as_mv.row * y_stride + x->best_mv.as_mv.col; - - x->best_mv.as_mv.row *= 8; - x->best_mv.as_mv.col *= 8; - - bestsme = cpi->fn_ptr[TF_BLOCK].vf(y + offset, y_stride, src_address, - src_stride, &sse); - - x->e_mbd.mi[0]->mv[0] = x->best_mv; - - // Restore input state - x->plane[0].src = src; - xd->plane[0].pre[0] = pre; - - return bestsme; - } - - // find_fractional_mv_step parameters: ref_mv is for mv rate cost - // calculation. The start full mv and the search result are stored in - // x->best_mv. mi_row and mi_col are only needed for "av1_is_scaled(sf)=1" - // case. - bestsme = cpi->find_fractional_mv_step( - x, &cpi->common, 0, 0, &ref_mv, cpi->common.allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[TF_BLOCK], 0, mv_sf->subpel_iters_per_step, - cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL, NULL, - 0, 0, BW, BH, USE_8_TAPS, 1); - - x->e_mbd.mi[0]->mv[0] = x->best_mv; - - // DO motion search on 4 16x16 sub_blocks. - int i, j, k = 0; - best_ref_mv1->row = x->e_mbd.mi[0]->mv[0].as_mv.row; - best_ref_mv1->col = x->e_mbd.mi[0]->mv[0].as_mv.col; - best_ref_mv1_full.col = best_ref_mv1->col >> 3; - best_ref_mv1_full.row = best_ref_mv1->row >> 3; - - for (i = 0; i < BH; i += SUB_BH) { - for (j = 0; j < BW; j += SUB_BW) { - // Setup frame pointers - x->plane[0].src.buf = arf_frame_buf + i * stride + j; - x->plane[0].src.stride = stride; - xd->plane[0].pre[0].buf = frame_ptr_buf + i * stride + j; - xd->plane[0].pre[0].stride = stride; - - av1_set_mv_search_range(&x->mv_limits, &ref_mv); - av1_full_pixel_search(cpi, x, TF_SUB_BLOCK, &best_ref_mv1_full, - step_param, NSTEP, 1, sadpb, - cond_cost_list(cpi, cost_list), &ref_mv, 0, 0, - x_pos, y_pos, 0, &cpi->ss_cfg[SS_CFG_LOOKAHEAD], 0); - x->mv_limits = tmp_mv_limits; - - blk_bestsme[k] = cpi->find_fractional_mv_step( - x, &cpi->common, 0, 0, &ref_mv, cpi->common.allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[TF_SUB_BLOCK], 0, - mv_sf->subpel_iters_per_step, cond_cost_list(cpi, cost_list), NULL, - NULL, &distortion, &sse, NULL, NULL, 0, 0, SUB_BW, SUB_BH, USE_8_TAPS, - 1); - - blk_mvs[k] = x->best_mv.as_mv; - k++; - } - } - - // Restore input state - x->plane[0].src = src; - xd->plane[0].pre[0] = pre; - - return bestsme; +// Helper function to compute number of blocks on either side of the frame. +static INLINE int get_num_blocks(const int frame_length, const int mb_length) { + return (frame_length + mb_length - 1) / mb_length; } -static int get_rows(int h) { return (h + BH - 1) >> BH_LOG2; } -static int get_cols(int w) { return (w + BW - 1) >> BW_LOG2; } - typedef struct { int64_t sum; int64_t sse; } FRAME_DIFF; -static FRAME_DIFF temporal_filter_iterate_c( - AV1_COMP *cpi, YV12_BUFFER_CONFIG **frames, int frame_count, - int alt_ref_index, int strength, double sigma, int is_key_frame, - struct scale_factors *ref_scale_factors) { - const AV1_COMMON *cm = &cpi->common; - const int num_planes = av1_num_planes(cm); - const int mb_cols = get_cols(frames[alt_ref_index]->y_crop_width); - const int mb_rows = get_rows(frames[alt_ref_index]->y_crop_height); - // TODO(any): the thresholds in this function need to adjusted based on bit_ - // depth, so that they work better in HBD encoding. - const int bd_shift = cm->seq_params.bit_depth - 8; - int byte; - int frame; - int mb_col, mb_row; - 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; - YV12_BUFFER_CONFIG *f = frames[alt_ref_index]; - uint8_t *dst1, *dst2; - DECLARE_ALIGNED(32, uint16_t, predictor16[BLK_PELS * 3]); - DECLARE_ALIGNED(32, uint8_t, predictor8[BLK_PELS * 3]); - uint8_t *predictor; - const int mb_uv_height = BH >> mbd->plane[1].subsampling_y; - const int mb_uv_width = BW >> mbd->plane[1].subsampling_x; -#if EXPERIMENT_TEMPORAL_FILTER - const int is_screen_content_type = cm->allow_screen_content_tools != 0; - const int use_new_temporal_mode = AOMMIN(cm->width, cm->height) >= 480 && - !is_screen_content_type && !is_key_frame; -#else - (void)sigma; - const int use_new_temporal_mode = 0; -#endif +// Does temporal filter for a particular frame. +// Inputs: +// cpi: Pointer to the composed information of input video. +// frames: Frame buffers used for temporal filtering. +// num_frames: Number of frames in the frame buffer. +// filter_frame_idx: Index of the frame to be filtered. +// is_key_frame: Whether the to-filter is a key frame. +// is_second_arf: Whether the to-filter frame is the second ARF. This field +// is ONLY used for assigning filter weight. +// block_size: Block size used for temporal filtering. +// scale: Scaling factor. +// strength: Pre-estimated strength for filter weight adjustment. +// noise_levels: Pointer to the noise levels of the to-filter frame, estimated +// with each plane (in Y, U, V order). +// Returns: +// Difference between filtered frame and the original frame. +static FRAME_DIFF tf_do_filtering( + AV1_COMP *cpi, YV12_BUFFER_CONFIG **frames, const int num_frames, + const int filter_frame_idx, const int is_key_frame, const int is_second_arf, + const BLOCK_SIZE block_size, const struct scale_factors *scale, + const int strength, const double *noise_levels) { + // Basic information. + const YV12_BUFFER_CONFIG *const frame_to_filter = frames[filter_frame_idx]; + const int frame_height = frame_to_filter->y_crop_height; + const int frame_width = frame_to_filter->y_crop_width; + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + const int mb_rows = get_num_blocks(frame_height, mb_height); + const int mb_cols = get_num_blocks(frame_width, mb_width); + const int num_planes = av1_num_planes(&cpi->common); + const int mi_h = mi_size_high_log2[block_size]; + const int mi_w = mi_size_wide_log2[block_size]; + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + const int is_high_bitdepth = is_frame_high_bitdepth(frame_to_filter); - // Save input state + // Save input state. + MACROBLOCK *const mb = &cpi->td.mb; + MACROBLOCKD *const mbd = &mb->e_mbd; uint8_t *input_buffer[MAX_MB_PLANE]; - int i; - const int is_hbd = is_cur_buf_hbd(mbd); - if (is_hbd) { - predictor = CONVERT_TO_BYTEPTR(predictor16); - } else { - predictor = predictor8; + for (int i = 0; i < num_planes; i++) { + input_buffer[i] = mbd->plane[i].pre[0].buf; } + MB_MODE_INFO **input_mb_mode_info = mbd->mi; - const unsigned int dim = AOMMIN(frames[alt_ref_index]->y_crop_width, - frames[alt_ref_index]->y_crop_height); - // Decide search param based on image resolution. - const int step_param = av1_init_search_range(dim); - - mbd->block_ref_scale_factors[0] = ref_scale_factors; - mbd->block_ref_scale_factors[1] = ref_scale_factors; - - for (i = 0; i < num_planes; i++) input_buffer[i] = mbd->plane[i].pre[0].buf; - - // Make a temporary mbmi for temporal filtering - MB_MODE_INFO **backup_mi_grid = mbd->mi; - MB_MODE_INFO mbmi; - memset(&mbmi, 0, sizeof(mbmi)); - MB_MODE_INFO *mbmi_ptr = &mbmi; - mbd->mi = &mbmi_ptr; + // Setup. + mbd->block_ref_scale_factors[0] = scale; + mbd->block_ref_scale_factors[1] = scale; + // A temporary block info used to store state in temporal filtering process. + MB_MODE_INFO *tmp_mb_mode_info = (MB_MODE_INFO *)malloc(sizeof(MB_MODE_INFO)); + memset(tmp_mb_mode_info, 0, sizeof(MB_MODE_INFO)); + mbd->mi = &tmp_mb_mode_info; + mbd->mi[0]->motion_mode = SIMPLE_TRANSLATION; + // Allocate memory for predictor, accumulator and count. + uint8_t *pred8 = aom_memalign(32, num_planes * mb_pels * sizeof(uint8_t)); + uint16_t *pred16 = aom_memalign(32, num_planes * mb_pels * sizeof(uint16_t)); + uint32_t *accum = aom_memalign(16, num_planes * mb_pels * sizeof(uint32_t)); + uint16_t *count = aom_memalign(16, num_planes * mb_pels * sizeof(uint16_t)); + memset(pred8, 0, num_planes * mb_pels * sizeof(pred8[0])); + memset(pred16, 0, num_planes * mb_pels * sizeof(pred16[0])); + uint8_t *const pred = is_high_bitdepth ? CONVERT_TO_BYTEPTR(pred16) : pred8; + // Do filtering. FRAME_DIFF diff = { 0, 0 }; - - for (mb_row = 0; mb_row < mb_rows; mb_row++) { - // Source frames are extended to 16 pixels. This is different than - // L/A/G reference frames that have a border of 32 (AV1ENCBORDERINPIXELS) - // A 6/8 tap filter is used for motion search. This requires 2 pixels - // before and 3 pixels after. So the largest Y mv on a border would - // then be 16 - AOM_INTERP_EXTEND. The UV blocks are half the size of the - // Y and therefore only extended by 8. The largest mv that a UV block - // can support is 8 - AOM_INTERP_EXTEND. A UV mv is half of a Y mv. - // (16 - AOM_INTERP_EXTEND) >> 1 which is greater than - // 8 - AOM_INTERP_EXTEND. - // To keep the mv in play for both Y and UV planes the max that it - // can be on a border is therefore 16 - (2*AOM_INTERP_EXTEND+1). - cpi->td.mb.mv_limits.row_min = - -((mb_row * BH) + (17 - 2 * AOM_INTERP_EXTEND)); - cpi->td.mb.mv_limits.row_max = - ((mb_rows - 1 - mb_row) * BH) + (17 - 2 * AOM_INTERP_EXTEND); - - for (mb_col = 0; mb_col < mb_cols; mb_col++) { - int j, k; - int stride; - MV best_ref_mv1 = kZeroMv; - - memset(accumulator, 0, BLK_PELS * 3 * sizeof(accumulator[0])); - memset(count, 0, BLK_PELS * 3 * sizeof(count[0])); - - cpi->td.mb.mv_limits.col_min = - -((mb_col * BW) + (17 - 2 * AOM_INTERP_EXTEND)); - cpi->td.mb.mv_limits.col_max = - ((mb_cols - 1 - mb_col) * BW) + (17 - 2 * AOM_INTERP_EXTEND); - - for (frame = 0; frame < frame_count; frame++) { - // MVs for 4 16x16 sub blocks. - MV blk_mvs[4]; - // Filter weights for 4 16x16 sub blocks. - int blk_fw[4] = { 0, 0, 0, 0 }; - int use_32x32 = 0; - + // Perform temporal filtering block by block. + for (int mb_row = 0; mb_row < mb_rows; mb_row++) { + av1_set_mv_row_limits(&cpi->common.mi_params, &mb->mv_limits, + (mb_row << mi_h), (mb_height >> MI_SIZE_LOG2), + cpi->oxcf.border_in_pixels); + for (int mb_col = 0; mb_col < mb_cols; mb_col++) { + av1_set_mv_col_limits(&cpi->common.mi_params, &mb->mv_limits, + (mb_col << mi_w), (mb_width >> MI_SIZE_LOG2), + cpi->oxcf.border_in_pixels); + memset(accum, 0, num_planes * mb_pels * sizeof(accum[0])); + memset(count, 0, num_planes * mb_pels * sizeof(count[0])); + MV ref_mv = kZeroMv; // Reference motion vector passed down along frames. + // Perform temporal filtering frame by frame. + for (int frame = 0; frame < num_frames; frame++) { if (frames[frame] == NULL) continue; - mbd->mi[0]->mv[0].as_mv.row = 0; - mbd->mi[0]->mv[0].as_mv.col = 0; - mbd->mi[0]->motion_mode = SIMPLE_TRANSLATION; - blk_mvs[0] = kZeroMv; - blk_mvs[1] = kZeroMv; - blk_mvs[2] = kZeroMv; - blk_mvs[3] = kZeroMv; + // Motion search. + MV subblock_mvs[4] = { kZeroMv, kZeroMv, kZeroMv, kZeroMv }; + int subblock_filter_weights[4] = { 0, 0, 0, 0 }; + int block_mse = INT_MAX; + int subblock_mses[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - if (frame == alt_ref_index) { - blk_fw[0] = blk_fw[1] = blk_fw[2] = blk_fw[3] = 2; - use_32x32 = 1; + if (frame == filter_frame_idx) { // Frame to be filtered. + // Set motion vector as 0 for the frame to be filtered. + mbd->mi[0]->mv[0].as_mv = kZeroMv; // Change ref_mv sign for following frames. - best_ref_mv1.row *= -1; - best_ref_mv1.col *= -1; - } else { - int thresh_low = 10000; - int thresh_high = 20000; - int blk_bestsme[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - - // 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_src_offset, - frames[frame]->y_buffer + mb_y_src_offset, - frames[frame]->y_stride, mb_col * BW, mb_row * BH, blk_mvs, - blk_bestsme, &best_ref_mv1, step_param); - - int err16 = - blk_bestsme[0] + blk_bestsme[1] + blk_bestsme[2] + blk_bestsme[3]; - int max_err = INT_MIN, min_err = INT_MAX; - for (k = 0; k < 4; k++) { - if (min_err > blk_bestsme[k]) min_err = blk_bestsme[k]; - if (max_err < blk_bestsme[k]) max_err = blk_bestsme[k]; + ref_mv.row *= -1; + ref_mv.col *= -1; + } else { // Other reference frames. + block_mse = tf_motion_search(cpi, frame_to_filter, frames[frame], + block_size, mb_row, mb_col, &ref_mv, + subblock_mvs, subblock_mses); + // Do not pass down the reference motion vector if error is too large. + const int thresh = AOMMIN(frame_height, frame_width) >= 720 ? 12 : 3; + if (block_mse > (thresh << (mbd->bd - 8))) { + ref_mv = kZeroMv; } - - if (((err * 15 < (err16 << 4)) && max_err - min_err < 12000) || - ((err * 14 < (err16 << 4)) && max_err - min_err < 6000)) { - use_32x32 = 1; - // Assign higher weight to matching MB if it's error - // score is lower. If not applying MC default behavior - // is to weight all MBs equal. - blk_fw[0] = err < (thresh_low << THR_SHIFT) - ? 2 - : err < (thresh_high << THR_SHIFT) ? 1 : 0; - blk_fw[1] = blk_fw[2] = blk_fw[3] = blk_fw[0]; - } else { - use_32x32 = 0; - for (k = 0; k < 4; k++) - blk_fw[k] = blk_bestsme[k] < thresh_low - ? 2 - : blk_bestsme[k] < thresh_high ? 1 : 0; - } - - // Don't use previous frame's mv result if error is large. - if (err > (3000 << bd_shift)) best_ref_mv1 = kZeroMv; } - 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_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, - num_planes, blk_mvs, use_32x32); + // Build predictor. + int use_subblock = tf_get_filter_weight( + block_mse, subblock_mses, is_second_arf, subblock_filter_weights); + tf_build_predictor(frames[frame], mbd, block_size, mb_row, mb_col, + num_planes, scale, use_subblock, subblock_mvs, pred); - // Apply the filter (YUV) - if (frame == alt_ref_index) { - uint8_t *pred = predictor; - uint32_t *accum = accumulator; - uint16_t *cnt = count; - int plane; - - // All 4 blk_fws are equal to 2. - for (plane = 0; plane < num_planes; ++plane) { - const int pred_stride = plane ? mb_uv_width : BW; - const unsigned int w = plane ? mb_uv_width : BW; - const unsigned int h = plane ? mb_uv_height : BH; - - if (is_hbd) { - highbd_apply_temporal_filter_self(pred, pred_stride, w, h, - blk_fw[0], accum, cnt, - use_new_temporal_mode); - } else { - apply_temporal_filter_self(pred, pred_stride, w, h, blk_fw[0], - accum, cnt, use_new_temporal_mode); - } - - pred += BLK_PELS; - accum += BLK_PELS; - cnt += BLK_PELS; - } - } else { - if (is_hbd) { -#if EXPERIMENT_TEMPORAL_FILTER - apply_temporal_filter_block( - f, mbd, mb_y_src_offset, mb_uv_src_offset, mb_uv_width, - mb_uv_height, num_planes, predictor, cm->height, strength, - sigma, blk_fw, use_32x32, accumulator, count, - use_new_temporal_mode); -#else - const int adj_strength = strength + 2 * (mbd->bd - 8); - if (num_planes <= 1) { - // Single plane case - av1_highbd_temporal_filter_apply_c( - 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. - 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)); - } -#endif // EXPERIMENT_TEMPORAL_FILTER - } else { -#if EXPERIMENT_TEMPORAL_FILTER - apply_temporal_filter_block( - f, mbd, mb_y_src_offset, mb_uv_src_offset, mb_uv_width, - mb_uv_height, num_planes, predictor, cm->height, strength, - sigma, blk_fw, use_32x32, accumulator, count, - use_new_temporal_mode); -#else - if (num_planes <= 1) { - // Single plane case - av1_temporal_filter_apply_c( - 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. - 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)); - } -#endif // EXPERIMENT_TEMPORAL_FILTER - } - } + // Perform weighted averaging. + if (frame == filter_frame_idx) { // Frame to be filtered. + av1_apply_temporal_filter_self(mbd, block_size, num_planes, + subblock_filter_weights[0], pred, + accum, count); + } else { // Other reference frames. + const FRAME_TYPE frame_type = + (cpi->common.current_frame.frame_number > 1) ? INTER_FRAME + : KEY_FRAME; + const int q_factor = + (int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[frame_type], + cpi->common.seq_params.bit_depth); + av1_apply_temporal_filter_others( + frame_to_filter, mbd, block_size, mb_row, mb_col, num_planes, + strength, use_subblock, subblock_filter_weights, noise_levels, + block_mse, subblock_mses, q_factor, pred, accum, count); } } - // Normalize filter output to produce AltRef frame - if (is_hbd) { - uint16_t *dst1_16; - uint16_t *dst2_16; - dst1 = cpi->alt_ref_buffer.y_buffer; - dst1_16 = CONVERT_TO_SHORTPTR(dst1); - stride = cpi->alt_ref_buffer.y_stride; - byte = mb_y_offset; - for (i = 0, k = 0; i < BH; i++) { - for (j = 0; j < BW; j++, k++) { - dst1_16[byte] = - (uint16_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]); + tf_normalize_filtered_frame(mbd, block_size, mb_row, mb_col, num_planes, + accum, count, &cpi->alt_ref_buffer); - // move to next pixel - byte++; - } - - byte += stride - BW; - } - if (num_planes > 1) { - dst1 = cpi->alt_ref_buffer.u_buffer; - dst2 = cpi->alt_ref_buffer.v_buffer; - dst1_16 = CONVERT_TO_SHORTPTR(dst1); - dst2_16 = CONVERT_TO_SHORTPTR(dst2); - stride = cpi->alt_ref_buffer.uv_stride; - byte = mb_uv_offset; - for (i = 0, k = BLK_PELS; i < mb_uv_height; i++) { - for (j = 0; j < mb_uv_width; j++, k++) { - int m = k + BLK_PELS; - // U - dst1_16[byte] = - (uint16_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]); - // V - dst2_16[byte] = - (uint16_t)OD_DIVU(accumulator[m] + (count[m] >> 1), count[m]); - // move to next pixel - byte++; - } - byte += stride - mb_uv_width; - } - } - } else { - dst1 = cpi->alt_ref_buffer.y_buffer; - stride = cpi->alt_ref_buffer.y_stride; - byte = mb_y_offset; - for (i = 0, k = 0; i < BH; i++) { - for (j = 0; j < BW; j++, k++) { - dst1[byte] = - (uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]); - - // move to next pixel - byte++; - } - byte += stride - BW; - } - if (num_planes > 1) { - dst1 = cpi->alt_ref_buffer.u_buffer; - dst2 = cpi->alt_ref_buffer.v_buffer; - stride = cpi->alt_ref_buffer.uv_stride; - byte = mb_uv_offset; - for (i = 0, k = BLK_PELS; i < mb_uv_height; i++) { - for (j = 0; j < mb_uv_width; j++, k++) { - int m = k + BLK_PELS; - // U - dst1[byte] = - (uint8_t)OD_DIVU(accumulator[k] + (count[k] >> 1), count[k]); - // V - dst2[byte] = - (uint8_t)OD_DIVU(accumulator[m] + (count[m] >> 1), count[m]); - // move to next pixel - byte++; - } - byte += stride - mb_uv_width; - } - } - } - - if (!is_key_frame && cpi->sf.adaptive_overlay_encoding) { - // Calculate the difference(dist) between source and filtered source. - dst1 = cpi->alt_ref_buffer.y_buffer + mb_y_offset; - stride = cpi->alt_ref_buffer.y_stride; - const uint8_t *src = f->y_buffer + mb_y_src_offset; - const int src_stride = f->y_stride; - const BLOCK_SIZE bsize = dims_to_size(BW, BH); + if (!is_key_frame && cpi->sf.hl_sf.adaptive_overlay_encoding) { + const int y_height = mb_height >> mbd->plane[0].subsampling_y; + const int y_width = mb_width >> mbd->plane[0].subsampling_x; + const int source_y_stride = frame_to_filter->y_stride; + const int filter_y_stride = cpi->alt_ref_buffer.y_stride; + const int source_offset = + mb_row * y_height * source_y_stride + mb_col * y_width; + const int filter_offset = + mb_row * y_height * filter_y_stride + mb_col * y_width; unsigned int sse = 0; - cpi->fn_ptr[bsize].vf(src, src_stride, dst1, stride, &sse); - + cpi->fn_ptr[block_size].vf(frame_to_filter->y_buffer + source_offset, + source_y_stride, + cpi->alt_ref_buffer.y_buffer + filter_offset, + filter_y_stride, &sse); diff.sum += sse; diff.sse += sse * sse; } - - 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 * 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 - for (i = 0; i < num_planes; i++) mbd->plane[i].pre[0].buf = input_buffer[i]; + for (int i = 0; i < num_planes; i++) { + mbd->plane[i].pre[0].buf = input_buffer[i]; + } + mbd->mi = input_mb_mode_info; + + free(tmp_mb_mode_info); + aom_free(pred8); + aom_free(pred16); + aom_free(accum); + aom_free(count); - mbd->mi = backup_mi_grid; return diff; } -// This is an adaptation of the mehtod in the following paper: -// Shen-Chuan Tai, Shih-Ming Yang, "A fast method for image noise -// estimation using Laplacian operator and adaptive edge detection," -// Proc. 3rd International Symposium on Communications, Control and -// Signal Processing, 2008, St Julians, Malta. -// -// Return noise estimate, or -1.0 if there was a failure -double estimate_noise(const uint8_t *src, int width, int height, int stride, - int edge_thresh) { - int64_t sum = 0; - int64_t num = 0; +// A constant number, sqrt(pi / 2), used for noise estimation. +static const double SQRT_PI_BY_2 = 1.25331413732; + +double av1_estimate_noise_from_single_plane(const YV12_BUFFER_CONFIG *frame, + const int plane, + const int bit_depth) { + const int is_y_plane = (plane == 0); + const int height = frame->crop_heights[is_y_plane ? 0 : 1]; + const int width = frame->crop_widths[is_y_plane ? 0 : 1]; + const int stride = frame->strides[is_y_plane ? 0 : 1]; + const uint8_t *src = frame->buffers[plane]; + const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); + const int is_high_bitdepth = is_frame_high_bitdepth(frame); + + int64_t accum = 0; + int count = 0; for (int i = 1; i < height - 1; ++i) { for (int j = 1; j < width - 1; ++j) { - const int k = i * stride + j; - // Sobel gradients - const int Gx = (src[k - stride - 1] - src[k - stride + 1]) + - (src[k + stride - 1] - src[k + stride + 1]) + - 2 * (src[k - 1] - src[k + 1]); - const int Gy = (src[k - stride - 1] - src[k + stride - 1]) + - (src[k - stride + 1] - src[k + stride + 1]) + - 2 * (src[k - stride] - src[k + stride]); - const int Ga = abs(Gx) + abs(Gy); - if (Ga < edge_thresh) { // Smooth pixels - // Find Laplacian - const int v = - 4 * src[k] - - 2 * (src[k - 1] + src[k + 1] + src[k - stride] + src[k + stride]) + - (src[k - stride - 1] + src[k - stride + 1] + src[k + stride - 1] + - src[k + stride + 1]); - sum += abs(v); - ++num; + // Setup a small 3x3 matrix. + const int center_idx = i * stride + j; + int mat[3][3]; + for (int ii = -1; ii <= 1; ++ii) { + for (int jj = -1; jj <= 1; ++jj) { + const int idx = center_idx + ii * stride + jj; + mat[ii + 1][jj + 1] = is_high_bitdepth ? src16[idx] : src[idx]; + } + } + // Compute sobel gradients. + const int Gx = (mat[0][0] - mat[0][2]) + (mat[2][0] - mat[2][2]) + + 2 * (mat[1][0] - mat[1][2]); + const int Gy = (mat[0][0] - mat[2][0]) + (mat[0][2] - mat[2][2]) + + 2 * (mat[0][1] - mat[2][1]); + const int Ga = ROUND_POWER_OF_TWO(abs(Gx) + abs(Gy), bit_depth - 8); + // Accumulate Laplacian. + if (Ga < NOISE_ESTIMATION_EDGE_THRESHOLD) { // Only count smooth pixels. + const int v = 4 * mat[1][1] - + 2 * (mat[0][1] + mat[2][1] + mat[1][0] + mat[1][2]) + + (mat[0][0] + mat[0][2] + mat[2][0] + mat[2][2]); + accum += ROUND_POWER_OF_TWO(abs(v), bit_depth - 8); + ++count; } } } - // If very few smooth pels, return -1 since the estimate is unreliable - if (num < 16) return -1.0; - const double sigma = (double)sum / (6 * num) * SQRT_PI_BY_2; - return sigma; + // Return -1.0 (unreliable estimation) if there are too few smooth pixels. + return (count < 16) ? -1.0 : (double)accum / (6 * count) * SQRT_PI_BY_2; } -// Return noise estimate, or -1.0 if there was a failure -double highbd_estimate_noise(const uint8_t *src8, int width, int height, - int stride, int bd, int edge_thresh) { - uint16_t *src = CONVERT_TO_SHORTPTR(src8); - int64_t sum = 0; - int64_t num = 0; - for (int i = 1; i < height - 1; ++i) { - for (int j = 1; j < width - 1; ++j) { - const int k = i * stride + j; - // Sobel gradients - const int Gx = (src[k - stride - 1] - src[k - stride + 1]) + - (src[k + stride - 1] - src[k + stride + 1]) + - 2 * (src[k - 1] - src[k + 1]); - const int Gy = (src[k - stride - 1] - src[k + stride - 1]) + - (src[k - stride + 1] - src[k + stride + 1]) + - 2 * (src[k - stride] - src[k + stride]); - const int Ga = ROUND_POWER_OF_TWO(abs(Gx) + abs(Gy), bd - 8); - if (Ga < edge_thresh) { // Smooth pixels - // Find Laplacian - const int v = - 4 * src[k] - - 2 * (src[k - 1] + src[k + 1] + src[k - stride] + src[k + stride]) + - (src[k - stride - 1] + src[k - stride + 1] + src[k + stride - 1] + - src[k + stride + 1]); - sum += ROUND_POWER_OF_TWO(abs(v), bd - 8); - ++num; - } +// Estimates the strength for filter weight adjustment, which is used in YUV +// strategy. This estimation is based on the pre-estimated noise level of the +// to-filter frame. +// Inputs: +// cpi: Pointer to the composed information of input video. +// noise_level: Noise level of the to-filter frame, estimated with Y-plane. +// group_boost: Boost level for the current group of frames. +// Returns: +// Estimated strength which will be used for filter weight adjustment. +static int tf_estimate_strength(const AV1_COMP *cpi, const double noise_level, + const int group_boost) { + int strength = cpi->oxcf.arnr_strength; + + // Adjust the strength based on the estimated noise level. + if (noise_level > 0) { // Adjust when the noise level is reliable. + if (noise_level < 0.75) { // Noise level lies in range (0, 0.75). + strength = strength - 2; + } else if (noise_level < 1.75) { // Noise level lies in range [0.75, 1.75). + strength = strength - 1; + } else if (noise_level < 4.0) { // Noise level lies in range [1.75, 4.0). + strength = strength + 0; + } else { // Noise level lies in range [4.0, +inf). + strength = strength + 1; } } - // If very few smooth pels, return -1 since the estimate is unreliable - if (num < 16) return -1.0; - const double sigma = (double)sum / (6 * num) * SQRT_PI_BY_2; - return sigma; -} - -static int estimate_strength(AV1_COMP *cpi, int distance, int group_boost, - double *sigma) { // Adjust the strength based on active max q. - int q; - if (cpi->common.current_frame.frame_number > 1) - q = ((int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[INTER_FRAME], - cpi->common.seq_params.bit_depth)); - else - q = ((int)av1_convert_qindex_to_q(cpi->rc.avg_frame_qindex[KEY_FRAME], - cpi->common.seq_params.bit_depth)); - MACROBLOCKD *mbd = &cpi->td.mb.e_mbd; - struct lookahead_entry *buf = av1_lookahead_peek(cpi->lookahead, distance); - int strength; - double noiselevel; - if (is_cur_buf_hbd(mbd)) { - noiselevel = highbd_estimate_noise( - buf->img.y_buffer, buf->img.y_crop_width, buf->img.y_crop_height, - buf->img.y_stride, mbd->bd, EDGE_THRESHOLD); - *sigma = noiselevel; - } else { - noiselevel = estimate_noise(buf->img.y_buffer, buf->img.y_crop_width, - buf->img.y_crop_height, buf->img.y_stride, - EDGE_THRESHOLD); - *sigma = noiselevel; - } - int adj_strength = cpi->oxcf.arnr_strength; - if (noiselevel > 0) { - // Get 4 integer adjustment levels in [-2, 1] - int noiselevel_adj; - if (noiselevel < 0.75) - noiselevel_adj = -2; - else if (noiselevel < 1.75) - noiselevel_adj = -1; - else if (noiselevel < 4.0) - noiselevel_adj = 0; - else - noiselevel_adj = 1; - adj_strength += noiselevel_adj; - } - // printf("[noise level: %g, strength = %d]\n", noiselevel, adj_strength); + const FRAME_TYPE frame_type = + (cpi->common.current_frame.frame_number > 1) ? INTER_FRAME : KEY_FRAME; + const int q = (int)av1_convert_qindex_to_q( + cpi->rc.avg_frame_qindex[frame_type], cpi->common.seq_params.bit_depth); + strength = strength - AOMMAX(0, (16 - q) / 2); - if (q > 16) { - strength = adj_strength; - } else { - strength = adj_strength - ((16 - q) / 2); - if (strength < 0) strength = 0; - } - - if (strength > group_boost / 300) { - strength = group_boost / 300; - } - - return strength; + return CLIP(strength, 0, group_boost / 300); } -// Apply buffer limits and context specific adjustments to arnr filter. -static void adjust_arnr_filter(AV1_COMP *cpi, int distance, int group_boost, - int *arnr_frames, int *arnr_strength, - double *sigma, int *frm_bwd, int *frm_fwd) { - int frames = cpi->oxcf.arnr_max_frames; +// Setups the frame buffer for temporal filtering. Basically, this fuction +// determines how many frames will be used for temporal filtering and then +// groups them into a buffer. +// Inputs: +// cpi: Pointer to the composed information of input video. +// filter_frame_lookahead_idx: The index of the to-filter frame in the +// lookahead buffer `cpi->lookahead`. +// is_second_arf: Whether the to-filter frame is the second ARF. This field +// will affect the number of frames used for filtering. +// frames: Pointer to the frame buffer to setup. +// num_frames_for_filtering: Number of frames used for filtering. +// filter_frame_idx: Index of the to-filter frame in the setup frame buffer. +// Returns: +// Nothing will be returned. But the frame buffer `frames`, number of frames +// in the buffer `num_frames_for_filtering`, and the index of the to-filter +// frame in the buffer `filter_frame_idx` will be updated in this function. +static void tf_setup_filtering_buffer(const AV1_COMP *cpi, + const int filter_frame_lookahead_idx, + const int is_second_arf, + YV12_BUFFER_CONFIG **frames, + int *num_frames_for_filtering, + int *filter_frame_idx) { + int num_frames = 0; // Number of frames used for filtering. + int num_frames_before = -1; // Number of frames before the to-filter frame. + int filter_frame_offset; - // Adjust number of frames in filter and strength based on gf boost level. - if (frames > group_boost / 150) { - frames = group_boost / 150; - frames += !(frames & 1); + if (filter_frame_lookahead_idx == -1) { // Key frame. + num_frames = TF_NUM_FILTERING_FRAMES_FOR_KEY_FRAME; + num_frames_before = 0; + filter_frame_offset = filter_frame_lookahead_idx; + } else if (filter_frame_lookahead_idx < -1) { // Key frame in one-pass mode. + num_frames = TF_NUM_FILTERING_FRAMES_FOR_KEY_FRAME; + num_frames_before = num_frames - 1; + filter_frame_offset = -filter_frame_lookahead_idx; + } else { + num_frames = cpi->oxcf.arnr_max_frames; + if (is_second_arf) { // Only use 2 neighbours for the second ARF. + num_frames = AOMMIN(num_frames, 3); + } + if (num_frames > cpi->rc.gfu_boost / 150) { + num_frames = cpi->rc.gfu_boost / 150; + num_frames += !(num_frames & 1); + } + num_frames_before = AOMMIN(num_frames >> 1, filter_frame_lookahead_idx + 1); + const int lookahead_depth = + av1_lookahead_depth(cpi->lookahead, cpi->compressor_stage); + const int num_frames_after = + AOMMIN((num_frames - 1) >> 1, + lookahead_depth - filter_frame_lookahead_idx - 1); + num_frames = num_frames_before + 1 + num_frames_after; + filter_frame_offset = filter_frame_lookahead_idx; } + *num_frames_for_filtering = num_frames; + *filter_frame_idx = num_frames_before; - const int frames_after_arf = - av1_lookahead_depth(cpi->lookahead) - distance - 1; - int frames_fwd = (frames - 1) >> 1; - int frames_bwd = frames >> 1; - - // Define the forward and backwards filter limits for this arnr group. - if (frames_fwd > frames_after_arf) frames_fwd = frames_after_arf; - if (frames_bwd > distance) frames_bwd = distance; - - // Set the baseline active filter size. - frames = frames_bwd + 1 + frames_fwd; - - *arnr_frames = frames; - *arnr_strength = estimate_strength(cpi, distance, group_boost, sigma); - *frm_bwd = frames_bwd; - *frm_fwd = frames_fwd; + // Setup the frame buffer. + for (int frame = 0; frame < num_frames; ++frame) { + const int lookahead_idx = frame - num_frames_before + filter_frame_offset; + struct lookahead_entry *buf = av1_lookahead_peek( + cpi->lookahead, lookahead_idx, cpi->compressor_stage); + frames[frame] = (buf == NULL) ? NULL : &buf->img; + } } -int av1_temporal_filter(AV1_COMP *cpi, int distance, - int *show_existing_alt_ref) { - RATE_CONTROL *const rc = &cpi->rc; - int frame; - int frames_to_blur; - int start_frame; - int strength; - int frames_to_blur_backward; - int frames_to_blur_forward; - struct scale_factors sf; - - YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = { NULL }; +int av1_temporal_filter(AV1_COMP *cpi, const int filter_frame_lookahead_idx, + int *show_existing_arf) { + // Basic informaton of the current frame. const GF_GROUP *const gf_group = &cpi->gf_group; - int rdmult = 0; - double sigma = 0; + const uint8_t group_idx = gf_group->index; + const FRAME_UPDATE_TYPE update_type = gf_group->update_type[group_idx]; + // Filter one more ARF if the lookahead index is leq 7 (w.r.t. 9-th frame). + // This frame is ALWAYS a show existing frame. + const int is_second_arf = (update_type == INTNL_ARF_UPDATE) && + (filter_frame_lookahead_idx >= 7) && + cpi->sf.hl_sf.second_alt_ref_filtering; + // TODO(anyone): Currently, we enforce the filtering strength on internal + // ARFs except the second ARF to be zero. We should investigate in which case + // it is more beneficial to use non-zero strength filtering. + if (update_type == INTNL_ARF_UPDATE && !is_second_arf) { + return 0; + } // TODO(yunqing): For INTNL_ARF_UPDATE type, the following me initialization // is used somewhere unexpectedly. Should be resolved later. // Initialize errorperbit, sadperbit16 and sadperbit4. - rdmult = av1_compute_rd_mult_based_on_qindex(cpi, ARNR_FILT_QINDEX); + const int rdmult = av1_compute_rd_mult_based_on_qindex(cpi, TF_QINDEX); set_error_per_bit(&cpi->td.mb, rdmult); - av1_initialize_me_consts(cpi, &cpi->td.mb, ARNR_FILT_QINDEX); - av1_fill_mv_costs(cpi->common.fc, cpi->common.cur_frame_force_integer_mv, - cpi->common.allow_high_precision_mv, &cpi->td.mb); + av1_initialize_me_consts(cpi, &cpi->td.mb, TF_QINDEX); + av1_fill_mv_costs(cpi->common.fc, + cpi->common.features.cur_frame_force_integer_mv, + cpi->common.features.allow_high_precision_mv, &cpi->td.mb); - // 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 - // 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; - return 0; + // Setup frame buffer for filtering. + YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS] = { NULL }; + int num_frames_for_filtering = 0; + int filter_frame_idx = -1; + tf_setup_filtering_buffer(cpi, filter_frame_lookahead_idx, is_second_arf, + frames, &num_frames_for_filtering, + &filter_frame_idx); + + // Estimate noise and strength. + const int bit_depth = cpi->common.seq_params.bit_depth; + const int num_planes = av1_num_planes(&cpi->common); + double noise_levels[MAX_MB_PLANE] = { 0 }; + for (int plane = 0; plane < num_planes; ++plane) { + noise_levels[plane] = av1_estimate_noise_from_single_plane( + frames[filter_frame_idx], plane, bit_depth); + } + const int strength = + tf_estimate_strength(cpi, noise_levels[0], cpi->rc.gfu_boost); + if (filter_frame_lookahead_idx >= 0) { + cpi->common.showable_frame = + (strength == 0 && num_frames_for_filtering == 1) || is_second_arf || + (cpi->oxcf.enable_overlay == 0 || cpi->sf.hl_sf.disable_overlay_frames); } - if (distance == -1) { - // Apply temporal filtering on key frame. - strength = estimate_strength(cpi, distance, rc->gfu_boost, &sigma); - // Number of frames for temporal filtering, could be tuned. - frames_to_blur = NUM_KEY_FRAME_DENOISING; - frames_to_blur_backward = 0; - frames_to_blur_forward = frames_to_blur - 1; - start_frame = distance + frames_to_blur_forward; - } else { - adjust_arnr_filter(cpi, distance, rc->gfu_boost, &frames_to_blur, &strength, - &sigma, &frames_to_blur_backward, - &frames_to_blur_forward); - start_frame = distance + frames_to_blur_forward; - } - - cpi->common.showable_frame = - (strength == 0 && frames_to_blur == 1) || - (cpi->oxcf.enable_overlay == 0 || cpi->sf.disable_overlay_frames); - - // Setup frame pointers, NULL indicates frame not included in filter. - for (frame = 0; frame < frames_to_blur; ++frame) { - const int which_buffer = start_frame - frame; - struct lookahead_entry *buf = - av1_lookahead_peek(cpi->lookahead, which_buffer); - if (buf == NULL) { - frames[frames_to_blur - 1 - frame] = NULL; - } else { - frames[frames_to_blur - 1 - frame] = &buf->img; - } - } - - if (frames_to_blur > 0 && frames[0] != NULL) { + // Do filtering. + const int is_key_frame = (filter_frame_lookahead_idx < 0); + FRAME_DIFF diff = { 0, 0 }; + if (num_frames_for_filtering > 0 && frames[0] != NULL) { // Setup scaling factors. Scaling on each of the arnr frames is not // supported. // ARF is produced at the native frame size and resized when coded. + struct scale_factors sf; av1_setup_scale_factors_for_frame( &sf, frames[0]->y_crop_width, frames[0]->y_crop_height, frames[0]->y_crop_width, frames[0]->y_crop_height); + diff = tf_do_filtering(cpi, frames, num_frames_for_filtering, + filter_frame_idx, is_key_frame, is_second_arf, + TF_BLOCK_SIZE, &sf, strength, noise_levels); } - FRAME_DIFF diff = temporal_filter_iterate_c(cpi, frames, frames_to_blur, - frames_to_blur_backward, strength, - sigma, distance == -1, &sf); + if (is_key_frame) { // Key frame should always be filtered. + return 1; + } - if (distance == -1) return 1; - - if (show_existing_alt_ref != NULL && cpi->sf.adaptive_overlay_encoding) { - AV1_COMMON *const cm = &cpi->common; - int top_index = 0, bottom_index = 0; + if ((show_existing_arf != NULL && cpi->sf.hl_sf.adaptive_overlay_encoding) || + is_second_arf) { + const int frame_height = frames[filter_frame_idx]->y_crop_height; + const int frame_width = frames[filter_frame_idx]->y_crop_width; + const int block_height = block_size_high[TF_BLOCK_SIZE]; + const int block_width = block_size_wide[TF_BLOCK_SIZE]; + const int mb_rows = get_num_blocks(frame_height, block_height); + const int mb_cols = get_num_blocks(frame_width, block_width); + const int num_mbs = AOMMAX(1, mb_rows * mb_cols); + const float mean = (float)diff.sum / num_mbs; + const float std = (float)sqrt((float)diff.sse / num_mbs - mean * mean); aom_clear_system_state(); // TODO(yunqing): This can be combined with TPL q calculation later. - cpi->rc.base_frame_target = gf_group->bit_allocation[gf_group->index]; - av1_set_target_rate(cpi, cm->width, cm->height); + cpi->rc.base_frame_target = gf_group->bit_allocation[group_idx]; + av1_set_target_rate(cpi, cpi->common.width, cpi->common.height); + int top_index = 0; + int bottom_index = 0; const int q = av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cpi->oxcf.width, - cpi->oxcf.height, gf_group->index, + cpi->oxcf.height, group_idx, &bottom_index, &top_index); - const int ac_q = av1_ac_quant_QTX(q, 0, cm->seq_params.bit_depth); - const int ac_q_2 = ac_q * ac_q; - const int mb_cols = get_cols(frames[frames_to_blur_backward]->y_crop_width); - const int mb_rows = - get_rows(frames[frames_to_blur_backward]->y_crop_height); - const int mbs = AOMMAX(1, mb_rows * mb_cols); - const float mean = (float)diff.sum / mbs; - const float std = (float)sqrt((float)diff.sse / mbs - mean * mean); - const float threshold = 0.7f; + const int ac_q = av1_ac_quant_QTX(q, 0, bit_depth); + const float threshold = 0.7f * ac_q * ac_q; - *show_existing_alt_ref = 0; - if (mean / ac_q_2 < threshold && std < mean * 1.2) - *show_existing_alt_ref = 1; - cpi->common.showable_frame |= *show_existing_alt_ref; + if (!is_second_arf) { + *show_existing_arf = 0; + if (mean < threshold && std < mean * 1.2) { + *show_existing_arf = 1; + } + cpi->common.showable_frame |= *show_existing_arf; + } else { + // Use source frame if the filtered frame becomes very different. + if (!(mean < threshold && std < mean * 1.2)) { + return 0; + } + } } return 1; diff --git a/media/libaom/src/av1/encoder/temporal_filter.h b/media/libaom/src/av1/encoder/temporal_filter.h index 2df266657d..5a6bde2594 100644 --- a/media/libaom/src/av1/encoder/temporal_filter.h +++ b/media/libaom/src/av1/encoder/temporal_filter.h @@ -16,43 +16,69 @@ extern "C" { #endif -#define ARNR_FILT_QINDEX 128 - -// Block size used in temporal filtering -#define TF_BLOCK BLOCK_32X32 +// TODO(any): These two variables are only used in avx2, sse2, sse4 +// implementations, where the block size is still hard coded. This should be +// fixed to align with the c implementation. #define BH 32 -#define BH_LOG2 5 #define BW 32 -#define BW_LOG2 5 -#define BLK_PELS 1024 // Pixels in the block -#define THR_SHIFT 2 -#define TF_SUB_BLOCK BLOCK_16X16 -#define SUB_BH 16 -#define SUB_BW 16 -#define NUM_KEY_FRAME_DENOISING 7 -#define EDGE_THRESHOLD 50 -#define SQRT_PI_BY_2 1.25331413732 +// Block size used in temporal filtering. +#define TF_BLOCK_SIZE BLOCK_32X32 -static INLINE BLOCK_SIZE dims_to_size(int w, int h) { - if (w != h) return -1; - switch (w) { - case 4: return BLOCK_4X4; - case 8: return BLOCK_8X8; - case 16: return BLOCK_16X16; - case 32: return BLOCK_32X32; - case 64: return BLOCK_64X64; - case 128: return BLOCK_128X128; - default: assert(0); return -1; - } -} +// Window size for YUV temporal filtering. +// This is particually used for function `av1_apply_temporal_filter_yuv()`. +#define TF_YUV_FILTER_WINDOW_LENGTH 3 +// A scale factor used in YUV temporal filtering for weight adjustment. +#define TF_YUV_FILTER_WEIGHT_SCALE 3 -int av1_temporal_filter(AV1_COMP *cpi, int distance, - int *show_existing_alt_ref); -double estimate_noise(const uint8_t *src, int width, int height, int stride, - int edge_thresh); -double highbd_estimate_noise(const uint8_t *src8, int width, int height, - int stride, int bd, int edge_thresh); +#define TF_ENABLE_PLANEWISE_STRATEGY 1 +// Window size for plane-wise temporal filtering. +// This is particually used for function `av1_apply_temporal_filter_planewise()` +#define TF_PLANEWISE_FILTER_WINDOW_LENGTH 5 +// A scale factor used in plane-wise temporal filtering to raise the filter +// weight from `double` with range [0, 1] to `int` with range [0, 1000]. +#define TF_PLANEWISE_FILTER_WEIGHT_SCALE 1000 + +#define NOISE_ESTIMATION_EDGE_THRESHOLD 50 +// Estimates noise level from a given frame using a single plane (Y, U, or V). +// This is an adaptation of the mehtod in the following paper: +// Shen-Chuan Tai, Shih-Ming Yang, "A fast method for image noise +// estimation using Laplacian operator and adaptive edge detection", +// Proc. 3rd International Symposium on Communications, Control and +// Signal Processing, 2008, St Julians, Malta. +// Inputs: +// frame: Pointer to the frame to estimate noise level from. +// plane: Index of the plane used for noise estimation. Commonly, 0 for +// Y-plane, 1 for U-plane, and 2 for V-plane. +// bit_depth: Actual bit-depth instead of the encoding bit-depth of the frame. +// Returns: +// The estimated noise, or -1.0 if there are too few smooth pixels. +double av1_estimate_noise_from_single_plane(const YV12_BUFFER_CONFIG *frame, + const int plane, + const int bit_depth); + +#define TF_QINDEX 128 // Q-index used in temporal filtering. +#define TF_NUM_FILTERING_FRAMES_FOR_KEY_FRAME 7 +// Performs temporal filtering if needed. +// NOTE: In this function, the lookahead index is different from the 0-based +// real index. For example, if we want to filter the first frame in the +// pre-fetched buffer `cpi->lookahead`, the lookahead index will be -1 instead +// of 0. More concretely, 0 indicates the first LOOKAHEAD frame, which is the +// second frame in the pre-fetched buffer. Another example: if we want to filter +// the 17-th frame, which is an ARF, the lookahead index is 15 instead of 16. +// Futhermore, negative number is used for key frame in one-pass mode, where key +// frame is filtered with the frames before it instead of after it. For example, +// -15 means to filter the 17-th frame, which is a key frame in one-pass mode. +// Inputs: +// cpi: Pointer to the composed information of input video. +// filter_frame_lookahead_idx: The index of the to-filter frame in the +// lookahead buffer `cpi->lookahead`. +// show_existing_arf: Whether to show existing ARF. This field will be updated +// in this function. +// Returns: +// Whether temporal filtering is successfully done. +int av1_temporal_filter(AV1_COMP *cpi, const int filter_frame_lookahead_idx, + int *show_existing_arf); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/encoder/tokenize.c b/media/libaom/src/av1/encoder/tokenize.c index 9fdd47b4de..e67415349e 100644 --- a/media/libaom/src/av1/encoder/tokenize.c +++ b/media/libaom/src/av1/encoder/tokenize.c @@ -130,7 +130,7 @@ void av1_tokenize_color_map(const MACROBLOCK *const x, int plane, counts, map_pb_cdf); } -static void tokenize_vartx(ThreadData *td, RUN_TYPE dry_run, TX_SIZE tx_size, +static void tokenize_vartx(ThreadData *td, TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int blk_row, int blk_col, int block, int plane, void *arg) { MACROBLOCK *const x = &td->mb; @@ -151,16 +151,9 @@ static void tokenize_vartx(ThreadData *td, RUN_TYPE dry_run, TX_SIZE tx_size, if (tx_size == plane_tx_size || plane) { plane_bsize = get_plane_block_size(mbmi->sb_type, pd->subsampling_x, pd->subsampling_y); - if (!dry_run) { - av1_update_and_record_txb_context(plane, block, blk_row, blk_col, - plane_bsize, tx_size, arg); - } else if (dry_run == DRY_RUN_NORMAL) { - av1_update_txb_context_b(plane, block, blk_row, blk_col, plane_bsize, - tx_size, arg); - } else { - printf("DRY_RUN_COSTCOEFFS is not supported yet\n"); - assert(0); - } + av1_update_and_record_txb_context(plane, block, blk_row, blk_col, + plane_bsize, tx_size, arg); + } else { // Half the block size in transform block unit. const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; @@ -177,8 +170,8 @@ static void tokenize_vartx(ThreadData *td, RUN_TYPE dry_run, TX_SIZE tx_size, if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; - tokenize_vartx(td, dry_run, sub_txs, plane_bsize, offsetr, offsetc, - block, plane, arg); + tokenize_vartx(td, sub_txs, plane_bsize, offsetr, offsetc, block, plane, + arg); block += step; } } @@ -186,65 +179,59 @@ static void tokenize_vartx(ThreadData *td, RUN_TYPE dry_run, TX_SIZE tx_size, } void av1_tokenize_sb_vartx(const AV1_COMP *cpi, ThreadData *td, - RUN_TYPE dry_run, int mi_row, int mi_col, - BLOCK_SIZE bsize, int *rate, + RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate, uint8_t allow_update_cdf) { + assert(bsize < BLOCK_SIZES_ALL); const AV1_COMMON *const cm = &cpi->common; - const int num_planes = av1_num_planes(cm); MACROBLOCK *const x = &td->mb; MACROBLOCKD *const xd = &x->e_mbd; - MB_MODE_INFO *const mbmi = xd->mi[0]; - struct tokenize_b_args arg = { cpi, td, 0, allow_update_cdf }; - if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + if (mi_row >= cm->mi_params.mi_rows || mi_col >= cm->mi_params.mi_cols) + return; - assert(bsize < BLOCK_SIZES_ALL); + const int num_planes = av1_num_planes(cm); + MB_MODE_INFO *const mbmi = xd->mi[0]; + struct tokenize_b_args arg = { cpi, td, 0, allow_update_cdf, dry_run }; if (mbmi->skip) { - av1_reset_skip_context(xd, mi_row, mi_col, bsize, num_planes); + av1_reset_entropy_context(xd, bsize, num_planes); return; } for (int plane = 0; plane < num_planes; ++plane) { - if (!is_chroma_reference(mi_row, mi_col, bsize, - xd->plane[plane].subsampling_x, - xd->plane[plane].subsampling_y)) { - continue; - } + if (plane && !xd->is_chroma_ref) break; const struct macroblockd_plane *const pd = &xd->plane[plane]; - const BLOCK_SIZE bsizec = - scale_chroma_bsize(bsize, pd->subsampling_x, pd->subsampling_y); - const BLOCK_SIZE plane_bsize = - get_plane_block_size(bsizec, pd->subsampling_x, pd->subsampling_y); + const int ss_x = pd->subsampling_x; + const int ss_y = pd->subsampling_y; + const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, ss_x, ss_y); assert(plane_bsize < BLOCK_SIZES_ALL); - const int mi_width = block_size_wide[plane_bsize] >> tx_size_wide_log2[0]; - const int mi_height = block_size_high[plane_bsize] >> tx_size_high_log2[0]; + const int mi_width = mi_size_wide[plane_bsize]; + const int mi_height = mi_size_high[plane_bsize]; const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, plane_bsize, plane); const BLOCK_SIZE txb_size = txsize_to_bsize[max_tx_size]; - int bw = block_size_wide[txb_size] >> tx_size_wide_log2[0]; - int bh = block_size_high[txb_size] >> tx_size_high_log2[0]; - int idx, idy; + const int bw = mi_size_wide[txb_size]; + const int bh = mi_size_high[txb_size]; int block = 0; - int step = tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; + const int step = + tx_size_wide_unit[max_tx_size] * tx_size_high_unit[max_tx_size]; const BLOCK_SIZE max_unit_bsize = - get_plane_block_size(BLOCK_64X64, pd->subsampling_x, pd->subsampling_y); - int mu_blocks_wide = - block_size_wide[max_unit_bsize] >> tx_size_wide_log2[0]; - int mu_blocks_high = - block_size_high[max_unit_bsize] >> tx_size_high_log2[0]; + get_plane_block_size(BLOCK_64X64, ss_x, ss_y); + int mu_blocks_wide = mi_size_wide[max_unit_bsize]; + int mu_blocks_high = mi_size_high[max_unit_bsize]; mu_blocks_wide = AOMMIN(mi_width, mu_blocks_wide); mu_blocks_high = AOMMIN(mi_height, mu_blocks_high); - for (idy = 0; idy < mi_height; idy += mu_blocks_high) { - for (idx = 0; idx < mi_width; idx += mu_blocks_wide) { - int blk_row, blk_col; + for (int idy = 0; idy < mi_height; idy += mu_blocks_high) { + for (int idx = 0; idx < mi_width; idx += mu_blocks_wide) { const int unit_height = AOMMIN(mu_blocks_high + idy, mi_height); const int unit_width = AOMMIN(mu_blocks_wide + idx, mi_width); - for (blk_row = idy; blk_row < unit_height; blk_row += bh) { - for (blk_col = idx; blk_col < unit_width; blk_col += bw) { - tokenize_vartx(td, dry_run, max_tx_size, plane_bsize, blk_row, - blk_col, block, plane, &arg); + for (int blk_row = idy; blk_row < unit_height; blk_row += bh) { + for (int blk_col = idx; blk_col < unit_width; blk_col += bw) { + tokenize_vartx(td, max_tx_size, plane_bsize, blk_row, blk_col, + block, plane, &arg); block += step; } } diff --git a/media/libaom/src/av1/encoder/tokenize.h b/media/libaom/src/av1/encoder/tokenize.h index 28334acea3..52caacbaee 100644 --- a/media/libaom/src/av1/encoder/tokenize.h +++ b/media/libaom/src/av1/encoder/tokenize.h @@ -22,7 +22,6 @@ extern "C" { typedef struct { aom_cdf_prob *color_map_cdf; - // TODO(yaowu: use packed enum type if appropriate) uint8_t token; } TOKENEXTRA; @@ -30,25 +29,25 @@ struct AV1_COMP; struct ThreadData; struct FRAME_COUNTS; -struct tokenize_b_args { - const struct AV1_COMP *cpi; - struct ThreadData *td; - int this_rate; - uint8_t allow_update_cdf; -}; - enum { OUTPUT_ENABLED = 0, DRY_RUN_NORMAL, DRY_RUN_COSTCOEFFS, } UENUM1BYTE(RUN_TYPE); +struct tokenize_b_args { + const struct AV1_COMP *cpi; + struct ThreadData *td; + int this_rate; + uint8_t allow_update_cdf; + RUN_TYPE dry_run; +}; + // Note in all the tokenize functions rate if non NULL is incremented // with the coefficient token cost only if dry_run = DRY_RUN_COSTCOEFS, // otherwise rate is not incremented. void av1_tokenize_sb_vartx(const struct AV1_COMP *cpi, struct ThreadData *td, - RUN_TYPE dry_run, int mi_row, int mi_col, - BLOCK_SIZE bsize, int *rate, + RUN_TYPE dry_run, BLOCK_SIZE bsize, int *rate, uint8_t allow_update_cdf); int av1_cost_color_map(const MACROBLOCK *const x, int plane, BLOCK_SIZE bsize, diff --git a/media/libaom/src/av1/encoder/tpl_model.c b/media/libaom/src/av1/encoder/tpl_model.c index 6f342c79ee..79b94f3739 100644 --- a/media/libaom/src/av1/encoder/tpl_model.c +++ b/media/libaom/src/av1/encoder/tpl_model.c @@ -19,9 +19,9 @@ #include "aom/aom_codec.h" #include "aom_ports/system_state.h" +#include "av1/common/av1_common_int.h" #include "av1/common/enums.h" #include "av1/common/idct.h" -#include "av1/common/onyxc_int.h" #include "av1/common/reconintra.h" #include "av1/encoder/encoder.h" @@ -31,8 +31,9 @@ #include "av1/encoder/reconinter_enc.h" #include "av1/encoder/tpl_model.h" -static AOM_INLINE void get_quantize_error(MACROBLOCK *x, int plane, - tran_low_t *coeff, tran_low_t *qcoeff, +static AOM_INLINE void get_quantize_error(const MACROBLOCK *x, int plane, + const tran_low_t *coeff, + tran_low_t *qcoeff, tran_low_t *dqcoeff, TX_SIZE tx_size, uint16_t *eob, int64_t *recon_error, int64_t *sse) { @@ -52,7 +53,7 @@ static AOM_INLINE void get_quantize_error(MACROBLOCK *x, int plane, *sse = AOMMAX(*sse, 1); } -static AOM_INLINE void wht_fwd_txfm(int16_t *src_diff, int bw, +static AOM_INLINE void tpl_fwd_txfm(const int16_t *src_diff, int bw, tran_low_t *coeff, TX_SIZE tx_size, int bit_depth, int is_hbd) { TxfmParam txfm_param; @@ -66,7 +67,22 @@ static AOM_INLINE void wht_fwd_txfm(int16_t *src_diff, int bw, av1_fwd_txfm(src_diff, coeff, bw, &txfm_param); } -static int rate_estimator(tran_low_t *qcoeff, int eob, TX_SIZE tx_size) { +static AOM_INLINE int64_t tpl_get_satd_cost(const MACROBLOCK *x, + int16_t *src_diff, int diff_stride, + const uint8_t *src, int src_stride, + const uint8_t *dst, int dst_stride, + tran_low_t *coeff, int bw, int bh, + TX_SIZE tx_size) { + const MACROBLOCKD *xd = &x->e_mbd; + const int pix_num = bw * bh; + + av1_subtract_block(xd, bh, bw, src_diff, diff_stride, src, src_stride, dst, + dst_stride); + tpl_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, is_cur_buf_hbd(xd)); + return aom_satd(coeff, pix_num); +} + +static int rate_estimator(const tran_low_t *qcoeff, int eob, TX_SIZE tx_size) { const SCAN_ORDER *const scan_order = &av1_default_scan_orders[tx_size]; assert((1 << num_pels_log2_lookup[txsize_to_bsize[tx_size]]) >= eob); @@ -81,29 +97,41 @@ static int rate_estimator(tran_low_t *qcoeff, int eob, TX_SIZE tx_size) { return (rate_cost << AV1_PROB_COST_SHIFT); } +static AOM_INLINE void txfm_quant_rdcost( + const MACROBLOCK *x, int16_t *src_diff, int diff_stride, uint8_t *src, + int src_stride, uint8_t *dst, int dst_stride, tran_low_t *coeff, + tran_low_t *qcoeff, tran_low_t *dqcoeff, int bw, int bh, TX_SIZE tx_size, + int *rate_cost, int64_t *recon_error, int64_t *sse) { + const MACROBLOCKD *xd = &x->e_mbd; + uint16_t eob; + av1_subtract_block(xd, bh, bw, src_diff, diff_stride, src, src_stride, dst, + dst_stride); + tpl_fwd_txfm(src_diff, diff_stride, coeff, tx_size, xd->bd, + is_cur_buf_hbd(xd)); + + get_quantize_error(x, 0, coeff, qcoeff, dqcoeff, tx_size, &eob, recon_error, + sse); + + *rate_cost = rate_estimator(qcoeff, eob, tx_size); + + av1_inverse_transform_block(xd, dqcoeff, 0, DCT_DCT, tx_size, dst, dst_stride, + eob, 0); +} + static uint32_t motion_estimation(AV1_COMP *cpi, MACROBLOCK *x, uint8_t *cur_frame_buf, uint8_t *ref_frame_buf, int stride, - int stride_ref, BLOCK_SIZE bsize, int mi_row, - int mi_col) { + int stride_ref, BLOCK_SIZE bsize, + MV center_mv, int_mv *best_mv) { AV1_COMMON *cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; - MV_SPEED_FEATURES *const mv_sf = &cpi->sf.mv; - const SEARCH_METHODS search_method = NSTEP; + TPL_SPEED_FEATURES *tpl_sf = &cpi->sf.tpl_sf; int step_param; - int sadpb = x->sadperbit16; uint32_t bestsme = UINT_MAX; int distortion; uint32_t sse; int cost_list[5]; - const MvLimits tmp_mv_limits = x->mv_limits; - search_site_config ss_cfg; - - MV best_ref_mv1 = { 0, 0 }; - MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */ - - best_ref_mv1_full.col = best_ref_mv1.col >> 3; - best_ref_mv1_full.row = best_ref_mv1.row >> 3; + FULLPEL_MV start_mv = get_fullmv_from_mv(¢er_mv); // Setup frame pointers x->plane[0].src.buf = cur_frame_buf; @@ -111,54 +139,74 @@ static uint32_t motion_estimation(AV1_COMP *cpi, MACROBLOCK *x, xd->plane[0].pre[0].buf = ref_frame_buf; xd->plane[0].pre[0].stride = stride_ref; - step_param = mv_sf->reduce_first_step_size; + step_param = tpl_sf->reduce_first_step_size; step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2); - av1_set_mv_search_range(&x->mv_limits, &best_ref_mv1); + search_site_config *ss_cfg = &cpi->mv_search_params.ss_cfg[SS_CFG_SRC]; + if (ss_cfg->stride != stride_ref) + ss_cfg = &cpi->mv_search_params.ss_cfg[SS_CFG_LOOKAHEAD]; - av1_init3smotion_compensation(&ss_cfg, stride_ref); - 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, &ss_cfg, 0); + assert(ss_cfg->stride == stride_ref); - /* restore UMV window */ - x->mv_limits = tmp_mv_limits; + FULLPEL_MOTION_SEARCH_PARAMS full_ms_params; + av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, ¢er_mv, + ss_cfg); - const int pw = block_size_wide[bsize]; - const int ph = block_size_high[bsize]; - bestsme = cpi->find_fractional_mv_step( - x, cm, mi_row, mi_col, &best_ref_mv1, cpi->common.allow_high_precision_mv, - x->errorperbit, &cpi->fn_ptr[bsize], 0, mv_sf->subpel_iters_per_step, - cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL, NULL, - 0, 0, pw, ph, 1, 1); + av1_full_pixel_search(start_mv, &full_ms_params, step_param, + cond_cost_list(cpi, cost_list), &best_mv->as_fullmv, + NULL); + + SUBPEL_MOTION_SEARCH_PARAMS ms_params; + av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, ¢er_mv, + cost_list); + ms_params.forced_stop = tpl_sf->subpel_force_stop; + ms_params.var_params.subpel_search_type = USE_2_TAPS; + ms_params.mv_cost_params.mv_cost_type = MV_COST_NONE; + MV subpel_start_mv = get_mv_from_fullmv(&best_mv->as_fullmv); + bestsme = cpi->mv_search_params.find_fractional_mv_step( + xd, cm, &ms_params, subpel_start_mv, &best_mv->as_mv, &distortion, &sse, + NULL); return bestsme; } +static int is_alike_mv(int_mv candidate_mv, int_mv *center_mvs, + int center_mvs_count, int skip_alike_starting_mv) { + // MV difference threshold is in 1/8 precision. + const int mv_diff_thr[3] = { 1, (8 << 3), (16 << 3) }; + int thr = mv_diff_thr[skip_alike_starting_mv]; + int i; + + for (i = 0; i < center_mvs_count; i++) { + if (abs(center_mvs[i].as_mv.col - candidate_mv.as_mv.col) < thr && + abs(center_mvs[i].as_mv.row - candidate_mv.as_mv.row) < thr) + return 1; + } + + return 0; +} + static AOM_INLINE void mode_estimation( AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, struct scale_factors *sf, - int frame_idx, int16_t *src_diff, tran_low_t *coeff, tran_low_t *qcoeff, - tran_low_t *dqcoeff, int mi_row, int mi_col, BLOCK_SIZE bsize, - TX_SIZE tx_size, const YV12_BUFFER_CONFIG *ref_frame[], - const YV12_BUFFER_CONFIG *src_ref_frame[], uint8_t *predictor, - int64_t *recon_error, int64_t *sse, TplDepStats *tpl_stats) { + int frame_idx, int mi_row, int mi_col, BLOCK_SIZE bsize, TX_SIZE tx_size, + const YV12_BUFFER_CONFIG *ref_frame[], + const YV12_BUFFER_CONFIG *src_ref_frame[], TplDepStats *tpl_stats) { AV1_COMMON *cm = &cpi->common; const GF_GROUP *gf_group = &cpi->gf_group; (void)gf_group; - TplDepFrame *tpl_frame = &cpi->tpl_frame[frame_idx]; + TplParams *tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[frame_idx]; + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; const int bw = 4 << mi_size_wide_log2[bsize]; const int bh = 4 << mi_size_high_log2[bsize]; - const int pix_num = bw * bh; const int_interpfilters kernel = av1_broadcast_interp_filter(EIGHTTAP_REGULAR); int64_t best_intra_cost = INT64_MAX; int64_t intra_cost; - PREDICTION_MODE mode; PREDICTION_MODE best_mode = DC_PRED; int mb_y_offset = mi_row * MI_SIZE * xd->cur_buf->y_stride + mi_col * MI_SIZE; @@ -170,45 +218,67 @@ static AOM_INLINE void mode_estimation( uint8_t *dst_buffer = tpl_frame->rec_picture->y_buffer + dst_mb_offset; const int dst_buffer_stride = tpl_frame->rec_picture->y_stride; + // Temporaray buffers + DECLARE_ALIGNED(32, uint8_t, predictor8[MC_FLOW_NUM_PELS * 2]); + DECLARE_ALIGNED(32, int16_t, src_diff[MC_FLOW_NUM_PELS]); + DECLARE_ALIGNED(32, tran_low_t, coeff[MC_FLOW_NUM_PELS]); + DECLARE_ALIGNED(32, tran_low_t, qcoeff[MC_FLOW_NUM_PELS]); + DECLARE_ALIGNED(32, tran_low_t, dqcoeff[MC_FLOW_NUM_PELS]); + DECLARE_ALIGNED(32, tran_low_t, best_coeff[MC_FLOW_NUM_PELS]); + uint8_t *predictor = + is_cur_buf_hbd(xd) ? CONVERT_TO_BYTEPTR(predictor8) : predictor8; + int64_t recon_error = 1, sse = 1; + memset(tpl_stats, 0, sizeof(*tpl_stats)); - xd->above_mbmi = NULL; - xd->left_mbmi = NULL; + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + set_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, x, xd, + mi_row, mi_col); + set_mi_row_col(xd, &xd->tile, mi_row, mi_height, mi_col, mi_width, + cm->mi_params.mi_rows, cm->mi_params.mi_cols); + set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize], + av1_num_planes(cm)); xd->mi[0]->sb_type = bsize; xd->mi[0]->motion_mode = SIMPLE_TRANSLATION; - xd->up_available = mi_row > 0; - xd->left_available = mi_col > 0; // Intra prediction search xd->mi[0]->ref_frame[0] = INTRA_FRAME; - for (mode = DC_PRED; mode <= PAETH_PRED; ++mode) { - uint8_t *src; - uint8_t *dst; - int dst_stride; - src = src_mb_buffer; - - dst = predictor; - dst_stride = bw; + // Pre-load the bottom left line. + if (xd->left_available && + mi_row + tx_size_high_unit[tx_size] < xd->tile.mi_row_end) { +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + uint16_t *dst = CONVERT_TO_SHORTPTR(dst_buffer); + for (int i = 0; i < bw; ++i) + dst[(bw + i) * dst_buffer_stride - 1] = + dst[(bw - 1) * dst_buffer_stride - 1]; + } else { + for (int i = 0; i < bw; ++i) + dst_buffer[(bw + i) * dst_buffer_stride - 1] = + dst_buffer[(bw - 1) * dst_buffer_stride - 1]; + } +#else + for (int i = 0; i < bw; ++i) + dst_buffer[(bw + i) * dst_buffer_stride - 1] = + dst_buffer[(bw - 1) * dst_buffer_stride - 1]; +#endif + } + // if cpi->sf.tpl_sf.prune_intra_modes is on, then search only DC_PRED, + // H_PRED, and V_PRED + const PREDICTION_MODE last_intra_mode = + cpi->sf.tpl_sf.prune_intra_modes ? D45_PRED : INTRA_MODE_END; + for (PREDICTION_MODE mode = INTRA_MODE_START; mode < last_intra_mode; + ++mode) { av1_predict_intra_block(cm, xd, block_size_wide[bsize], block_size_high[bsize], tx_size, mode, 0, 0, FILTER_INTRA_MODES, dst_buffer, dst_buffer_stride, - dst, dst_stride, 0, 0, 0); + predictor, bw, 0, 0, 0); -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, src_diff, bw, src, src_stride, dst, - dst_stride, xd->bd); - } else { - aom_subtract_block(bh, bw, src_diff, bw, src, src_stride, dst, - dst_stride); - } -#else - aom_subtract_block(bh, bw, src_diff, bw, src, src_stride, dst, dst_stride); -#endif - wht_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, is_cur_buf_hbd(xd)); - intra_cost = aom_satd(coeff, pix_num); + intra_cost = tpl_get_satd_cost(x, src_diff, bw, src_mb_buffer, src_stride, + predictor, bw, coeff, bw, bh, tx_size); if (intra_cost < best_intra_cost) { best_intra_cost = intra_cost; @@ -217,7 +287,7 @@ static AOM_INLINE void mode_estimation( } // Motion compensated prediction - xd->mi[0]->ref_frame[0] = GOLDEN_FRAME; + xd->mi[0]->ref_frame[0] = INTRA_FRAME; int best_rf_idx = -1; int_mv best_mv; @@ -225,11 +295,13 @@ static AOM_INLINE void mode_estimation( int64_t best_inter_cost = INT64_MAX; int rf_idx; - best_mv.as_int = 0; + best_mv.as_int = INVALID_MV; for (rf_idx = 0; rf_idx < INTER_REFS_PER_FRAME; ++rf_idx) { - if (ref_frame[rf_idx] == NULL) continue; - if (src_ref_frame[rf_idx] == NULL) continue; + if (ref_frame[rf_idx] == NULL || src_ref_frame[rf_idx] == NULL) { + tpl_stats->mv[rf_idx].as_int = INVALID_MV; + continue; + } const YV12_BUFFER_CONFIG *ref_frame_ptr = src_ref_frame[rf_idx]; int ref_mb_offset = @@ -237,75 +309,123 @@ static AOM_INLINE void mode_estimation( uint8_t *ref_mb = ref_frame_ptr->y_buffer + ref_mb_offset; int ref_stride = ref_frame_ptr->y_stride; - motion_estimation(cpi, x, src_mb_buffer, ref_mb, src_stride, ref_stride, - bsize, mi_row, mi_col); + int_mv best_rfidx_mv = { 0 }; + uint32_t bestsme = UINT32_MAX; + int_mv center_mvs[4] = { { 0 } }; + int refmv_count = 1; + + if (xd->up_available) { + TplDepStats *ref_tpl_stats = &tpl_frame->tpl_stats_ptr[av1_tpl_ptr_pos( + mi_row - mi_height, mi_col, tpl_frame->stride, block_mis_log2)]; + if (!is_alike_mv(ref_tpl_stats->mv[rf_idx], center_mvs, refmv_count, + cpi->sf.tpl_sf.skip_alike_starting_mv)) { + center_mvs[refmv_count].as_int = ref_tpl_stats->mv[rf_idx].as_int; + ++refmv_count; + } + } + + if (xd->left_available) { + TplDepStats *ref_tpl_stats = &tpl_frame->tpl_stats_ptr[av1_tpl_ptr_pos( + mi_row, mi_col - mi_width, tpl_frame->stride, block_mis_log2)]; + if (!is_alike_mv(ref_tpl_stats->mv[rf_idx], center_mvs, refmv_count, + cpi->sf.tpl_sf.skip_alike_starting_mv)) { + center_mvs[refmv_count].as_int = ref_tpl_stats->mv[rf_idx].as_int; + ++refmv_count; + } + } + + if (xd->up_available && mi_col + mi_width < xd->tile.mi_col_end) { + TplDepStats *ref_tpl_stats = &tpl_frame->tpl_stats_ptr[av1_tpl_ptr_pos( + mi_row - mi_height, mi_col + mi_width, tpl_frame->stride, + block_mis_log2)]; + if (!is_alike_mv(ref_tpl_stats->mv[rf_idx], center_mvs, refmv_count, + cpi->sf.tpl_sf.skip_alike_starting_mv)) { + center_mvs[refmv_count].as_int = ref_tpl_stats->mv[rf_idx].as_int; + ++refmv_count; + } + } + + for (int idx = 0; idx < refmv_count; ++idx) { + int_mv this_mv; + uint32_t thissme = + motion_estimation(cpi, x, src_mb_buffer, ref_mb, src_stride, + ref_stride, bsize, center_mvs[idx].as_mv, &this_mv); + + if (thissme < bestsme) { + bestsme = thissme; + best_rfidx_mv = this_mv; + } + } + + tpl_stats->mv[rf_idx].as_int = best_rfidx_mv.as_int; + + struct buf_2d ref_buf = { NULL, ref_frame_ptr->y_buffer, + ref_frame_ptr->y_width, ref_frame_ptr->y_height, + ref_frame_ptr->y_stride }; InterPredParams inter_pred_params; - av1_init_inter_params(&inter_pred_params, bw, bh, mi_col * MI_SIZE, - mi_row * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, - sf, kernel); + av1_init_inter_params(&inter_pred_params, bw, bh, mi_row * MI_SIZE, + mi_col * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, + sf, &ref_buf, kernel); inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - av1_build_inter_predictor(ref_mb, ref_stride, predictor, bw, - &x->best_mv.as_mv, mi_col * MI_SIZE, - mi_row * MI_SIZE, &inter_pred_params); + av1_enc_build_one_inter_predictor(predictor, bw, &best_rfidx_mv.as_mv, + &inter_pred_params); -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - predictor, bw, xd->bd); - } else { - aom_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - predictor, bw); - } -#else - aom_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - predictor, bw); -#endif - - wht_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, is_cur_buf_hbd(xd)); - inter_cost = aom_satd(coeff, pix_num); + inter_cost = tpl_get_satd_cost(x, src_diff, bw, src_mb_buffer, src_stride, + predictor, bw, coeff, bw, bh, tx_size); + // Store inter cost for each ref frame + tpl_stats->pred_error[rf_idx] = AOMMAX(1, inter_cost); if (inter_cost < best_inter_cost) { - uint16_t eob; + memcpy(best_coeff, coeff, sizeof(best_coeff)); 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, &eob, - recon_error, sse); - int rate_cost = rate_estimator(qcoeff, eob, tx_size); - tpl_stats->srcrf_rate = rate_cost << TPL_DEP_COST_SCALE_LOG2; - if (best_inter_cost < best_intra_cost) best_mode = NEWMV; + best_inter_cost = inter_cost; + best_mv.as_int = best_rfidx_mv.as_int; + if (best_inter_cost < best_intra_cost) { + best_mode = NEWMV; + xd->mi[0]->ref_frame[0] = best_rf_idx + LAST_FRAME; + xd->mi[0]->mv[0].as_int = best_mv.as_int; + } } } + + if (best_inter_cost < INT64_MAX) { + uint16_t eob; + get_quantize_error(x, 0, best_coeff, qcoeff, dqcoeff, tx_size, &eob, + &recon_error, &sse); + + const int rate_cost = rate_estimator(qcoeff, eob, tx_size); + tpl_stats->srcrf_rate = rate_cost << TPL_DEP_COST_SCALE_LOG2; + } + best_intra_cost = AOMMAX(best_intra_cost, 1); - if (frame_idx == 0) + if (frame_idx == 0) { best_inter_cost = 0; - else + } else { best_inter_cost = AOMMIN(best_intra_cost, best_inter_cost); + } tpl_stats->inter_cost = best_inter_cost << TPL_DEP_COST_SCALE_LOG2; tpl_stats->intra_cost = best_intra_cost << TPL_DEP_COST_SCALE_LOG2; - tpl_stats->srcrf_dist = *recon_error << (TPL_DEP_COST_SCALE_LOG2); + tpl_stats->srcrf_dist = recon_error << (TPL_DEP_COST_SCALE_LOG2); // Final encode if (is_inter_mode(best_mode)) { + const YV12_BUFFER_CONFIG *ref_frame_ptr = ref_frame[best_rf_idx]; + InterPredParams inter_pred_params; - av1_init_inter_params(&inter_pred_params, bw, bh, mi_col * MI_SIZE, - mi_row * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, - sf, kernel); + struct buf_2d ref_buf = { NULL, ref_frame_ptr->y_buffer, + ref_frame_ptr->y_width, ref_frame_ptr->y_height, + ref_frame_ptr->y_stride }; + av1_init_inter_params(&inter_pred_params, bw, bh, mi_row * MI_SIZE, + mi_col * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0, + sf, &ref_buf, kernel); inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - const YV12_BUFFER_CONFIG *ref_frame_ptr = ref_frame[best_rf_idx]; - const int ref_mb_offset = - mi_row * MI_SIZE * ref_frame_ptr->y_stride + mi_col * MI_SIZE; - uint8_t *ref_mb = ref_frame_ptr->y_buffer + ref_mb_offset; - int ref_stride = ref_frame_ptr->y_stride; - - av1_build_inter_predictor(ref_mb, ref_stride, dst_buffer, dst_buffer_stride, - &best_mv.as_mv, mi_col * MI_SIZE, - mi_row * MI_SIZE, &inter_pred_params); + av1_enc_build_one_inter_predictor(dst_buffer, dst_buffer_stride, + &best_mv.as_mv, &inter_pred_params); } else { av1_predict_intra_block(cm, xd, block_size_wide[bsize], block_size_high[bsize], tx_size, best_mode, 0, 0, @@ -313,43 +433,32 @@ static AOM_INLINE void mode_estimation( dst_buffer, dst_buffer_stride, 0, 0, 0); } -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - dst_buffer, dst_buffer_stride, xd->bd); - } else { - aom_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - dst_buffer, dst_buffer_stride); - } -#else - aom_subtract_block(bh, bw, src_diff, bw, src_mb_buffer, src_stride, - dst_buffer, dst_buffer_stride); -#endif - wht_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, is_cur_buf_hbd(xd)); + int rate_cost; + txfm_quant_rdcost(x, src_diff, bw, src_mb_buffer, src_stride, dst_buffer, + dst_buffer_stride, coeff, qcoeff, dqcoeff, bw, bh, tx_size, + &rate_cost, &recon_error, &sse); - uint16_t eob; - - get_quantize_error(x, 0, coeff, qcoeff, dqcoeff, tx_size, &eob, recon_error, - sse); - - int rate_cost = rate_estimator(qcoeff, eob, tx_size); - - av1_inverse_transform_block(xd, dqcoeff, 0, DCT_DCT, tx_size, dst_buffer, - dst_buffer_stride, eob, 0); - - tpl_stats->recrf_dist = *recon_error << (TPL_DEP_COST_SCALE_LOG2); + tpl_stats->recrf_dist = recon_error << (TPL_DEP_COST_SCALE_LOG2); tpl_stats->recrf_rate = rate_cost << TPL_DEP_COST_SCALE_LOG2; if (!is_inter_mode(best_mode)) { - tpl_stats->srcrf_dist = *recon_error << (TPL_DEP_COST_SCALE_LOG2); + tpl_stats->srcrf_dist = recon_error << (TPL_DEP_COST_SCALE_LOG2); tpl_stats->srcrf_rate = rate_cost << TPL_DEP_COST_SCALE_LOG2; } tpl_stats->recrf_dist = AOMMAX(tpl_stats->srcrf_dist, tpl_stats->recrf_dist); tpl_stats->recrf_rate = AOMMAX(tpl_stats->srcrf_rate, tpl_stats->recrf_rate); - if (frame_idx && best_rf_idx != -1) { - tpl_stats->mv.as_int = best_mv.as_int; - tpl_stats->ref_frame_index = - cpi->tpl_frame[frame_idx].ref_map_index[best_rf_idx]; + if (best_rf_idx >= 0) { + tpl_stats->mv[best_rf_idx].as_int = best_mv.as_int; + tpl_stats->ref_frame_index = best_rf_idx; + } + + for (int idy = 0; idy < mi_height; ++idy) { + for (int idx = 0; idx < mi_width; ++idx) { + if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > idx && + (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > idy) { + xd->mi[idx + idy * cm->mi_params.mi_stride] = xd->mi[0]; + } + } } } @@ -392,9 +501,7 @@ static int get_overlap_area(int grid_pos_row, int grid_pos_col, int ref_pos_row, return width * height; } -int av1_tpl_ptr_pos(AV1_COMP *cpi, int mi_row, int mi_col, int stride) { - const int right_shift = cpi->tpl_stats_block_mis_log2; - +int av1_tpl_ptr_pos(int mi_row, int mi_col, int stride, uint8_t right_shift) { return (mi_row >> right_shift) * stride + (mi_col >> right_shift); } @@ -427,15 +534,28 @@ static int64_t delta_rate_cost(int64_t delta_rate, int64_t recrf_dist, return rate_cost; } -static AOM_INLINE void tpl_model_update_b(AV1_COMP *cpi, TplDepFrame *tpl_frame, - TplDepStats *tpl_stats_ptr, - int mi_row, int mi_col, - const BLOCK_SIZE bsize) { - TplDepFrame *ref_tpl_frame = &tpl_frame[tpl_stats_ptr->ref_frame_index]; +static AOM_INLINE void tpl_model_update_b(TplParams *const tpl_data, int mi_row, + int mi_col, const BLOCK_SIZE bsize, + int frame_idx) { + TplDepFrame *tpl_frame_ptr = &tpl_data->tpl_frame[frame_idx]; + TplDepStats *tpl_ptr = tpl_frame_ptr->tpl_stats_ptr; + TplDepFrame *tpl_frame = tpl_data->tpl_frame; + const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2; + TplDepStats *tpl_stats_ptr = &tpl_ptr[av1_tpl_ptr_pos( + mi_row, mi_col, tpl_frame->stride, block_mis_log2)]; + + if (tpl_stats_ptr->ref_frame_index < 0) return; + const int ref_frame_index = tpl_stats_ptr->ref_frame_index; + TplDepFrame *ref_tpl_frame = + &tpl_frame[tpl_frame[frame_idx].ref_map_index[ref_frame_index]]; TplDepStats *ref_stats_ptr = ref_tpl_frame->tpl_stats_ptr; - const int ref_pos_row = mi_row * MI_SIZE + (tpl_stats_ptr->mv.as_mv.row >> 3); - const int ref_pos_col = mi_col * MI_SIZE + (tpl_stats_ptr->mv.as_mv.col >> 3); + if (tpl_frame[frame_idx].ref_map_index[ref_frame_index] < 0) return; + + const FULLPEL_MV full_mv = + get_fullmv_from_mv(&tpl_stats_ptr->mv[ref_frame_index].as_mv); + const int ref_pos_row = mi_row * MI_SIZE + full_mv.row; + const int ref_pos_col = mi_col * MI_SIZE + full_mv.col; const int bw = 4 << mi_size_wide_log2[bsize]; const int bh = 4 << mi_size_high_log2[bsize]; @@ -468,12 +588,13 @@ static AOM_INLINE void tpl_model_update_b(AV1_COMP *cpi, TplDepFrame *tpl_frame, grid_pos_row, grid_pos_col, ref_pos_row, ref_pos_col, block, bsize); int ref_mi_row = round_floor(grid_pos_row, bh) * mi_height; int ref_mi_col = round_floor(grid_pos_col, bw) * mi_width; - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << block_mis_log2; for (int idy = 0; idy < mi_height; idy += step) { for (int idx = 0; idx < mi_width; idx += step) { TplDepStats *des_stats = &ref_stats_ptr[av1_tpl_ptr_pos( - cpi, ref_mi_row + idy, ref_mi_col + idx, ref_tpl_frame->stride)]; + ref_mi_row + idy, ref_mi_col + idx, ref_tpl_frame->stride, + block_mis_log2)]; des_stats->mc_dep_dist += ((cur_dep_dist + mc_dep_dist) * overlap_area) / pix_num; des_stats->mc_dep_rate += @@ -486,32 +607,30 @@ static AOM_INLINE void tpl_model_update_b(AV1_COMP *cpi, TplDepFrame *tpl_frame, } } -static AOM_INLINE void tpl_model_update(AV1_COMP *cpi, TplDepFrame *tpl_frame, - TplDepStats *tpl_stats_ptr, int mi_row, - int mi_col, const BLOCK_SIZE bsize) { +static AOM_INLINE void tpl_model_update(TplParams *const tpl_data, int mi_row, + int mi_col, const BLOCK_SIZE bsize, + int frame_idx) { const int mi_height = mi_size_high[bsize]; const int mi_width = mi_size_wide[bsize]; - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << tpl_data->tpl_stats_block_mis_log2; const BLOCK_SIZE tpl_block_size = - convert_length_to_bsize(MI_SIZE << cpi->tpl_stats_block_mis_log2); + convert_length_to_bsize(MI_SIZE << tpl_data->tpl_stats_block_mis_log2); for (int idy = 0; idy < mi_height; idy += step) { for (int idx = 0; idx < mi_width; idx += step) { - TplDepStats *tpl_ptr = &tpl_stats_ptr[av1_tpl_ptr_pos( - cpi, mi_row + idy, mi_col + idx, tpl_frame->stride)]; - tpl_model_update_b(cpi, tpl_frame, tpl_ptr, mi_row + idy, mi_col + idx, - tpl_block_size); + tpl_model_update_b(tpl_data, mi_row + idy, mi_col + idx, tpl_block_size, + frame_idx); } } } -static AOM_INLINE void tpl_model_store(AV1_COMP *cpi, - TplDepStats *tpl_stats_ptr, int mi_row, +static AOM_INLINE void tpl_model_store(TplDepStats *tpl_stats_ptr, int mi_row, int mi_col, BLOCK_SIZE bsize, int stride, - const TplDepStats *src_stats) { + const TplDepStats *src_stats, + uint8_t block_mis_log2) { const int mi_height = mi_size_high[bsize]; const int mi_width = mi_size_wide[bsize]; - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << block_mis_log2; int64_t intra_cost = src_stats->intra_cost / (mi_height * mi_width); int64_t inter_cost = src_stats->inter_cost / (mi_height * mi_width); @@ -528,8 +647,8 @@ static AOM_INLINE void tpl_model_store(AV1_COMP *cpi, recrf_rate = AOMMAX(1, recrf_rate); for (int idy = 0; idy < mi_height; idy += step) { - TplDepStats *tpl_ptr = - &tpl_stats_ptr[av1_tpl_ptr_pos(cpi, mi_row + idy, mi_col, stride)]; + TplDepStats *tpl_ptr = &tpl_stats_ptr[av1_tpl_ptr_pos( + mi_row + idy, mi_col, stride, block_mis_log2)]; for (int idx = 0; idx < mi_width; idx += step) { tpl_ptr->intra_cost = intra_cost; tpl_ptr->inter_cost = inter_cost; @@ -537,44 +656,31 @@ static AOM_INLINE void tpl_model_store(AV1_COMP *cpi, tpl_ptr->recrf_dist = recrf_dist; tpl_ptr->srcrf_rate = srcrf_rate; tpl_ptr->recrf_rate = recrf_rate; - tpl_ptr->mv.as_int = src_stats->mv.as_int; + memcpy(tpl_ptr->mv, src_stats->mv, sizeof(tpl_ptr->mv)); + memcpy(tpl_ptr->pred_error, src_stats->pred_error, + sizeof(tpl_ptr->pred_error)); tpl_ptr->ref_frame_index = src_stats->ref_frame_index; ++tpl_ptr; } } } -static YV12_BUFFER_CONFIG *get_framebuf( - AV1_COMP *cpi, const EncodeFrameInput *const frame_input, int frame_idx) { - if (frame_idx == 0) { - RefCntBuffer *ref_buf = get_ref_frame_buf(&cpi->common, GOLDEN_FRAME); - return &ref_buf->buf; - } else if (frame_idx == 1) { - return frame_input ? frame_input->source : NULL; - } else { - const GF_GROUP *gf_group = &cpi->gf_group; - const int frame_disp_idx = gf_group->frame_disp_idx[frame_idx]; - struct lookahead_entry *buf = av1_lookahead_peek( - cpi->lookahead, frame_disp_idx - cpi->num_gf_group_show_frames); - return &buf->img; - } -} - static AOM_INLINE void mc_flow_dispenser(AV1_COMP *cpi, int frame_idx, int pframe_qindex) { const GF_GROUP *gf_group = &cpi->gf_group; if (frame_idx == gf_group->size) return; - TplDepFrame *tpl_frame = &cpi->tpl_frame[frame_idx]; + TplParams *const tpl_data = &cpi->tpl_data; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[frame_idx]; const YV12_BUFFER_CONFIG *this_frame = tpl_frame->gf_picture; const YV12_BUFFER_CONFIG *ref_frame[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - unsigned int ref_frame_display_index[7]; - MV_REFERENCE_FRAME ref[2] = { LAST_FRAME, INTRA_FRAME }; - const int max_allowed_refs = get_max_allowed_ref_frames(cpi); + const YV12_BUFFER_CONFIG *ref_frames_ordered[INTER_REFS_PER_FRAME]; + int ref_frame_flags; const YV12_BUFFER_CONFIG *src_frame[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; AV1_COMMON *cm = &cpi->common; + const CommonModeInfoParams *const mi_params = &cm->mi_params; struct scale_factors sf; int rdmult, idx; ThreadData *td = &cpi->td; @@ -584,18 +690,10 @@ static AOM_INLINE void mc_flow_dispenser(AV1_COMP *cpi, int frame_idx, const BLOCK_SIZE bsize = convert_length_to_bsize(MC_FLOW_BSIZE_1D); av1_tile_init(&xd->tile, cm, 0, 0); - DECLARE_ALIGNED(32, uint8_t, predictor8[MC_FLOW_NUM_PELS * 2]); - DECLARE_ALIGNED(32, int16_t, src_diff[MC_FLOW_NUM_PELS]); - DECLARE_ALIGNED(32, tran_low_t, coeff[MC_FLOW_NUM_PELS]); - DECLARE_ALIGNED(32, tran_low_t, qcoeff[MC_FLOW_NUM_PELS]); - DECLARE_ALIGNED(32, tran_low_t, dqcoeff[MC_FLOW_NUM_PELS]); - 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 = 1, sse = 1; - // Setup scaling factor av1_setup_scale_factors_for_frame( &sf, this_frame->y_crop_width, this_frame->y_crop_height, @@ -603,42 +701,31 @@ static AOM_INLINE void mc_flow_dispenser(AV1_COMP *cpi, int frame_idx, xd->cur_buf = this_frame; - uint8_t *predictor = - is_cur_buf_hbd(xd) ? CONVERT_TO_BYTEPTR(predictor8) : predictor8; - for (idx = 0; idx < INTER_REFS_PER_FRAME; ++idx) { - TplDepFrame *tpl_ref_frame = &cpi->tpl_frame[tpl_frame->ref_map_index[idx]]; - ref_frame[idx] = cpi->tpl_frame[tpl_frame->ref_map_index[idx]].rec_picture; - ref_frame_display_index[idx] = tpl_ref_frame->frame_display_index; - src_frame[idx] = cpi->tpl_frame[tpl_frame->ref_map_index[idx]].gf_picture; + ref_frame[idx] = + tpl_data->tpl_frame[tpl_frame->ref_map_index[idx]].rec_picture; + src_frame[idx] = + tpl_data->tpl_frame[tpl_frame->ref_map_index[idx]].gf_picture; } - // Remove duplicate frames - for (int idx1 = 0; idx1 < INTER_REFS_PER_FRAME; ++idx1) { - for (int idx2 = idx1 + 1; idx2 < INTER_REFS_PER_FRAME; ++idx2) { - if (ref_frame[idx1] == ref_frame[idx2]) { - ref_frame[idx2] = NULL; - } - } + // Store the reference frames based on priority order + for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { + ref_frames_ordered[i] = ref_frame[ref_frame_priority_order[i] - 1]; } - // Skip motion estimation w.r.t. reference frames which are not - // considered in RD search, using "selective_ref_frame" speed feature + // Work out which reference frame slots may be used. + ref_frame_flags = get_ref_frame_flags(&cpi->sf, ref_frames_ordered, + cpi->ext_flags.ref_frame_flags); + + enforce_max_ref_frames(cpi, &ref_frame_flags); + + // Prune reference frames for (idx = 0; idx < INTER_REFS_PER_FRAME; ++idx) { - ref[0] = idx + 1; - if (prune_ref_by_selective_ref_frame(cpi, ref, ref_frame_display_index, - tpl_frame->frame_display_index)) { + if ((ref_frame_flags & (1 << idx)) == 0) { ref_frame[idx] = NULL; } } - // Skip reference frames based on user options and speed. - for (idx = 0; idx < AOMMIN(4, INTER_REFS_PER_FRAME - max_allowed_refs); - ++idx) { - const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[idx]; - ref_frame[ref_frame_to_disable - 1] = NULL; - } - // Make a temporary mbmi for tpl model MB_MODE_INFO mbmi; memset(&mbmi, 0, sizeof(mbmi)); @@ -656,36 +743,35 @@ static AOM_INLINE void mc_flow_dispenser(AV1_COMP *cpi, int frame_idx, tpl_frame->is_valid = 1; - cm->base_qindex = base_qindex; + cm->quant_params.base_qindex = base_qindex; av1_frame_init_quantizer(cpi); tpl_frame->base_rdmult = av1_compute_rd_mult_based_on_qindex(cpi, pframe_qindex) / 6; - for (mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) { + for (mi_row = 0; mi_row < mi_params->mi_rows; mi_row += mi_height) { // Motion estimation row boundary - x->mv_limits.row_min = -((mi_row * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND)); - x->mv_limits.row_max = (cm->mi_rows - mi_height - mi_row) * MI_SIZE + - (17 - 2 * AOM_INTERP_EXTEND); - 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; - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) { + av1_set_mv_row_limits(mi_params, &x->mv_limits, mi_row, mi_height, + cpi->oxcf.border_in_pixels); + xd->mb_to_top_edge = -GET_MV_SUBPEL(mi_row * MI_SIZE); + xd->mb_to_bottom_edge = + GET_MV_SUBPEL((mi_params->mi_rows - mi_height - mi_row) * MI_SIZE); + for (mi_col = 0; mi_col < mi_params->mi_cols; mi_col += mi_width) { TplDepStats tpl_stats; // Motion estimation column boundary - x->mv_limits.col_min = - -((mi_col * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND)); - x->mv_limits.col_max = ((cm->mi_cols - mi_width - mi_col) * MI_SIZE) + - (17 - 2 * AOM_INTERP_EXTEND); - 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; - mode_estimation(cpi, x, xd, &sf, frame_idx, src_diff, coeff, qcoeff, - dqcoeff, mi_row, mi_col, bsize, tx_size, ref_frame, - src_frame, predictor, &recon_error, &sse, &tpl_stats); + av1_set_mv_col_limits(mi_params, &x->mv_limits, mi_col, mi_width, + cpi->oxcf.border_in_pixels); + xd->mb_to_left_edge = -GET_MV_SUBPEL(mi_col * MI_SIZE); + xd->mb_to_right_edge = + GET_MV_SUBPEL(mi_params->mi_cols - mi_width - mi_col); + mode_estimation(cpi, x, xd, &sf, frame_idx, mi_row, mi_col, bsize, + tx_size, ref_frame, src_frame, &tpl_stats); // Motion flow dependency dispenser. - tpl_model_store(cpi, tpl_frame->tpl_stats_ptr, mi_row, mi_col, bsize, - tpl_frame->stride, &tpl_stats); + tpl_model_store(tpl_frame->tpl_stats_ptr, mi_row, mi_col, bsize, + tpl_frame->stride, &tpl_stats, + tpl_data->tpl_stats_block_mis_log2); } } } @@ -696,17 +782,16 @@ static void mc_flow_synthesizer(AV1_COMP *cpi, int frame_idx) { const GF_GROUP *gf_group = &cpi->gf_group; if (frame_idx == gf_group->size) return; - TplDepFrame *tpl_frame = &cpi->tpl_frame[frame_idx]; + TplParams *const tpl_data = &cpi->tpl_data; const BLOCK_SIZE bsize = convert_length_to_bsize(MC_FLOW_BSIZE_1D); const int mi_height = mi_size_high[bsize]; const int mi_width = mi_size_wide[bsize]; - for (int mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) { - for (int mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) { + for (int mi_row = 0; mi_row < cm->mi_params.mi_rows; mi_row += mi_height) { + for (int mi_col = 0; mi_col < cm->mi_params.mi_cols; mi_col += mi_width) { if (frame_idx) { - tpl_model_update(cpi, cpi->tpl_frame, tpl_frame->tpl_stats_ptr, mi_row, - mi_col, bsize); + tpl_model_update(tpl_data, mi_row, mi_col, bsize, frame_idx); } } } @@ -714,57 +799,43 @@ static void mc_flow_synthesizer(AV1_COMP *cpi, int frame_idx) { static AOM_INLINE void init_gop_frames_for_tpl( AV1_COMP *cpi, const EncodeFrameParams *const init_frame_params, - GF_GROUP *gf_group, int *tpl_group_frames, + GF_GROUP *gf_group, int gop_eval, int *tpl_group_frames, const EncodeFrameInput *const frame_input, int *pframe_qindex) { AV1_COMMON *cm = &cpi->common; - const SequenceHeader *const seq_params = &cm->seq_params; - int frame_idx = 0; - RefCntBuffer *frame_bufs = cm->buffer_pool->frame_bufs; int cur_frame_idx = gf_group->index; *pframe_qindex = 0; RefBufferStack ref_buffer_stack = cpi->ref_buffer_stack; EncodeFrameParams frame_params = *init_frame_params; + TplParams *const tpl_data = &cpi->tpl_data; int ref_picture_map[REF_FRAMES]; - for (int i = 0; i < FRAME_BUFFERS && frame_idx < INTER_REFS_PER_FRAME + 1; - ++i) { - if (frame_bufs[i].ref_count == 0) { - alloc_frame_mvs(cm, &frame_bufs[i]); - if (aom_realloc_frame_buffer( - &frame_bufs[i].buf, cm->width, cm->height, - seq_params->subsampling_x, seq_params->subsampling_y, - seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels, - cm->byte_alignment, NULL, NULL, NULL)) - aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR, - "Failed to allocate frame buffer"); - ++frame_idx; - } - } for (int i = 0; i < REF_FRAMES; ++i) { - if (frame_params.frame_type == KEY_FRAME) { - cpi->tpl_frame[-i - 1].gf_picture = NULL; - cpi->tpl_frame[-1 - 1].rec_picture = NULL; - cpi->tpl_frame[-i - 1].frame_display_index = 0; + if (frame_params.frame_type == KEY_FRAME || gop_eval) { + tpl_data->tpl_frame[-i - 1].gf_picture = NULL; + tpl_data->tpl_frame[-1 - 1].rec_picture = NULL; + tpl_data->tpl_frame[-i - 1].frame_display_index = 0; } else { - cpi->tpl_frame[-i - 1].gf_picture = &cm->ref_frame_map[i]->buf; - cpi->tpl_frame[-i - 1].rec_picture = &cm->ref_frame_map[i]->buf; - cpi->tpl_frame[-i - 1].frame_display_index = + tpl_data->tpl_frame[-i - 1].gf_picture = &cm->ref_frame_map[i]->buf; + tpl_data->tpl_frame[-i - 1].rec_picture = &cm->ref_frame_map[i]->buf; + tpl_data->tpl_frame[-i - 1].frame_display_index = cm->ref_frame_map[i]->display_order_hint; } ref_picture_map[i] = -i - 1; } - *tpl_group_frames = 0; + *tpl_group_frames = cur_frame_idx; int gf_index; int use_arf = gf_group->update_type[1] == ARF_UPDATE; + int anc_frame_offset = gf_group->cur_frame_idx[cur_frame_idx] + 1; + int process_frame_count = 0; const int gop_length = AOMMIN(gf_group->size - 1 + use_arf, MAX_LENGTH_TPL_FRAME_STATS - 1); for (gf_index = cur_frame_idx; gf_index <= gop_length; ++gf_index) { - TplDepFrame *tpl_frame = &cpi->tpl_frame[gf_index]; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_index]; FRAME_UPDATE_TYPE frame_update_type = gf_group->update_type[gf_index]; frame_params.show_frame = frame_update_type != ARF_UPDATE && @@ -789,8 +860,9 @@ static AOM_INLINE void init_gop_frames_for_tpl( int frame_display_index = gf_index == gf_group->size ? cpi->rc.baseline_gf_interval : gf_group->frame_disp_idx[gf_index]; - struct lookahead_entry *buf = - av1_lookahead_peek(cpi->lookahead, frame_display_index - 1); + struct lookahead_entry *buf = av1_lookahead_peek( + cpi->lookahead, frame_display_index - anc_frame_offset, + cpi->compressor_stage); if (buf == NULL) break; tpl_frame->gf_picture = &buf->img; // frame display index = frame offset within the gf group + start frame of @@ -798,14 +870,22 @@ static AOM_INLINE void init_gop_frames_for_tpl( tpl_frame->frame_display_index = frame_display_index + cpi->common.current_frame.display_order_hint; } - tpl_frame->rec_picture = &tpl_frame->rec_picture_buf; + + if (frame_update_type != OVERLAY_UPDATE && + frame_update_type != INTNL_OVERLAY_UPDATE) { + tpl_frame->rec_picture = &tpl_data->tpl_rec_pool[process_frame_count]; + tpl_frame->tpl_stats_ptr = tpl_data->tpl_stats_pool[process_frame_count]; + ++process_frame_count; + } av1_get_ref_frames(cpi, &ref_buffer_stack); int refresh_mask = av1_get_refresh_frame_flags( cpi, &frame_params, frame_update_type, &ref_buffer_stack); + int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask); - av1_update_ref_frame_map(cpi, frame_update_type, refresh_frame_map_index, - &ref_buffer_stack); + av1_update_ref_frame_map(cpi, frame_update_type, + frame_params.show_existing_frame, + refresh_frame_map_index, &ref_buffer_stack); for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) tpl_frame->ref_map_index[i - LAST_FRAME] = @@ -819,11 +899,15 @@ static AOM_INLINE void init_gop_frames_for_tpl( if (cur_frame_idx == 0) return; int extend_frame_count = 0; + int extend_frame_length = + AOMMIN(cpi->rc.baseline_gf_interval, + cpi->rc.frames_to_key - cpi->rc.baseline_gf_interval); int frame_display_index = cpi->rc.baseline_gf_interval + 1; - for (; gf_index < MAX_LENGTH_TPL_FRAME_STATS && extend_frame_count < 2; + for (; gf_index < MAX_LENGTH_TPL_FRAME_STATS && + extend_frame_count < extend_frame_length; ++gf_index) { - TplDepFrame *tpl_frame = &cpi->tpl_frame[gf_index]; + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_index]; FRAME_UPDATE_TYPE frame_update_type = LF_UPDATE; frame_params.show_frame = frame_update_type != ARF_UPDATE && frame_update_type != INTNL_ARF_UPDATE; @@ -831,13 +915,16 @@ static AOM_INLINE void init_gop_frames_for_tpl( frame_update_type == INTNL_OVERLAY_UPDATE; frame_params.frame_type = INTER_FRAME; - struct lookahead_entry *buf = - av1_lookahead_peek(cpi->lookahead, frame_display_index - 1); + struct lookahead_entry *buf = av1_lookahead_peek( + cpi->lookahead, frame_display_index - anc_frame_offset, + cpi->compressor_stage); if (buf == NULL) break; tpl_frame->gf_picture = &buf->img; - tpl_frame->rec_picture = &tpl_frame->rec_picture_buf; + tpl_frame->rec_picture = &tpl_data->tpl_rec_pool[process_frame_count]; + tpl_frame->tpl_stats_ptr = tpl_data->tpl_stats_pool[process_frame_count]; + ++process_frame_count; // frame display index = frame offset within the gf group + start frame of // the gf group @@ -851,13 +938,19 @@ static AOM_INLINE void init_gop_frames_for_tpl( int refresh_mask = av1_get_refresh_frame_flags( cpi, &frame_params, frame_update_type, &ref_buffer_stack); int refresh_frame_map_index = av1_get_refresh_ref_frame_map(refresh_mask); - av1_update_ref_frame_map(cpi, frame_update_type, refresh_frame_map_index, - &ref_buffer_stack); + av1_update_ref_frame_map(cpi, frame_update_type, + frame_params.show_existing_frame, + refresh_frame_map_index, &ref_buffer_stack); for (int i = LAST_FRAME; i <= ALTREF_FRAME; ++i) tpl_frame->ref_map_index[i - LAST_FRAME] = ref_picture_map[cm->remapped_ref_idx[i - LAST_FRAME]]; + tpl_frame->ref_map_index[ALTREF_FRAME - LAST_FRAME] = -1; + tpl_frame->ref_map_index[LAST3_FRAME - LAST_FRAME] = -1; + tpl_frame->ref_map_index[BWDREF_FRAME - LAST_FRAME] = -1; + tpl_frame->ref_map_index[ALTREF2_FRAME - LAST_FRAME] = -1; + if (refresh_mask) ref_picture_map[refresh_frame_map_index] = gf_index; ++*tpl_group_frames; @@ -868,34 +961,39 @@ static AOM_INLINE void init_gop_frames_for_tpl( av1_get_ref_frames(cpi, &cpi->ref_buffer_stack); } -static AOM_INLINE void init_tpl_stats(AV1_COMP *cpi) { - for (int frame_idx = 0; frame_idx < MAX_LENGTH_TPL_FRAME_STATS; ++frame_idx) { - TplDepFrame *tpl_frame = &cpi->tpl_stats_buffer[frame_idx]; - memset(tpl_frame->tpl_stats_ptr, 0, +static AOM_INLINE void init_tpl_stats(TplParams *const tpl_data) { + for (int frame_idx = 0; frame_idx < MAX_LAG_BUFFERS; ++frame_idx) { + TplDepFrame *tpl_frame = &tpl_data->tpl_stats_buffer[frame_idx]; + memset(tpl_data->tpl_stats_pool[frame_idx], 0, tpl_frame->height * tpl_frame->width * sizeof(*tpl_frame->tpl_stats_ptr)); tpl_frame->is_valid = 0; } } -void av1_tpl_setup_stats(AV1_COMP *cpi, - const EncodeFrameParams *const frame_params, - const EncodeFrameInput *const frame_input) { +int av1_tpl_setup_stats(AV1_COMP *cpi, int gop_eval, + const EncodeFrameParams *const frame_params, + const EncodeFrameInput *const frame_input) { AV1_COMMON *cm = &cpi->common; GF_GROUP *gf_group = &cpi->gf_group; int bottom_index, top_index; EncodeFrameParams this_frame_params = *frame_params; + TplParams *const tpl_data = &cpi->tpl_data; + + if (cpi->superres_mode != SUPERRES_NONE) return 0; cm->current_frame.frame_type = frame_params->frame_type; for (int gf_index = gf_group->index; gf_index < gf_group->size; ++gf_index) { av1_configure_buffer_updates(cpi, &this_frame_params, gf_group->update_type[gf_index], 0); - cpi->refresh_last_frame = this_frame_params.refresh_last_frame; cpi->refresh_golden_frame = this_frame_params.refresh_golden_frame; cpi->refresh_bwd_ref_frame = this_frame_params.refresh_bwd_ref_frame; cpi->refresh_alt_ref_frame = this_frame_params.refresh_alt_ref_frame; + cm->show_frame = gf_group->update_type[gf_index] != ARF_UPDATE && + gf_group->update_type[gf_index] != INTNL_ARF_UPDATE; + gf_group->q_val[gf_index] = av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cm->width, cm->height, gf_index, &bottom_index, &top_index); @@ -904,296 +1002,74 @@ void av1_tpl_setup_stats(AV1_COMP *cpi, } int pframe_qindex; - init_gop_frames_for_tpl(cpi, frame_params, gf_group, - &cpi->tpl_gf_group_frames, frame_input, - &pframe_qindex); + int tpl_gf_group_frames; + init_gop_frames_for_tpl(cpi, frame_params, gf_group, gop_eval, + &tpl_gf_group_frames, frame_input, &pframe_qindex); cpi->rc.base_layer_qp = pframe_qindex; - init_tpl_stats(cpi); + init_tpl_stats(tpl_data); - if (cpi->oxcf.enable_tpl_model == 1) { - // Backward propagation from tpl_group_frames to 1. - for (int frame_idx = gf_group->index; frame_idx < cpi->tpl_gf_group_frames; - ++frame_idx) { - if (gf_group->update_type[frame_idx] == INTNL_OVERLAY_UPDATE || - gf_group->update_type[frame_idx] == OVERLAY_UPDATE) - continue; + // Backward propagation from tpl_group_frames to 1. + for (int frame_idx = gf_group->index; frame_idx < tpl_gf_group_frames; + ++frame_idx) { + if (gf_group->update_type[frame_idx] == INTNL_OVERLAY_UPDATE || + gf_group->update_type[frame_idx] == OVERLAY_UPDATE) + continue; - mc_flow_dispenser(cpi, frame_idx, pframe_qindex); + mc_flow_dispenser(cpi, frame_idx, pframe_qindex); - aom_extend_frame_borders(cpi->tpl_frame[frame_idx].rec_picture, - av1_num_planes(cm)); - } + aom_extend_frame_borders(tpl_data->tpl_frame[frame_idx].rec_picture, + av1_num_planes(cm)); + } - for (int frame_idx = cpi->tpl_gf_group_frames - 1; - frame_idx >= gf_group->index; --frame_idx) { - if (gf_group->update_type[frame_idx] == INTNL_OVERLAY_UPDATE || - gf_group->update_type[frame_idx] == OVERLAY_UPDATE) - continue; + for (int frame_idx = tpl_gf_group_frames - 1; frame_idx >= gf_group->index; + --frame_idx) { + if (gf_group->update_type[frame_idx] == INTNL_OVERLAY_UPDATE || + gf_group->update_type[frame_idx] == OVERLAY_UPDATE) + continue; - mc_flow_synthesizer(cpi, frame_idx); - } + mc_flow_synthesizer(cpi, frame_idx); } av1_configure_buffer_updates(cpi, &this_frame_params, gf_group->update_type[gf_group->index], 0); cm->current_frame.frame_type = frame_params->frame_type; -} + cm->show_frame = frame_params->show_frame; -static AOM_INLINE void get_tpl_forward_stats(AV1_COMP *cpi, MACROBLOCK *x, - MACROBLOCKD *xd, BLOCK_SIZE bsize, - int use_satd, - YV12_BUFFER_CONFIG *ref, - YV12_BUFFER_CONFIG *src, - TplDepFrame *ref_tpl_frame) { -// TODO(yuec) Consider deleting forward tpl model completely -#if !USE_TPL_CLASSIC_MODEL - AV1_COMMON *cm = &cpi->common; - const int bw = 4 << mi_size_wide_log2[bsize]; - const int bh = 4 << mi_size_high_log2[bsize]; - const int mi_height = mi_size_high[bsize]; - const int mi_width = mi_size_wide[bsize]; - const int pix_num = bw * bh; - const TX_SIZE tx_size = max_txsize_lookup[bsize]; + if (cpi->common.tiles.large_scale) return 0; + if (gf_group->max_layer_depth_allowed == 0) return 1; - DECLARE_ALIGNED(32, uint8_t, predictor8[MC_FLOW_NUM_PELS * 2]); - DECLARE_ALIGNED(32, int16_t, src_diff[MC_FLOW_NUM_PELS]); - DECLARE_ALIGNED(32, tran_low_t, coeff[MC_FLOW_NUM_PELS]); - uint8_t *predictor = - is_cur_buf_hbd(xd) ? CONVERT_TO_BYTEPTR(predictor8) : predictor8; + double beta[2] = { 0.0 }; + for (int frame_idx = 1; frame_idx <= AOMMIN(tpl_gf_group_frames - 1, 2); + ++frame_idx) { + TplDepFrame *tpl_frame = &tpl_data->tpl_frame[frame_idx]; + TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; + int tpl_stride = tpl_frame->stride; + int64_t intra_cost_base = 0; + int64_t mc_dep_cost_base = 0; + const int step = 1 << tpl_data->tpl_stats_block_mis_log2; + const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width); - // Initialize advanced prediction parameters as default values - struct scale_factors sf; - av1_setup_scale_factors_for_frame(&sf, ref->y_crop_width, ref->y_crop_height, - src->y_crop_width, src->y_crop_height); - const int_interpfilters kernel = - av1_broadcast_interp_filter(EIGHTTAP_REGULAR); - xd->above_mbmi = NULL; - xd->left_mbmi = NULL; - xd->mi[0]->sb_type = bsize; - xd->mi[0]->motion_mode = SIMPLE_TRANSLATION; - xd->block_ref_scale_factors[0] = &sf; - - for (int mi_row = 0; mi_row < cm->mi_rows; mi_row += mi_height) { - // Motion estimation row boundary - x->mv_limits.row_min = -((mi_row * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND)); - x->mv_limits.row_max = (cm->mi_rows - mi_height - mi_row) * MI_SIZE + - (17 - 2 * AOM_INTERP_EXTEND); - 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; - - for (int mi_col = 0; mi_col < cm->mi_cols; mi_col += mi_width) { - int64_t inter_cost, intra_cost; - x->mv_limits.col_min = - -((mi_col * MI_SIZE) + (17 - 2 * AOM_INTERP_EXTEND)); - x->mv_limits.col_max = ((cm->mi_cols - mi_width - mi_col) * MI_SIZE) + - (17 - 2 * AOM_INTERP_EXTEND); - 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; - - // Intra mode - xd->mi[0]->ref_frame[0] = INTRA_FRAME; - int64_t best_intra_cost = INT64_MAX; - for (PREDICTION_MODE mode = DC_PRED; mode <= PAETH_PRED; ++mode) { - uint8_t *src_buf = - src->y_buffer + mi_row * MI_SIZE * src->y_stride + mi_col * MI_SIZE; - const int src_stride = src->y_stride; - - uint8_t *dst_buf = predictor; - const int dst_stride = bw; - - av1_predict_intra_block(cm, xd, bw, bh, tx_size, mode, 0, 0, - FILTER_INTRA_MODES, src_buf, src_stride, - dst_buf, dst_stride, 0, 0, 0); - - if (use_satd) { -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, src_diff, bw, src_buf, src_stride, - dst_buf, dst_stride, xd->bd); - } else { - aom_subtract_block(bh, bw, src_diff, bw, src_buf, src_stride, - dst_buf, dst_stride); - } -#else - aom_subtract_block(bh, bw, src_diff, bw, src_buf, src_stride, dst_buf, - dst_stride); -#endif - wht_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, - is_cur_buf_hbd(xd)); - - intra_cost = aom_satd(coeff, pix_num); - } else { - int64_t sse; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - sse = aom_highbd_sse(src_buf, src_stride, dst_buf, dst_stride, bw, - bh); - } else { - sse = aom_sse(src_buf, src_stride, dst_buf, dst_stride, bw, bh); - } -#else - sse = aom_sse(src_buf, src_stride, dst_buf, dst_stride, bw, bh); -#endif - intra_cost = ROUND_POWER_OF_TWO(sse, (xd->bd - 8) * 2); - } - if (intra_cost < best_intra_cost) best_intra_cost = intra_cost; - } - - // Inter mode - // Motion estimation column boundary - xd->mi[0]->ref_frame[0] = GOLDEN_FRAME; - - const int mb_y_offset = - mi_row * MI_SIZE * src->y_stride + mi_col * MI_SIZE; - const int mb_y_offset_ref = - mi_row * MI_SIZE * ref->y_stride + mi_col * MI_SIZE; - motion_estimation(cpi, x, src->y_buffer + mb_y_offset, - ref->y_buffer + mb_y_offset_ref, src->y_stride, - ref->y_stride, bsize, mi_row, mi_col); - - InterPredParams inter_pred_params; - av1_init_inter_params(&inter_pred_params, bw, bh, mi_col * MI_SIZE, - mi_row * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), - 0, &sf, kernel); - inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd); - - av1_build_inter_predictor(ref->y_buffer + mb_y_offset_ref, ref->y_stride, - predictor, bw, &x->best_mv.as_mv, - mi_col * MI_SIZE, mi_row * MI_SIZE, - &inter_pred_params); - if (use_satd) { -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - aom_highbd_subtract_block(bh, bw, src_diff, bw, - src->y_buffer + mb_y_offset, src->y_stride, - predictor, bw, xd->bd); - } else { - aom_subtract_block(bh, bw, src_diff, bw, src->y_buffer + mb_y_offset, - src->y_stride, predictor, bw); - } -#else - aom_subtract_block(bh, bw, src_diff, bw, src->y_buffer + mb_y_offset, - src->y_stride, predictor, bw); -#endif - wht_fwd_txfm(src_diff, bw, coeff, tx_size, xd->bd, is_cur_buf_hbd(xd)); - inter_cost = aom_satd(coeff, pix_num); - } else { - int64_t sse; -#if CONFIG_AV1_HIGHBITDEPTH - if (is_cur_buf_hbd(xd)) { - sse = aom_highbd_sse(src->y_buffer + mb_y_offset, src->y_stride, - predictor, bw, bw, bh); - } else { - sse = aom_sse(src->y_buffer + mb_y_offset, src->y_stride, predictor, - bw, bw, bh); - } -#else - sse = aom_sse(src->y_buffer + mb_y_offset, src->y_stride, predictor, bw, - bw, bh); -#endif - inter_cost = ROUND_POWER_OF_TWO(sse, (xd->bd - 8) * 2); - } - - // Finalize stats - best_intra_cost = AOMMAX(best_intra_cost, 1); - inter_cost = AOMMIN(best_intra_cost, inter_cost); - - // Project stats to reference block - TplDepStats *ref_stats_ptr = ref_tpl_frame->tpl_stats_ptr; - const MV mv = x->best_mv.as_mv; - const int mv_row = mv.row >> 3; - const int mv_col = mv.col >> 3; - const int ref_pos_row = mi_row * MI_SIZE + mv_row; - const int ref_pos_col = mi_col * MI_SIZE + mv_col; - const int grid_pos_row_base = round_floor(ref_pos_row, bh) * bh; - const int grid_pos_col_base = round_floor(ref_pos_col, bw) * bw; - - for (int block = 0; block < 4; ++block) { - const int grid_pos_row = grid_pos_row_base + bh * (block >> 1); - const int grid_pos_col = grid_pos_col_base + bw * (block & 0x01); - - if (grid_pos_row >= 0 && - grid_pos_row < ref_tpl_frame->mi_rows * MI_SIZE && - grid_pos_col >= 0 && - grid_pos_col < ref_tpl_frame->mi_cols * MI_SIZE) { - const int overlap_area = - get_overlap_area(grid_pos_row, grid_pos_col, ref_pos_row, - ref_pos_col, block, bsize); - const int ref_mi_row = round_floor(grid_pos_row, bh) * mi_height; - const int ref_mi_col = round_floor(grid_pos_col, bw) * mi_width; - - const int64_t mc_saved = (best_intra_cost - inter_cost) - << TPL_DEP_COST_SCALE_LOG2; - for (int idy = 0; idy < mi_height; ++idy) { - for (int idx = 0; idx < mi_width; ++idx) { - TplDepStats *des_stats = - &ref_stats_ptr[(ref_mi_row + idy) * ref_tpl_frame->stride + - (ref_mi_col + idx)]; - des_stats->mc_count += overlap_area << TPL_DEP_COST_SCALE_LOG2; - des_stats->mc_saved += (mc_saved * overlap_area) / pix_num; - - assert(overlap_area >= 0); - } - } - } + for (int row = 0; row < cm->mi_params.mi_rows; row += step) { + for (int col = 0; col < mi_cols_sr; col += step) { + TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos( + row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)]; + int64_t mc_dep_delta = + RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate, + this_stats->mc_dep_dist); + intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS); + mc_dep_cost_base += + (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta; } } + beta[frame_idx - 1] = (double)mc_dep_cost_base / intra_cost_base; } -#else - (void)cpi; - (void)x; - (void)xd; - (void)bsize; - (void)use_satd; - (void)ref; - (void)src; - (void)ref_tpl_frame; -#endif // !USE_TPL_CLASSIC_MODEL -} -void av1_tpl_setup_forward_stats(AV1_COMP *cpi) { - ThreadData *td = &cpi->td; - MACROBLOCK *x = &td->mb; - MACROBLOCKD *xd = &x->e_mbd; - const BLOCK_SIZE bsize = convert_length_to_bsize(MC_FLOW_BSIZE_1D); - - const GF_GROUP *gf_group = &cpi->gf_group; - assert(IMPLIES(gf_group->size > 0, gf_group->index < gf_group->size)); - const int tpl_cur_idx = gf_group->frame_disp_idx[gf_group->index]; - TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_cur_idx]; - memset( - tpl_frame->tpl_stats_ptr, 0, - tpl_frame->height * tpl_frame->width * sizeof(*tpl_frame->tpl_stats_ptr)); - tpl_frame->is_valid = 0; - int tpl_used_mask[MAX_LENGTH_TPL_FRAME_STATS] = { 0 }; - for (int idx = gf_group->index + 1; idx < cpi->tpl_gf_group_frames; ++idx) { - const int tpl_future_idx = gf_group->frame_disp_idx[idx]; - - if (gf_group->update_type[idx] == OVERLAY_UPDATE || - gf_group->update_type[idx] == INTNL_OVERLAY_UPDATE) - continue; - if (tpl_future_idx == tpl_cur_idx) continue; - if (tpl_used_mask[tpl_future_idx]) continue; - - for (int ridx = 0; ridx < INTER_REFS_PER_FRAME; ++ridx) { - const int ref_idx = gf_group->ref_frame_gop_idx[idx][ridx]; - const int tpl_ref_idx = gf_group->frame_disp_idx[ref_idx]; - if (tpl_ref_idx == tpl_cur_idx) { - // Do tpl stats computation between current buffer and the one at - // gf_group index given by idx (and with disp index given by - // tpl_future_idx). - assert(idx >= 2); - YV12_BUFFER_CONFIG *cur_buf = &cpi->common.cur_frame->buf; - YV12_BUFFER_CONFIG *future_buf = get_framebuf(cpi, NULL, idx); - get_tpl_forward_stats(cpi, x, xd, bsize, 0, cur_buf, future_buf, - tpl_frame); - tpl_frame->is_valid = 1; - tpl_used_mask[tpl_future_idx] = 1; - } - } - } + // Allow larger GOP size if the base layer ARF has higher dependency factor + // than the intermediate ARF and both ARFs have reasonably high dependency + // factors. + return (beta[0] >= beta[1] + 0.7) && beta[0] > 3.0; } void av1_tpl_rdmult_setup(AV1_COMP *cpi) { @@ -1203,10 +1079,11 @@ void av1_tpl_rdmult_setup(AV1_COMP *cpi) { assert(IMPLIES(gf_group->size > 0, tpl_idx < gf_group->size)); - const TplDepFrame *const tpl_frame = &cpi->tpl_frame[tpl_idx]; + TplParams *const tpl_data = &cpi->tpl_data; + const TplDepFrame *const tpl_frame = &tpl_data->tpl_frame[tpl_idx]; if (!tpl_frame->is_valid) return; - if (cpi->oxcf.superres_mode != SUPERRES_NONE) return; + if (cpi->superres_mode != SUPERRES_NONE) return; const TplDepStats *const tpl_stats = tpl_frame->tpl_stats_ptr; const int tpl_stride = tpl_frame->stride; @@ -1216,9 +1093,9 @@ void av1_tpl_rdmult_setup(AV1_COMP *cpi) { const int num_mi_w = mi_size_wide[block_size]; const int num_mi_h = mi_size_high[block_size]; const int num_cols = (mi_cols_sr + num_mi_w - 1) / num_mi_w; - const int num_rows = (cm->mi_rows + num_mi_h - 1) / num_mi_h; + const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h; const double c = 1.2; - const int step = 1 << cpi->tpl_stats_block_mis_log2; + const int step = 1 << tpl_data->tpl_stats_block_mis_log2; aom_clear_system_state(); @@ -1231,9 +1108,9 @@ void av1_tpl_rdmult_setup(AV1_COMP *cpi) { mi_row += step) { for (int mi_col = col * num_mi_w; mi_col < (col + 1) * num_mi_w; mi_col += step) { - if (mi_row >= cm->mi_rows || mi_col >= mi_cols_sr) continue; - const TplDepStats *this_stats = - &tpl_stats[av1_tpl_ptr_pos(cpi, mi_row, mi_col, tpl_stride)]; + if (mi_row >= cm->mi_params.mi_rows || mi_col >= mi_cols_sr) continue; + const TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos( + mi_row, mi_col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)]; int64_t mc_dep_delta = RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate, this_stats->mc_dep_dist); @@ -1256,23 +1133,19 @@ void av1_tpl_rdmult_setup_sb(AV1_COMP *cpi, MACROBLOCK *const x, assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int tpl_idx = cpi->gf_group.index; - TplDepFrame *tpl_frame = &cpi->tpl_frame[tpl_idx]; + TplDepFrame *tpl_frame = &cpi->tpl_data.tpl_frame[tpl_idx]; - if (cpi->tpl_model_pass == 1) { - assert(cpi->oxcf.enable_tpl_model == 2); - return; - } if (tpl_frame->is_valid == 0) return; if (!is_frame_tpl_eligible(cpi)) return; if (tpl_idx >= MAX_LAG_BUFFERS) return; - if (cpi->oxcf.superres_mode != SUPERRES_NONE) return; + if (cpi->superres_mode != SUPERRES_NONE) return; if (cpi->oxcf.aq_mode != NO_AQ) return; const int bsize_base = BLOCK_16X16; const int num_mi_w = mi_size_wide[bsize_base]; const int num_mi_h = mi_size_high[bsize_base]; - const int num_cols = (cm->mi_cols + num_mi_w - 1) / num_mi_w; - const int num_rows = (cm->mi_rows + num_mi_h - 1) / num_mi_h; + const int num_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w; + const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h; const int num_bcols = (mi_size_wide[sb_size] + num_mi_w - 1) / num_mi_w; const int num_brows = (mi_size_high[sb_size] + num_mi_h - 1) / num_mi_h; int row, col; @@ -1292,10 +1165,12 @@ void av1_tpl_rdmult_setup_sb(AV1_COMP *cpi, MACROBLOCK *const x, } MACROBLOCKD *const xd = &x->e_mbd; - const int orig_rdmult = - av1_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q); - const int new_rdmult = av1_compute_rd_mult( - cpi, cm->base_qindex + xd->delta_qindex + cm->y_dc_delta_q); + const CommonQuantParams *quant_params = &cm->quant_params; + const int orig_rdmult = av1_compute_rd_mult( + cpi, quant_params->base_qindex + quant_params->y_dc_delta_q); + const int new_rdmult = + av1_compute_rd_mult(cpi, quant_params->base_qindex + xd->delta_qindex + + quant_params->y_dc_delta_q); const double scaling_factor = (double)new_rdmult / (double)orig_rdmult; double scale_adj = log(scaling_factor) - log_sum / base_block_count; diff --git a/media/libaom/src/av1/encoder/tpl_model.h b/media/libaom/src/av1/encoder/tpl_model.h index 3a55ef8ad3..11a61b649d 100644 --- a/media/libaom/src/av1/encoder/tpl_model.h +++ b/media/libaom/src/av1/encoder/tpl_model.h @@ -29,13 +29,11 @@ static INLINE BLOCK_SIZE convert_length_to_bsize(int length) { } } -void av1_tpl_setup_stats(AV1_COMP *cpi, - const EncodeFrameParams *const frame_params, - const EncodeFrameInput *const frame_input); +int av1_tpl_setup_stats(AV1_COMP *cpi, int gop_eval, + const EncodeFrameParams *const frame_params, + const EncodeFrameInput *const frame_input); -void av1_tpl_setup_forward_stats(AV1_COMP *cpi); - -int av1_tpl_ptr_pos(AV1_COMP *cpi, int mi_row, int mi_col, int stride); +int av1_tpl_ptr_pos(int mi_row, int mi_col, int stride, uint8_t right_shift); void av1_tpl_rdmult_setup(AV1_COMP *cpi); diff --git a/media/libaom/src/av1/encoder/tune_vmaf.c b/media/libaom/src/av1/encoder/tune_vmaf.c new file mode 100644 index 0000000000..997f78e27c --- /dev/null +++ b/media/libaom/src/av1/encoder/tune_vmaf.c @@ -0,0 +1,794 @@ +/* + * 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 "av1/encoder/tune_vmaf.h" + +#include "aom_dsp/psnr.h" +#include "aom_dsp/vmaf.h" +#include "aom_ports/system_state.h" +#include "av1/encoder/extend.h" +#include "av1/encoder/rdopt.h" + +static const double kBaselineVmaf = 97.42773; + +// TODO(sdeng): Add the SIMD implementation. +static AOM_INLINE void highbd_unsharp_rect(const uint16_t *source, + int source_stride, + const uint16_t *blurred, + int blurred_stride, uint16_t *dst, + int dst_stride, int w, int h, + double amount, int bit_depth) { + const int max_value = (1 << bit_depth) - 1; + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + const double val = + (double)source[j] + amount * ((double)source[j] - (double)blurred[j]); + dst[j] = (uint16_t)clamp((int)(val + 0.5), 0, max_value); + } + source += source_stride; + blurred += blurred_stride; + dst += dst_stride; + } +} + +static AOM_INLINE void unsharp_rect(const uint8_t *source, int source_stride, + const uint8_t *blurred, int blurred_stride, + uint8_t *dst, int dst_stride, int w, int h, + double amount) { + for (int i = 0; i < h; ++i) { + for (int j = 0; j < w; ++j) { + const double val = + (double)source[j] + amount * ((double)source[j] - (double)blurred[j]); + dst[j] = (uint8_t)clamp((int)(val + 0.5), 0, 255); + } + source += source_stride; + blurred += blurred_stride; + dst += dst_stride; + } +} + +static AOM_INLINE void unsharp(const AV1_COMP *const cpi, + const YV12_BUFFER_CONFIG *source, + const YV12_BUFFER_CONFIG *blurred, + const YV12_BUFFER_CONFIG *dst, double amount) { + const int bit_depth = cpi->td.mb.e_mbd.bd; + if (bit_depth > 8) { + highbd_unsharp_rect(CONVERT_TO_SHORTPTR(source->y_buffer), source->y_stride, + CONVERT_TO_SHORTPTR(blurred->y_buffer), + blurred->y_stride, CONVERT_TO_SHORTPTR(dst->y_buffer), + dst->y_stride, source->y_width, source->y_height, + amount, bit_depth); + } else { + unsharp_rect(source->y_buffer, source->y_stride, blurred->y_buffer, + blurred->y_stride, dst->y_buffer, dst->y_stride, + source->y_width, source->y_height, amount); + } +} + +// 8-tap Gaussian convolution filter with sigma = 1.0, sums to 128, +// all co-efficients must be even. +DECLARE_ALIGNED(16, static const int16_t, gauss_filter[8]) = { 0, 8, 30, 52, + 30, 8, 0, 0 }; +static AOM_INLINE void gaussian_blur(const int bit_depth, + const YV12_BUFFER_CONFIG *source, + const YV12_BUFFER_CONFIG *dst) { + const int block_size = BLOCK_128X128; + const int block_w = mi_size_wide[block_size] * 4; + const int block_h = mi_size_high[block_size] * 4; + const int num_cols = (source->y_width + block_w - 1) / block_w; + const int num_rows = (source->y_height + block_h - 1) / block_h; + int row, col; + + ConvolveParams conv_params = get_conv_params(0, 0, bit_depth); + InterpFilterParams filter = { .filter_ptr = gauss_filter, + .taps = 8, + .subpel_shifts = 0, + .interp_filter = EIGHTTAP_REGULAR }; + + for (row = 0; row < num_rows; ++row) { + for (col = 0; col < num_cols; ++col) { + const int row_offset_y = row * block_h; + const int col_offset_y = col * block_w; + + uint8_t *src_buf = + source->y_buffer + row_offset_y * source->y_stride + col_offset_y; + uint8_t *dst_buf = + dst->y_buffer + row_offset_y * dst->y_stride + col_offset_y; + + if (bit_depth > 8) { + av1_highbd_convolve_2d_sr( + CONVERT_TO_SHORTPTR(src_buf), source->y_stride, + CONVERT_TO_SHORTPTR(dst_buf), dst->y_stride, block_w, block_h, + &filter, &filter, 0, 0, &conv_params, bit_depth); + } else { + av1_convolve_2d_sr(src_buf, source->y_stride, dst_buf, dst->y_stride, + block_w, block_h, &filter, &filter, 0, 0, + &conv_params); + } + } + } +} + +static double frame_average_variance(const AV1_COMP *const cpi, + const YV12_BUFFER_CONFIG *const frame) { + const uint8_t *const y_buffer = frame->y_buffer; + const int y_stride = frame->y_stride; + const BLOCK_SIZE block_size = BLOCK_64X64; + + const int block_w = mi_size_wide[block_size] * 4; + const int block_h = mi_size_high[block_size] * 4; + int row, col; + const int bit_depth = cpi->td.mb.e_mbd.bd; + double var = 0.0, var_count = 0.0; + + // Loop through each block. + for (row = 0; row < frame->y_height / block_h; ++row) { + for (col = 0; col < frame->y_width / block_w; ++col) { + struct buf_2d buf; + const int row_offset_y = row * block_h; + const int col_offset_y = col * block_w; + + buf.buf = (uint8_t *)y_buffer + row_offset_y * y_stride + col_offset_y; + buf.stride = y_stride; + + if (bit_depth > 8) { + var += av1_high_get_sby_perpixel_variance(cpi, &buf, block_size, + bit_depth); + } else { + var += av1_get_sby_perpixel_variance(cpi, &buf, block_size); + } + var_count += 1.0; + } + } + var /= var_count; + return var; +} + +static double cal_approx_vmaf(const AV1_COMP *const cpi, double source_variance, + YV12_BUFFER_CONFIG *const source, + YV12_BUFFER_CONFIG *const sharpened) { + const int bit_depth = cpi->td.mb.e_mbd.bd; + double new_vmaf; + aom_calc_vmaf(cpi->oxcf.vmaf_model_path, source, sharpened, bit_depth, + &new_vmaf); + const double sharpened_var = frame_average_variance(cpi, sharpened); + return source_variance / sharpened_var * (new_vmaf - kBaselineVmaf); +} + +static double find_best_frame_unsharp_amount_loop( + const AV1_COMP *const cpi, YV12_BUFFER_CONFIG *const source, + YV12_BUFFER_CONFIG *const blurred, YV12_BUFFER_CONFIG *const sharpened, + double best_vmaf, const double baseline_variance, + const double unsharp_amount_start, const double step_size, + const int max_loop_count, const double max_amount) { + const double min_amount = 0.0; + int loop_count = 0; + double approx_vmaf = best_vmaf; + double unsharp_amount = unsharp_amount_start; + do { + best_vmaf = approx_vmaf; + unsharp_amount += step_size; + if (unsharp_amount > max_amount || unsharp_amount < min_amount) break; + unsharp(cpi, source, blurred, sharpened, unsharp_amount); + approx_vmaf = cal_approx_vmaf(cpi, baseline_variance, source, sharpened); + + loop_count++; + } while (approx_vmaf > best_vmaf && loop_count < max_loop_count); + unsharp_amount = + approx_vmaf > best_vmaf ? unsharp_amount : unsharp_amount - step_size; + return AOMMIN(max_amount, AOMMAX(unsharp_amount, min_amount)); +} + +static double find_best_frame_unsharp_amount(const AV1_COMP *const cpi, + YV12_BUFFER_CONFIG *const source, + YV12_BUFFER_CONFIG *const blurred, + const double unsharp_amount_start, + const double step_size, + const int max_loop_count, + const double max_filter_amount) { + const AV1_COMMON *const cm = &cpi->common; + const int width = source->y_width; + const int height = source->y_height; + + YV12_BUFFER_CONFIG sharpened; + memset(&sharpened, 0, sizeof(sharpened)); + aom_alloc_frame_buffer( + &sharpened, width, height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + + const double baseline_variance = frame_average_variance(cpi, source); + double unsharp_amount; + if (unsharp_amount_start <= step_size) { + unsharp_amount = find_best_frame_unsharp_amount_loop( + cpi, source, blurred, &sharpened, 0.0, baseline_variance, 0.0, + step_size, max_loop_count, max_filter_amount); + } else { + double a0 = unsharp_amount_start - step_size, a1 = unsharp_amount_start; + double v0, v1; + unsharp(cpi, source, blurred, &sharpened, a0); + v0 = cal_approx_vmaf(cpi, baseline_variance, source, &sharpened); + unsharp(cpi, source, blurred, &sharpened, a1); + v1 = cal_approx_vmaf(cpi, baseline_variance, source, &sharpened); + if (fabs(v0 - v1) < 0.01) { + unsharp_amount = a0; + } else if (v0 > v1) { + unsharp_amount = find_best_frame_unsharp_amount_loop( + cpi, source, blurred, &sharpened, v0, baseline_variance, a0, + -step_size, max_loop_count, max_filter_amount); + } else { + unsharp_amount = find_best_frame_unsharp_amount_loop( + cpi, source, blurred, &sharpened, v1, baseline_variance, a1, + step_size, max_loop_count, max_filter_amount); + } + } + + aom_free_frame_buffer(&sharpened); + return unsharp_amount; +} + +void av1_vmaf_frame_preprocessing(AV1_COMP *const cpi, + YV12_BUFFER_CONFIG *const source) { + aom_clear_system_state(); + const AV1_COMMON *const cm = &cpi->common; + const int bit_depth = cpi->td.mb.e_mbd.bd; + const int width = source->y_width; + const int height = source->y_height; + + YV12_BUFFER_CONFIG source_extended, blurred; + memset(&source_extended, 0, sizeof(source_extended)); + memset(&blurred, 0, sizeof(blurred)); + aom_alloc_frame_buffer( + &source_extended, width, height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + aom_alloc_frame_buffer( + &blurred, width, height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + + av1_copy_and_extend_frame(source, &source_extended); + gaussian_blur(bit_depth, &source_extended, &blurred); + aom_free_frame_buffer(&source_extended); + + const double best_frame_unsharp_amount = find_best_frame_unsharp_amount( + cpi, source, &blurred, cpi->last_frame_unsharp_amount, 0.05, 20, 1.01); + cpi->last_frame_unsharp_amount = best_frame_unsharp_amount; + + unsharp(cpi, source, &blurred, source, best_frame_unsharp_amount); + aom_free_frame_buffer(&blurred); + aom_clear_system_state(); +} + +void av1_vmaf_blk_preprocessing(AV1_COMP *const cpi, + YV12_BUFFER_CONFIG *const source) { + aom_clear_system_state(); + const AV1_COMMON *const cm = &cpi->common; + const int width = source->y_width; + const int height = source->y_height; + const int bit_depth = cpi->td.mb.e_mbd.bd; + + YV12_BUFFER_CONFIG source_extended, blurred; + memset(&blurred, 0, sizeof(blurred)); + memset(&source_extended, 0, sizeof(source_extended)); + aom_alloc_frame_buffer( + &blurred, width, height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + aom_alloc_frame_buffer( + &source_extended, width, height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + + av1_copy_and_extend_frame(source, &source_extended); + gaussian_blur(bit_depth, &source_extended, &blurred); + aom_free_frame_buffer(&source_extended); + + const double best_frame_unsharp_amount = find_best_frame_unsharp_amount( + cpi, source, &blurred, cpi->last_frame_unsharp_amount, 0.05, 20, 1.01); + cpi->last_frame_unsharp_amount = best_frame_unsharp_amount; + + const int block_size = BLOCK_64X64; + const int block_w = mi_size_wide[block_size] * 4; + const int block_h = mi_size_high[block_size] * 4; + const int num_cols = (source->y_width + block_w - 1) / block_w; + const int num_rows = (source->y_height + block_h - 1) / block_h; + double *best_unsharp_amounts = + aom_malloc(sizeof(*best_unsharp_amounts) * num_cols * num_rows); + memset(best_unsharp_amounts, 0, + sizeof(*best_unsharp_amounts) * num_cols * num_rows); + + YV12_BUFFER_CONFIG source_block, blurred_block; + memset(&source_block, 0, sizeof(source_block)); + memset(&blurred_block, 0, sizeof(blurred_block)); + aom_alloc_frame_buffer( + &source_block, block_w, block_h, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + aom_alloc_frame_buffer( + &blurred_block, block_w, block_h, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + + for (int row = 0; row < num_rows; ++row) { + for (int col = 0; col < num_cols; ++col) { + const int row_offset_y = row * block_h; + const int col_offset_y = col * block_w; + const int block_width = AOMMIN(width - col_offset_y, block_w); + const int block_height = AOMMIN(height - row_offset_y, block_h); + const int index = col + row * num_cols; + + if (bit_depth > 8) { + uint16_t *frame_src_buf = CONVERT_TO_SHORTPTR(source->y_buffer) + + row_offset_y * source->y_stride + + col_offset_y; + uint16_t *frame_blurred_buf = CONVERT_TO_SHORTPTR(blurred.y_buffer) + + row_offset_y * blurred.y_stride + + col_offset_y; + uint16_t *blurred_dst = CONVERT_TO_SHORTPTR(blurred_block.y_buffer); + uint16_t *src_dst = CONVERT_TO_SHORTPTR(source_block.y_buffer); + + // Copy block from source frame. + for (int i = 0; i < block_h; ++i) { + for (int j = 0; j < block_w; ++j) { + if (i >= block_height || j >= block_width) { + src_dst[j] = 0; + blurred_dst[j] = 0; + } else { + src_dst[j] = frame_src_buf[j]; + blurred_dst[j] = frame_blurred_buf[j]; + } + } + frame_src_buf += source->y_stride; + frame_blurred_buf += blurred.y_stride; + src_dst += source_block.y_stride; + blurred_dst += blurred_block.y_stride; + } + } else { + uint8_t *frame_src_buf = + source->y_buffer + row_offset_y * source->y_stride + col_offset_y; + uint8_t *frame_blurred_buf = + blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y; + uint8_t *blurred_dst = blurred_block.y_buffer; + uint8_t *src_dst = source_block.y_buffer; + + // Copy block from source frame. + for (int i = 0; i < block_h; ++i) { + for (int j = 0; j < block_w; ++j) { + if (i >= block_height || j >= block_width) { + src_dst[j] = 0; + blurred_dst[j] = 0; + } else { + src_dst[j] = frame_src_buf[j]; + blurred_dst[j] = frame_blurred_buf[j]; + } + } + frame_src_buf += source->y_stride; + frame_blurred_buf += blurred.y_stride; + src_dst += source_block.y_stride; + blurred_dst += blurred_block.y_stride; + } + } + + best_unsharp_amounts[index] = find_best_frame_unsharp_amount( + cpi, &source_block, &blurred_block, best_frame_unsharp_amount, 0.1, 3, + 1.5); + } + } + + // Apply best blur amounts + for (int row = 0; row < num_rows; ++row) { + for (int col = 0; col < num_cols; ++col) { + const int row_offset_y = row * block_h; + const int col_offset_y = col * block_w; + const int block_width = AOMMIN(source->y_width - col_offset_y, block_w); + const int block_height = AOMMIN(source->y_height - row_offset_y, block_h); + const int index = col + row * num_cols; + + if (bit_depth > 8) { + uint16_t *src_buf = CONVERT_TO_SHORTPTR(source->y_buffer) + + row_offset_y * source->y_stride + col_offset_y; + uint16_t *blurred_buf = CONVERT_TO_SHORTPTR(blurred.y_buffer) + + row_offset_y * blurred.y_stride + col_offset_y; + highbd_unsharp_rect(src_buf, source->y_stride, blurred_buf, + blurred.y_stride, src_buf, source->y_stride, + block_width, block_height, + best_unsharp_amounts[index], bit_depth); + } else { + uint8_t *src_buf = + source->y_buffer + row_offset_y * source->y_stride + col_offset_y; + uint8_t *blurred_buf = + blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y; + unsharp_rect(src_buf, source->y_stride, blurred_buf, blurred.y_stride, + src_buf, source->y_stride, block_width, block_height, + best_unsharp_amounts[index]); + } + } + } + + aom_free_frame_buffer(&source_block); + aom_free_frame_buffer(&blurred_block); + aom_free_frame_buffer(&blurred); + aom_free(best_unsharp_amounts); + aom_clear_system_state(); +} + +typedef struct FrameData { + const YV12_BUFFER_CONFIG *source, *blurred; + int block_w, block_h, num_rows, num_cols, row, col, bit_depth; +} FrameData; + +// A callback function used to pass data to VMAF. +// Returns 0 after reading a frame. +// Returns 2 when there is no more frame to read. +static int update_frame(float *ref_data, float *main_data, float *temp_data, + int stride, void *user_data) { + FrameData *frames = (FrameData *)user_data; + const int width = frames->source->y_width; + const int height = frames->source->y_height; + const int row = frames->row; + const int col = frames->col; + const int num_rows = frames->num_rows; + const int num_cols = frames->num_cols; + const int block_w = frames->block_w; + const int block_h = frames->block_h; + const YV12_BUFFER_CONFIG *source = frames->source; + const YV12_BUFFER_CONFIG *blurred = frames->blurred; + const int bit_depth = frames->bit_depth; + const float scale_factor = 1.0f / (float)(1 << (bit_depth - 8)); + (void)temp_data; + stride /= (int)sizeof(*ref_data); + + for (int i = 0; i < height; ++i) { + float *ref, *main; + ref = ref_data + i * stride; + main = main_data + i * stride; + if (bit_depth == 8) { + uint8_t *src; + src = source->y_buffer + i * source->y_stride; + for (int j = 0; j < width; ++j) { + ref[j] = main[j] = (float)src[j]; + } + } else { + uint16_t *src; + src = CONVERT_TO_SHORTPTR(source->y_buffer) + i * source->y_stride; + for (int j = 0; j < width; ++j) { + ref[j] = main[j] = scale_factor * (float)src[j]; + } + } + } + if (row < num_rows && col < num_cols) { + // Set current block + const int row_offset = row * block_h; + const int col_offset = col * block_w; + const int block_width = AOMMIN(width - col_offset, block_w); + const int block_height = AOMMIN(height - row_offset, block_h); + + float *main_buf = main_data + col_offset + row_offset * stride; + if (bit_depth == 8) { + uint8_t *blurred_buf = + blurred->y_buffer + row_offset * blurred->y_stride + col_offset; + for (int i = 0; i < block_height; ++i) { + for (int j = 0; j < block_width; ++j) { + main_buf[j] = (float)blurred_buf[j]; + } + main_buf += stride; + blurred_buf += blurred->y_stride; + } + } else { + uint16_t *blurred_buf = CONVERT_TO_SHORTPTR(blurred->y_buffer) + + row_offset * blurred->y_stride + col_offset; + for (int i = 0; i < block_height; ++i) { + for (int j = 0; j < block_width; ++j) { + main_buf[j] = scale_factor * (float)blurred_buf[j]; + } + main_buf += stride; + blurred_buf += blurred->y_stride; + } + } + + frames->col++; + if (frames->col >= num_cols) { + frames->col = 0; + frames->row++; + } + return 0; + } else { + return 2; + } +} + +void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi) { + AV1_COMMON *cm = &cpi->common; + const int y_width = cpi->source->y_width; + const int y_height = cpi->source->y_height; + const int resized_block_size = BLOCK_32X32; + const int resize_factor = 2; + const int bit_depth = cpi->td.mb.e_mbd.bd; + + aom_clear_system_state(); + YV12_BUFFER_CONFIG resized_source; + memset(&resized_source, 0, sizeof(resized_source)); + aom_alloc_frame_buffer( + &resized_source, y_width / resize_factor, y_height / resize_factor, 1, 1, + cm->seq_params.use_highbitdepth, cpi->oxcf.border_in_pixels, + cm->features.byte_alignment); + av1_resize_and_extend_frame(cpi->source, &resized_source, bit_depth, + av1_num_planes(cm)); + + const int resized_y_width = resized_source.y_width; + const int resized_y_height = resized_source.y_height; + const int resized_block_w = mi_size_wide[resized_block_size] * 4; + const int resized_block_h = mi_size_high[resized_block_size] * 4; + const int num_cols = + (resized_y_width + resized_block_w - 1) / resized_block_w; + const int num_rows = + (resized_y_height + resized_block_h - 1) / resized_block_h; + + YV12_BUFFER_CONFIG blurred; + memset(&blurred, 0, sizeof(blurred)); + aom_alloc_frame_buffer(&blurred, resized_y_width, resized_y_height, 1, 1, + cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, + cm->features.byte_alignment); + gaussian_blur(bit_depth, &resized_source, &blurred); + + double *scores = aom_malloc(sizeof(*scores) * (num_rows * num_cols)); + memset(scores, 0, sizeof(*scores) * (num_rows * num_cols)); + FrameData frame_data; + frame_data.source = &resized_source; + frame_data.blurred = &blurred; + frame_data.block_w = resized_block_w; + frame_data.block_h = resized_block_h; + frame_data.num_rows = num_rows; + frame_data.num_cols = num_cols; + frame_data.row = 0; + frame_data.col = 0; + frame_data.bit_depth = bit_depth; + aom_calc_vmaf_multi_frame(&frame_data, cpi->oxcf.vmaf_model_path, + update_frame, resized_y_width, resized_y_height, + bit_depth, scores); + + // Loop through each 'block_size' block. + for (int row = 0; row < num_rows; ++row) { + for (int col = 0; col < num_cols; ++col) { + const int index = row * num_cols + col; + const int row_offset_y = row * resized_block_h; + const int col_offset_y = col * resized_block_w; + + uint8_t *const orig_buf = resized_source.y_buffer + + row_offset_y * resized_source.y_stride + + col_offset_y; + uint8_t *const blurred_buf = + blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y; + + const double vmaf = scores[index]; + const double dvmaf = kBaselineVmaf - vmaf; + unsigned int sse; + cpi->fn_ptr[resized_block_size].vf(orig_buf, resized_source.y_stride, + blurred_buf, blurred.y_stride, &sse); + + const double mse = + (double)sse / (double)(resized_y_width * resized_y_height); + double weight; + const double eps = 0.01 / (num_rows * num_cols); + if (dvmaf < eps || mse < eps) { + weight = 1.0; + } else { + weight = mse / dvmaf; + } + + // Normalize it with a data fitted model. + weight = 6.0 * (1.0 - exp(-0.05 * weight)) + 0.8; + cpi->vmaf_rdmult_scaling_factors[index] = weight; + } + } + + aom_free_frame_buffer(&resized_source); + aom_free_frame_buffer(&blurred); + aom_free(scores); + aom_clear_system_state(); +} + +void av1_set_vmaf_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x, + const BLOCK_SIZE bsize, const int mi_row, + const int mi_col, int *const rdmult) { + const AV1_COMMON *const cm = &cpi->common; + + const int bsize_base = BLOCK_64X64; + const int num_mi_w = mi_size_wide[bsize_base]; + const int num_mi_h = mi_size_high[bsize_base]; + const int num_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w; + const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h; + const int num_bcols = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w; + const int num_brows = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h; + int row, col; + double num_of_mi = 0.0; + double geom_mean_of_scale = 0.0; + + aom_clear_system_state(); + for (row = mi_row / num_mi_w; + row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) { + for (col = mi_col / num_mi_h; + col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) { + const int index = row * num_cols + col; + geom_mean_of_scale += log(cpi->vmaf_rdmult_scaling_factors[index]); + num_of_mi += 1.0; + } + } + geom_mean_of_scale = exp(geom_mean_of_scale / num_of_mi); + + *rdmult = (int)((double)(*rdmult) * geom_mean_of_scale + 0.5); + *rdmult = AOMMAX(*rdmult, 0); + set_error_per_bit(x, *rdmult); + aom_clear_system_state(); +} + +// TODO(sdeng): replace them with the SIMD versions. +static AOM_INLINE double highbd_image_sad_c(const uint16_t *src, int src_stride, + const uint16_t *ref, int ref_stride, + int w, int h) { + double accum = 0.0; + int i, j; + + for (i = 0; i < h; ++i) { + for (j = 0; j < w; ++j) { + double img1px = src[i * src_stride + j]; + double img2px = ref[i * ref_stride + j]; + + accum += fabs(img1px - img2px); + } + } + + return accum / (double)(h * w); +} + +static AOM_INLINE double image_sad_c(const uint8_t *src, int src_stride, + const uint8_t *ref, int ref_stride, int w, + int h) { + double accum = 0.0; + int i, j; + + for (i = 0; i < h; ++i) { + for (j = 0; j < w; ++j) { + double img1px = src[i * src_stride + j]; + double img2px = ref[i * ref_stride + j]; + + accum += fabs(img1px - img2px); + } + } + + return accum / (double)(h * w); +} + +static AOM_INLINE double calc_vmaf_motion_score( + const AV1_COMP *const cpi, const AV1_COMMON *const cm, + const YV12_BUFFER_CONFIG *const cur, const YV12_BUFFER_CONFIG *const last, + const YV12_BUFFER_CONFIG *const next) { + const int y_width = cur->y_width; + const int y_height = cur->y_height; + YV12_BUFFER_CONFIG blurred_cur, blurred_last, blurred_next; + const int bit_depth = cpi->td.mb.e_mbd.bd; + + memset(&blurred_cur, 0, sizeof(blurred_cur)); + memset(&blurred_last, 0, sizeof(blurred_last)); + memset(&blurred_next, 0, sizeof(blurred_next)); + + aom_alloc_frame_buffer( + &blurred_cur, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + aom_alloc_frame_buffer( + &blurred_last, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + aom_alloc_frame_buffer( + &blurred_next, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth, + cpi->oxcf.border_in_pixels, cm->features.byte_alignment); + + gaussian_blur(bit_depth, cur, &blurred_cur); + gaussian_blur(bit_depth, last, &blurred_last); + if (next) gaussian_blur(bit_depth, next, &blurred_next); + + double motion1, motion2 = 65536.0; + if (bit_depth > 8) { + const float scale_factor = 1.0f / (float)(1 << (bit_depth - 8)); + motion1 = highbd_image_sad_c(CONVERT_TO_SHORTPTR(blurred_cur.y_buffer), + blurred_cur.y_stride, + CONVERT_TO_SHORTPTR(blurred_last.y_buffer), + blurred_last.y_stride, y_width, y_height) * + scale_factor; + if (next) { + motion2 = highbd_image_sad_c(CONVERT_TO_SHORTPTR(blurred_cur.y_buffer), + blurred_cur.y_stride, + CONVERT_TO_SHORTPTR(blurred_next.y_buffer), + blurred_next.y_stride, y_width, y_height) * + scale_factor; + } + } else { + motion1 = image_sad_c(blurred_cur.y_buffer, blurred_cur.y_stride, + blurred_last.y_buffer, blurred_last.y_stride, y_width, + y_height); + if (next) { + motion2 = image_sad_c(blurred_cur.y_buffer, blurred_cur.y_stride, + blurred_next.y_buffer, blurred_next.y_stride, + y_width, y_height); + } + } + + aom_free_frame_buffer(&blurred_cur); + aom_free_frame_buffer(&blurred_last); + aom_free_frame_buffer(&blurred_next); + + return AOMMIN(motion1, motion2); +} + +// Calculates the new qindex from the VMAF motion score. This is based on the +// observation: when the motion score becomes higher, the VMAF score of the +// same source and distorted frames would become higher. +int av1_get_vmaf_base_qindex(const AV1_COMP *const cpi, int current_qindex) { + const AV1_COMMON *const cm = &cpi->common; + if (cm->current_frame.frame_number == 0 || cpi->oxcf.pass == 1) { + return current_qindex; + } + const int bit_depth = cpi->td.mb.e_mbd.bd; + const double approx_sse = + cpi->last_frame_ysse / + (double)((1 << (bit_depth - 8)) * (1 << (bit_depth - 8))); + const double approx_dvmaf = kBaselineVmaf - cpi->last_frame_vmaf; + const double sse_threshold = + 0.01 * cpi->source->y_width * cpi->source->y_height; + const double vmaf_threshold = 0.01; + if (approx_sse < sse_threshold || approx_dvmaf < vmaf_threshold) { + return current_qindex; + } + aom_clear_system_state(); + const GF_GROUP *gf_group = &cpi->gf_group; + YV12_BUFFER_CONFIG *cur_buf = cpi->source; + int src_index = 0; + if (cm->show_frame == 0) { + src_index = gf_group->arf_src_offset[gf_group->index]; + struct lookahead_entry *cur_entry = + av1_lookahead_peek(cpi->lookahead, src_index, cpi->compressor_stage); + cur_buf = &cur_entry->img; + } + assert(cur_buf); + + const struct lookahead_entry *last_entry = + av1_lookahead_peek(cpi->lookahead, src_index - 1, cpi->compressor_stage); + const struct lookahead_entry *next_entry = + av1_lookahead_peek(cpi->lookahead, src_index + 1, cpi->compressor_stage); + const YV12_BUFFER_CONFIG *next_buf = &next_entry->img; + const YV12_BUFFER_CONFIG *last_buf = + cm->show_frame ? cpi->last_source : &last_entry->img; + + assert(last_buf); + + const double motion = + calc_vmaf_motion_score(cpi, cm, cur_buf, last_buf, next_buf); + + // Get dVMAF through a data fitted model. + const double dvmaf = 26.11 * (1.0 - exp(-0.06 * motion)); + const double dsse = dvmaf * approx_sse / approx_dvmaf; + + const double beta = approx_sse / (dsse + approx_sse); + const int offset = av1_get_deltaq_offset(cpi, current_qindex, beta); + int qindex = current_qindex + offset; + + qindex = AOMMIN(qindex, MAXQ); + qindex = AOMMAX(qindex, MINQ); + + aom_clear_system_state(); + return qindex; +} + +void av1_update_vmaf_curve(AV1_COMP *cpi, YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *recon) { + const int bit_depth = cpi->td.mb.e_mbd.bd; + aom_calc_vmaf(cpi->oxcf.vmaf_model_path, source, recon, bit_depth, + &cpi->last_frame_vmaf); + if (bit_depth > 8) { + cpi->last_frame_ysse = (double)aom_highbd_get_y_sse(source, recon); + } else { + cpi->last_frame_ysse = (double)aom_get_y_sse(source, recon); + } +} diff --git a/media/libaom/src/av1/encoder/tune_vmaf.h b/media/libaom/src/av1/encoder/tune_vmaf.h new file mode 100644 index 0000000000..c4cf072242 --- /dev/null +++ b/media/libaom/src/av1/encoder/tune_vmaf.h @@ -0,0 +1,32 @@ +/* + * 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_TUNE_VMAF_H_ +#define AOM_AV1_ENCODER_TUNE_VMAF_H_ + +#include "aom_scale/yv12config.h" +#include "av1/encoder/encoder.h" + +void av1_vmaf_blk_preprocessing(AV1_COMP *cpi, YV12_BUFFER_CONFIG *source); + +void av1_vmaf_frame_preprocessing(AV1_COMP *cpi, YV12_BUFFER_CONFIG *source); + +void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi); + +void av1_set_vmaf_rdmult(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, + int mi_row, int mi_col, int *rdmult); + +int av1_get_vmaf_base_qindex(const AV1_COMP *cpi, int current_qindex); + +void av1_update_vmaf_curve(AV1_COMP *cpi, YV12_BUFFER_CONFIG *source, + YV12_BUFFER_CONFIG *recon); + +#endif // AOM_AV1_ENCODER_TUNE_VMAF_H_ diff --git a/media/libaom/src/av1/encoder/tx_search.c b/media/libaom/src/av1/encoder/tx_search.c new file mode 100644 index 0000000000..65b9a24726 --- /dev/null +++ b/media/libaom/src/av1/encoder/tx_search.c @@ -0,0 +1,3602 @@ +/* + * Copyright (c) 2020, Alliance for Open Media. All rights reserved + * + * This source code is subject to the terms of the BSD 2 Clause License and + * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License + * was not distributed with this source code in the LICENSE file, you can + * obtain it at www.aomedia.org/license/software. If the Alliance for Open + * Media Patent License 1.0 was not distributed with this source code in the + * PATENTS file, you can obtain it at www.aomedia.org/license/patent. + */ + +#include "av1/common/cfl.h" +#include "av1/common/reconintra.h" +#include "av1/encoder/encodetxb.h" +#include "av1/encoder/hybrid_fwd_txfm.h" +#include "av1/common/idct.h" +#include "av1/encoder/model_rd.h" +#include "av1/encoder/random.h" +#include "av1/encoder/rdopt_utils.h" +#include "av1/encoder/tx_prune_model_weights.h" +#include "av1/encoder/tx_search.h" + +struct rdcost_block_args { + const AV1_COMP *cpi; + MACROBLOCK *x; + ENTROPY_CONTEXT t_above[MAX_MIB_SIZE]; + ENTROPY_CONTEXT t_left[MAX_MIB_SIZE]; + RD_STATS rd_stats; + int64_t current_rd; + int64_t best_rd; + int exit_early; + int incomplete_exit; + int use_fast_coef_costing; + FAST_TX_SEARCH_MODE ftxs_mode; + int skip_trellis; +}; + +typedef struct { + int64_t rd; + int txb_entropy_ctx; + TX_TYPE tx_type; +} TxCandidateInfo; + +typedef struct { + int leaf; + int8_t children[4]; +} RD_RECORD_IDX_NODE; + +// 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, +}; + +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. + for (int i = cur_record->index_start - 1; i >= 0; i--) { + if (cur_record->hash_vals[i] == hash) return i; + } + for (int i = cur_record->num - 1; i >= cur_record->index_start; i--) { + if (cur_record->hash_vals[i] == hash) return i; + } + int index; + // If not found - add new RD info into the buffer and return its index + if (cur_record->num < TX_SIZE_RD_RECORD_BUFFER_LEN) { + index = (cur_record->index_start + cur_record->num) % + TX_SIZE_RD_RECORD_BUFFER_LEN; + cur_record->num++; + } else { + index = cur_record->index_start; + cur_record->index_start = + (cur_record->index_start + 1) % TX_SIZE_RD_RECORD_BUFFER_LEN; + } + + cur_record->hash_vals[index] = hash; + av1_zero(cur_record->tx_rd_info[index]); + return index; +} + +static const RD_RECORD_IDX_NODE rd_record_tree_8x8[] = { + { 1, { 0 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_8x16[] = { + { 0, { 1, 2, -1, -1 } }, + { 1, { 0, 0, 0, 0 } }, + { 1, { 0, 0, 0, 0 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_16x8[] = { + { 0, { 1, 2, -1, -1 } }, + { 1, { 0 } }, + { 1, { 0 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_16x16[] = { + { 0, { 1, 2, 3, 4 } }, { 1, { 0 } }, { 1, { 0 } }, { 1, { 0 } }, { 1, { 0 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_1_2[] = { + { 0, { 1, 2, -1, -1 } }, + { 0, { 3, 4, 5, 6 } }, + { 0, { 7, 8, 9, 10 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_2_1[] = { + { 0, { 1, 2, -1, -1 } }, + { 0, { 3, 4, 7, 8 } }, + { 0, { 5, 6, 9, 10 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_sqr[] = { + { 0, { 1, 2, 3, 4 } }, { 0, { 5, 6, 9, 10 } }, { 0, { 7, 8, 11, 12 } }, + { 0, { 13, 14, 17, 18 } }, { 0, { 15, 16, 19, 20 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_64x128[] = { + { 0, { 2, 3, 4, 5 } }, { 0, { 6, 7, 8, 9 } }, + { 0, { 10, 11, 14, 15 } }, { 0, { 12, 13, 16, 17 } }, + { 0, { 18, 19, 22, 23 } }, { 0, { 20, 21, 24, 25 } }, + { 0, { 26, 27, 30, 31 } }, { 0, { 28, 29, 32, 33 } }, + { 0, { 34, 35, 38, 39 } }, { 0, { 36, 37, 40, 41 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_128x64[] = { + { 0, { 2, 3, 6, 7 } }, { 0, { 4, 5, 8, 9 } }, + { 0, { 10, 11, 18, 19 } }, { 0, { 12, 13, 20, 21 } }, + { 0, { 14, 15, 22, 23 } }, { 0, { 16, 17, 24, 25 } }, + { 0, { 26, 27, 34, 35 } }, { 0, { 28, 29, 36, 37 } }, + { 0, { 30, 31, 38, 39 } }, { 0, { 32, 33, 40, 41 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_128x128[] = { + { 0, { 4, 5, 8, 9 } }, { 0, { 6, 7, 10, 11 } }, + { 0, { 12, 13, 16, 17 } }, { 0, { 14, 15, 18, 19 } }, + { 0, { 20, 21, 28, 29 } }, { 0, { 22, 23, 30, 31 } }, + { 0, { 24, 25, 32, 33 } }, { 0, { 26, 27, 34, 35 } }, + { 0, { 36, 37, 44, 45 } }, { 0, { 38, 39, 46, 47 } }, + { 0, { 40, 41, 48, 49 } }, { 0, { 42, 43, 50, 51 } }, + { 0, { 52, 53, 60, 61 } }, { 0, { 54, 55, 62, 63 } }, + { 0, { 56, 57, 64, 65 } }, { 0, { 58, 59, 66, 67 } }, + { 0, { 68, 69, 76, 77 } }, { 0, { 70, 71, 78, 79 } }, + { 0, { 72, 73, 80, 81 } }, { 0, { 74, 75, 82, 83 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_1_4[] = { + { 0, { 1, -1, 2, -1 } }, + { 0, { 3, 4, -1, -1 } }, + { 0, { 5, 6, -1, -1 } }, +}; + +static const RD_RECORD_IDX_NODE rd_record_tree_4_1[] = { + { 0, { 1, 2, -1, -1 } }, + { 0, { 3, 4, -1, -1 } }, + { 0, { 5, 6, -1, -1 } }, +}; + +static const RD_RECORD_IDX_NODE *rd_record_tree[BLOCK_SIZES_ALL] = { + NULL, // BLOCK_4X4 + NULL, // BLOCK_4X8 + NULL, // BLOCK_8X4 + rd_record_tree_8x8, // BLOCK_8X8 + rd_record_tree_8x16, // BLOCK_8X16 + rd_record_tree_16x8, // BLOCK_16X8 + rd_record_tree_16x16, // BLOCK_16X16 + rd_record_tree_1_2, // BLOCK_16X32 + rd_record_tree_2_1, // BLOCK_32X16 + rd_record_tree_sqr, // BLOCK_32X32 + rd_record_tree_1_2, // BLOCK_32X64 + rd_record_tree_2_1, // BLOCK_64X32 + rd_record_tree_sqr, // BLOCK_64X64 + rd_record_tree_64x128, // BLOCK_64X128 + rd_record_tree_128x64, // BLOCK_128X64 + rd_record_tree_128x128, // BLOCK_128X128 + NULL, // BLOCK_4X16 + NULL, // BLOCK_16X4 + rd_record_tree_1_4, // BLOCK_8X32 + rd_record_tree_4_1, // BLOCK_32X8 + rd_record_tree_1_4, // BLOCK_16X64 + rd_record_tree_4_1, // BLOCK_64X16 +}; + +static const int rd_record_tree_size[BLOCK_SIZES_ALL] = { + 0, // BLOCK_4X4 + 0, // BLOCK_4X8 + 0, // BLOCK_8X4 + sizeof(rd_record_tree_8x8) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X8 + sizeof(rd_record_tree_8x16) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X16 + sizeof(rd_record_tree_16x8) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X8 + sizeof(rd_record_tree_16x16) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X16 + sizeof(rd_record_tree_1_2) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X32 + sizeof(rd_record_tree_2_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X16 + sizeof(rd_record_tree_sqr) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X32 + sizeof(rd_record_tree_1_2) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X64 + sizeof(rd_record_tree_2_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X32 + sizeof(rd_record_tree_sqr) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X64 + sizeof(rd_record_tree_64x128) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X128 + sizeof(rd_record_tree_128x64) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_128X64 + sizeof(rd_record_tree_128x128) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_128X128 + 0, // BLOCK_4X16 + 0, // BLOCK_16X4 + sizeof(rd_record_tree_1_4) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_8X32 + sizeof(rd_record_tree_4_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_32X8 + sizeof(rd_record_tree_1_4) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_16X64 + sizeof(rd_record_tree_4_1) / sizeof(RD_RECORD_IDX_NODE), // BLOCK_64X16 +}; + +static INLINE void init_rd_record_tree(TXB_RD_INFO_NODE *tree, + BLOCK_SIZE bsize) { + const RD_RECORD_IDX_NODE *rd_record = rd_record_tree[bsize]; + const int size = rd_record_tree_size[bsize]; + for (int i = 0; i < size; ++i) { + if (rd_record[i].leaf) { + av1_zero(tree[i].children); + } else { + for (int j = 0; j < 4; ++j) { + const int8_t idx = rd_record[i].children[j]; + tree[i].children[j] = idx > 0 ? &tree[idx] : NULL; + } + } + } +} + +// Go through all TX blocks that could be used in TX size search, compute +// residual hash values for them and find matching RD info that stores previous +// RD search results for these TX blocks. The idea is to prevent repeated +// rate/distortion computations that happen because of the combination of +// partition and TX size search. The resulting RD info records are returned in +// the form of a quadtree for easier access in actual TX size search. +static int find_tx_size_rd_records(MACROBLOCK *x, BLOCK_SIZE bsize, + TXB_RD_INFO_NODE *dst_rd_info) { + TXB_RD_RECORD *rd_records_table[4] = { x->txb_rd_record_8X8, + x->txb_rd_record_16X16, + x->txb_rd_record_32X32, + x->txb_rd_record_64X64 }; + const TX_SIZE max_square_tx_size = max_txsize_lookup[bsize]; + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + + // Hashing is performed only for square TX sizes larger than TX_4X4 + if (max_square_tx_size < TX_8X8) return 0; + const int diff_stride = bw; + const struct macroblock_plane *const p = &x->plane[0]; + const int16_t *diff = &p->src_diff[0]; + init_rd_record_tree(dst_rd_info, bsize); + // Coordinates of the top-left corner of current block within the superblock + // measured in pixels: + const int mi_row = x->e_mbd.mi_row; + const int mi_col = x->e_mbd.mi_col; + const int mi_row_in_sb = (mi_row % MAX_MIB_SIZE) << MI_SIZE_LOG2; + const int mi_col_in_sb = (mi_col % MAX_MIB_SIZE) << MI_SIZE_LOG2; + int cur_rd_info_idx = 0; + int cur_tx_depth = 0; + TX_SIZE cur_tx_size = max_txsize_rect_lookup[bsize]; + while (cur_tx_depth <= MAX_VARTX_DEPTH) { + const int cur_tx_bw = tx_size_wide[cur_tx_size]; + const int cur_tx_bh = tx_size_high[cur_tx_size]; + if (cur_tx_bw < 8 || cur_tx_bh < 8) break; + const TX_SIZE next_tx_size = sub_tx_size_map[cur_tx_size]; + const int tx_size_idx = cur_tx_size - TX_8X8; + for (int row = 0; row < bh; row += cur_tx_bh) { + for (int col = 0; col < bw; col += cur_tx_bw) { + if (cur_tx_bw != cur_tx_bh) { + // Use dummy nodes for all rectangular transforms within the + // TX size search tree. + dst_rd_info[cur_rd_info_idx].rd_info_array = NULL; + } else { + // Get spatial location of this TX block within the superblock + // (measured in cur_tx_bsize units). + const int row_in_sb = (mi_row_in_sb + row) / cur_tx_bh; + const int col_in_sb = (mi_col_in_sb + col) / cur_tx_bw; + + int16_t hash_data[MAX_SB_SQUARE]; + int16_t *cur_hash_row = hash_data; + const int16_t *cur_diff_row = diff + row * diff_stride + col; + for (int i = 0; i < cur_tx_bh; i++) { + memcpy(cur_hash_row, cur_diff_row, sizeof(*hash_data) * cur_tx_bw); + cur_hash_row += cur_tx_bw; + cur_diff_row += diff_stride; + } + const int hash = av1_get_crc32c_value(&x->mb_rd_record.crc_calculator, + (uint8_t *)hash_data, + 2 * cur_tx_bw * cur_tx_bh); + // Find corresponding RD info based on the hash value. + const int record_idx = + row_in_sb * (MAX_MIB_SIZE >> (tx_size_idx + 1)) + col_in_sb; + TXB_RD_RECORD *records = &rd_records_table[tx_size_idx][record_idx]; + int idx = find_tx_size_rd_info(records, hash); + dst_rd_info[cur_rd_info_idx].rd_info_array = + &records->tx_rd_info[idx]; + } + ++cur_rd_info_idx; + } + } + cur_tx_size = next_tx_size; + ++cur_tx_depth; + } + return 1; +} + +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 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 AOM_INLINE 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_array(xd->tx_type_map, tx_rd_info->tx_type_map, n4); + *rd_stats = tx_rd_info->rd_stats; +} + +// Compute the pixel domain distortion from diff on all visible 4x4s in the +// transform block. +static INLINE int64_t pixel_diff_dist(const MACROBLOCK *x, int plane, + int blk_row, int blk_col, + const BLOCK_SIZE plane_bsize, + const BLOCK_SIZE tx_bsize, + unsigned int *block_mse_q8) { + int visible_rows, visible_cols; + const MACROBLOCKD *xd = &x->e_mbd; + get_txb_dimensions(xd, plane, plane_bsize, blk_row, blk_col, tx_bsize, NULL, + NULL, &visible_cols, &visible_rows); + const int diff_stride = block_size_wide[plane_bsize]; + const int16_t *diff = x->plane[plane].src_diff; + + diff += ((blk_row * diff_stride + blk_col) << MI_SIZE_LOG2); + uint64_t sse = + aom_sum_squares_2d_i16(diff, diff_stride, visible_cols, visible_rows); + if (block_mse_q8 != NULL) { + if (visible_cols > 0 && visible_rows > 0) + *block_mse_q8 = + (unsigned int)((256 * sse) / (visible_cols * visible_rows)); + else + *block_mse_q8 = UINT_MAX; + } + return sse; +} + +// 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; + // For faster early skip decision, use dist to compare against threshold so + // that quality risk is less for the skip=1 decision. Otherwise, use mse + // since the fwd_txfm coeff checks will take care of quality + // TODO(any): Use dist to return 0 when predict_skip_level is 1 + int64_t pred_err = (x->predict_skip_level >= 2) ? *dist : mse; + // Predict not to skip when error is larger than threshold. + if (pred_err > mse_thresh) return 0; + // Return as skip otherwise for aggressive early skip + else if (x->predict_skip_level >= 2) + return 1; + + 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 AOM_INLINE 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(xd->tx_type_map, DCT_DCT, sizeof(xd->tx_type_map[0]) * n4); + 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 AOM_INLINE 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_array(tx_rd_info->tx_type_map, xd->tx_type_map, n4); + tx_rd_info->rd_stats = *rd_stats; +} + +static int get_search_init_depth(int mi_width, int mi_height, int is_inter, + const SPEED_FEATURES *sf, + int tx_size_search_method) { + if (tx_size_search_method == USE_LARGESTALL) return MAX_VARTX_DEPTH; + + if (sf->tx_sf.tx_size_search_lgr_block) { + if (mi_width > mi_size_wide[BLOCK_64X64] || + mi_height > mi_size_high[BLOCK_64X64]) + return MAX_VARTX_DEPTH; + } + + if (is_inter) { + return (mi_height != mi_width) + ? sf->tx_sf.inter_tx_size_search_init_depth_rect + : sf->tx_sf.inter_tx_size_search_init_depth_sqr; + } else { + return (mi_height != mi_width) + ? sf->tx_sf.intra_tx_size_search_init_depth_rect + : sf->tx_sf.intra_tx_size_search_init_depth_sqr; + } +} + +static AOM_INLINE void select_tx_block( + const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, + TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, + ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, + RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd, + int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, + TXB_RD_INFO_NODE *rd_info_node); + +// NOTE: CONFIG_COLLECT_RD_STATS has 3 possible values +// 0: Do not collect any RD stats +// 1: Collect RD stats for transform units +// 2: Collect RD stats for partition units +#if CONFIG_COLLECT_RD_STATS + +static AOM_INLINE void get_energy_distribution_fine( + const AV1_COMP *cpi, BLOCK_SIZE bsize, const uint8_t *src, int src_stride, + const uint8_t *dst, int dst_stride, int need_4th, double *hordist, + double *verdist) { + const int bw = block_size_wide[bsize]; + const int bh = block_size_high[bsize]; + unsigned int esq[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + if (bsize < BLOCK_16X16 || (bsize >= BLOCK_4X16 && bsize <= BLOCK_32X8)) { + // Special cases: calculate 'esq' values manually, as we don't have 'vf' + // functions for the 16 (very small) sub-blocks of this block. + const int w_shift = (bw == 4) ? 0 : (bw == 8) ? 1 : (bw == 16) ? 2 : 3; + const int h_shift = (bh == 4) ? 0 : (bh == 8) ? 1 : (bh == 16) ? 2 : 3; + assert(bw <= 32); + assert(bh <= 32); + assert(((bw - 1) >> w_shift) + (((bh - 1) >> h_shift) << 2) == 15); + if (cpi->common.seq_params.use_highbitdepth) { + const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); + const uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); + for (int i = 0; i < bh; ++i) + for (int j = 0; j < bw; ++j) { + const int index = (j >> w_shift) + ((i >> h_shift) << 2); + esq[index] += + (src16[j + i * src_stride] - dst16[j + i * dst_stride]) * + (src16[j + i * src_stride] - dst16[j + i * dst_stride]); + } + } else { + for (int i = 0; i < bh; ++i) + for (int j = 0; j < bw; ++j) { + const int index = (j >> w_shift) + ((i >> h_shift) << 2); + esq[index] += (src[j + i * src_stride] - dst[j + i * dst_stride]) * + (src[j + i * src_stride] - dst[j + i * dst_stride]); + } + } + } else { // Calculate 'esq' values using 'vf' functions on the 16 sub-blocks. + const int f_index = + (bsize < BLOCK_SIZES) ? bsize - BLOCK_16X16 : bsize - BLOCK_8X16; + assert(f_index >= 0 && f_index < BLOCK_SIZES_ALL); + const BLOCK_SIZE subsize = (BLOCK_SIZE)f_index; + assert(block_size_wide[bsize] == 4 * block_size_wide[subsize]); + assert(block_size_high[bsize] == 4 * block_size_high[subsize]); + cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[0]); + cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, + &esq[1]); + cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, + &esq[2]); + cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, + dst_stride, &esq[3]); + src += bh / 4 * src_stride; + dst += bh / 4 * dst_stride; + + cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[4]); + cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, + &esq[5]); + cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, + &esq[6]); + cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, + dst_stride, &esq[7]); + src += bh / 4 * src_stride; + dst += bh / 4 * dst_stride; + + cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[8]); + cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, + &esq[9]); + cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, + &esq[10]); + cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, + dst_stride, &esq[11]); + src += bh / 4 * src_stride; + dst += bh / 4 * dst_stride; + + cpi->fn_ptr[subsize].vf(src, src_stride, dst, dst_stride, &esq[12]); + cpi->fn_ptr[subsize].vf(src + bw / 4, src_stride, dst + bw / 4, dst_stride, + &esq[13]); + cpi->fn_ptr[subsize].vf(src + bw / 2, src_stride, dst + bw / 2, dst_stride, + &esq[14]); + cpi->fn_ptr[subsize].vf(src + 3 * bw / 4, src_stride, dst + 3 * bw / 4, + dst_stride, &esq[15]); + } + + double total = (double)esq[0] + esq[1] + esq[2] + esq[3] + esq[4] + esq[5] + + esq[6] + esq[7] + esq[8] + esq[9] + esq[10] + esq[11] + + esq[12] + esq[13] + esq[14] + esq[15]; + if (total > 0) { + const double e_recip = 1.0 / total; + hordist[0] = ((double)esq[0] + esq[4] + esq[8] + esq[12]) * e_recip; + hordist[1] = ((double)esq[1] + esq[5] + esq[9] + esq[13]) * e_recip; + hordist[2] = ((double)esq[2] + esq[6] + esq[10] + esq[14]) * e_recip; + if (need_4th) { + hordist[3] = ((double)esq[3] + esq[7] + esq[11] + esq[15]) * e_recip; + } + verdist[0] = ((double)esq[0] + esq[1] + esq[2] + esq[3]) * e_recip; + verdist[1] = ((double)esq[4] + esq[5] + esq[6] + esq[7]) * e_recip; + verdist[2] = ((double)esq[8] + esq[9] + esq[10] + esq[11]) * e_recip; + if (need_4th) { + verdist[3] = ((double)esq[12] + esq[13] + esq[14] + esq[15]) * e_recip; + } + } else { + hordist[0] = verdist[0] = 0.25; + hordist[1] = verdist[1] = 0.25; + hordist[2] = verdist[2] = 0.25; + if (need_4th) { + hordist[3] = verdist[3] = 0.25; + } + } +} + +static double get_sse_norm(const int16_t *diff, int stride, int w, int h) { + double sum = 0.0; + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + const int err = diff[j * stride + i]; + sum += err * err; + } + } + assert(w > 0 && h > 0); + return sum / (w * h); +} + +static double get_sad_norm(const int16_t *diff, int stride, int w, int h) { + double sum = 0.0; + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + sum += abs(diff[j * stride + i]); + } + } + assert(w > 0 && h > 0); + return sum / (w * h); +} + +static AOM_INLINE void get_2x2_normalized_sses_and_sads( + const AV1_COMP *const cpi, BLOCK_SIZE tx_bsize, const uint8_t *const src, + int src_stride, const uint8_t *const dst, int dst_stride, + const int16_t *const src_diff, int diff_stride, double *const sse_norm_arr, + double *const sad_norm_arr) { + const BLOCK_SIZE tx_bsize_half = + get_partition_subsize(tx_bsize, PARTITION_SPLIT); + if (tx_bsize_half == BLOCK_INVALID) { // manually calculate stats + const int half_width = block_size_wide[tx_bsize] / 2; + const int half_height = block_size_high[tx_bsize] / 2; + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + const int16_t *const this_src_diff = + src_diff + row * half_height * diff_stride + col * half_width; + if (sse_norm_arr) { + sse_norm_arr[row * 2 + col] = + get_sse_norm(this_src_diff, diff_stride, half_width, half_height); + } + if (sad_norm_arr) { + sad_norm_arr[row * 2 + col] = + get_sad_norm(this_src_diff, diff_stride, half_width, half_height); + } + } + } + } else { // use function pointers to calculate stats + const int half_width = block_size_wide[tx_bsize_half]; + const int half_height = block_size_high[tx_bsize_half]; + const int num_samples_half = half_width * half_height; + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + const uint8_t *const this_src = + src + row * half_height * src_stride + col * half_width; + const uint8_t *const this_dst = + dst + row * half_height * dst_stride + col * half_width; + + if (sse_norm_arr) { + unsigned int this_sse; + cpi->fn_ptr[tx_bsize_half].vf(this_src, src_stride, this_dst, + dst_stride, &this_sse); + sse_norm_arr[row * 2 + col] = (double)this_sse / num_samples_half; + } + + if (sad_norm_arr) { + const unsigned int this_sad = cpi->fn_ptr[tx_bsize_half].sdf( + this_src, src_stride, this_dst, dst_stride); + sad_norm_arr[row * 2 + col] = (double)this_sad / num_samples_half; + } + } + } + } +} + +#if CONFIG_COLLECT_RD_STATS == 1 +static double get_mean(const int16_t *diff, int stride, int w, int h) { + double sum = 0.0; + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + sum += diff[j * stride + i]; + } + } + assert(w > 0 && h > 0); + return sum / (w * h); +} +static AOM_INLINE void PrintTransformUnitStats( + const AV1_COMP *const cpi, MACROBLOCK *x, const RD_STATS *const rd_stats, + int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + TX_TYPE tx_type, int64_t rd) { + if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return; + + // Generate small sample to restrict output size. + static unsigned int seed = 21743; + if (lcg_rand16(&seed) % 256 > 0) return; + + const char output_file[] = "tu_stats.txt"; + FILE *fout = fopen(output_file, "a"); + if (!fout) return; + + const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size]; + const MACROBLOCKD *const xd = &x->e_mbd; + const int plane = 0; + struct macroblock_plane *const p = &x->plane[plane]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const int txw = tx_size_wide[tx_size]; + const int txh = tx_size_high[tx_size]; + const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; + const int q_step = p->dequant_QTX[1] >> dequant_shift; + const int num_samples = txw * txh; + + const double rate_norm = (double)rd_stats->rate / num_samples; + const double dist_norm = (double)rd_stats->dist / num_samples; + + fprintf(fout, "%g %g", rate_norm, dist_norm); + + const int src_stride = p->src.stride; + const uint8_t *const src = + &p->src.buf[(blk_row * src_stride + blk_col) << MI_SIZE_LOG2]; + const int dst_stride = pd->dst.stride; + const uint8_t *const dst = + &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2]; + unsigned int sse; + cpi->fn_ptr[tx_bsize].vf(src, src_stride, dst, dst_stride, &sse); + const double sse_norm = (double)sse / num_samples; + + const unsigned int sad = + cpi->fn_ptr[tx_bsize].sdf(src, src_stride, dst, dst_stride); + const double sad_norm = (double)sad / num_samples; + + fprintf(fout, " %g %g", sse_norm, sad_norm); + + const int diff_stride = block_size_wide[plane_bsize]; + const int16_t *const src_diff = + &p->src_diff[(blk_row * diff_stride + blk_col) << MI_SIZE_LOG2]; + + double sse_norm_arr[4], sad_norm_arr[4]; + get_2x2_normalized_sses_and_sads(cpi, tx_bsize, src, src_stride, dst, + dst_stride, src_diff, diff_stride, + sse_norm_arr, sad_norm_arr); + for (int i = 0; i < 4; ++i) { + fprintf(fout, " %g", sse_norm_arr[i]); + } + for (int i = 0; i < 4; ++i) { + fprintf(fout, " %g", sad_norm_arr[i]); + } + + const TX_TYPE_1D tx_type_1d_row = htx_tab[tx_type]; + const TX_TYPE_1D tx_type_1d_col = vtx_tab[tx_type]; + + fprintf(fout, " %d %d %d %d %d", q_step, tx_size_wide[tx_size], + tx_size_high[tx_size], tx_type_1d_row, tx_type_1d_col); + + int model_rate; + int64_t model_dist; + model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, tx_bsize, plane, sse, num_samples, + &model_rate, &model_dist); + const double model_rate_norm = (double)model_rate / num_samples; + const double model_dist_norm = (double)model_dist / num_samples; + fprintf(fout, " %g %g", model_rate_norm, model_dist_norm); + + const double mean = get_mean(src_diff, diff_stride, txw, txh); + float hor_corr, vert_corr; + av1_get_horver_correlation_full(src_diff, diff_stride, txw, txh, &hor_corr, + &vert_corr); + fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr); + + double hdist[4] = { 0 }, vdist[4] = { 0 }; + get_energy_distribution_fine(cpi, tx_bsize, src, src_stride, dst, dst_stride, + 1, hdist, vdist); + fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2], + hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]); + + fprintf(fout, " %d %" PRId64, x->rdmult, rd); + + fprintf(fout, "\n"); + fclose(fout); +} +#endif // CONFIG_COLLECT_RD_STATS == 1 + +#if CONFIG_COLLECT_RD_STATS >= 2 +static int64_t get_sse(const AV1_COMP *cpi, const MACROBLOCK *x) { + const AV1_COMMON *cm = &cpi->common; + const int num_planes = av1_num_planes(cm); + const MACROBLOCKD *xd = &x->e_mbd; + const MB_MODE_INFO *mbmi = xd->mi[0]; + int64_t total_sse = 0; + for (int plane = 0; plane < num_planes; ++plane) { + const struct macroblock_plane *const p = &x->plane[plane]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const BLOCK_SIZE bs = get_plane_block_size(mbmi->sb_type, pd->subsampling_x, + pd->subsampling_y); + unsigned int sse; + + if (x->skip_chroma_rd && plane) continue; + + cpi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, + &sse); + total_sse += sse; + } + total_sse <<= 4; + return total_sse; +} + +static int get_est_rate_dist(const TileDataEnc *tile_data, BLOCK_SIZE bsize, + int64_t sse, int *est_residue_cost, + int64_t *est_dist) { + aom_clear_system_state(); + const InterModeRdModel *md = &tile_data->inter_mode_rd_models[bsize]; + if (md->ready) { + if (sse < md->dist_mean) { + *est_residue_cost = 0; + *est_dist = sse; + } else { + *est_dist = (int64_t)round(md->dist_mean); + const double est_ld = md->a * sse + md->b; + // Clamp estimated rate cost by INT_MAX / 2. + // TODO(angiebird@google.com): find better solution than clamping. + if (fabs(est_ld) < 1e-2) { + *est_residue_cost = INT_MAX / 2; + } else { + double est_residue_cost_dbl = ((sse - md->dist_mean) / est_ld); + if (est_residue_cost_dbl < 0) { + *est_residue_cost = 0; + } else { + *est_residue_cost = + (int)AOMMIN((int64_t)round(est_residue_cost_dbl), INT_MAX / 2); + } + } + if (*est_residue_cost <= 0) { + *est_residue_cost = 0; + *est_dist = sse; + } + } + return 1; + } + return 0; +} + +static double get_highbd_diff_mean(const uint8_t *src8, int src_stride, + const uint8_t *dst8, int dst_stride, int w, + int h) { + const uint16_t *src = CONVERT_TO_SHORTPTR(src8); + const uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); + double sum = 0.0; + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + const int diff = src[j * src_stride + i] - dst[j * dst_stride + i]; + sum += diff; + } + } + assert(w > 0 && h > 0); + return sum / (w * h); +} + +static double get_diff_mean(const uint8_t *src, int src_stride, + const uint8_t *dst, int dst_stride, int w, int h) { + double sum = 0.0; + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + const int diff = src[j * src_stride + i] - dst[j * dst_stride + i]; + sum += diff; + } + } + assert(w > 0 && h > 0); + return sum / (w * h); +} + +static AOM_INLINE void PrintPredictionUnitStats(const AV1_COMP *const cpi, + const TileDataEnc *tile_data, + MACROBLOCK *x, + const RD_STATS *const rd_stats, + BLOCK_SIZE plane_bsize) { + if (rd_stats->rate == INT_MAX || rd_stats->dist == INT64_MAX) return; + + if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 && + (tile_data == NULL || + !tile_data->inter_mode_rd_models[plane_bsize].ready)) + return; + (void)tile_data; + // Generate small sample to restrict output size. + static unsigned int seed = 95014; + + if ((lcg_rand16(&seed) % (1 << (14 - num_pels_log2_lookup[plane_bsize]))) != + 1) + return; + + const char output_file[] = "pu_stats.txt"; + FILE *fout = fopen(output_file, "a"); + if (!fout) return; + + MACROBLOCKD *const xd = &x->e_mbd; + const int plane = 0; + struct macroblock_plane *const p = &x->plane[plane]; + struct macroblockd_plane *pd = &xd->plane[plane]; + const int diff_stride = block_size_wide[plane_bsize]; + int bw, bh; + get_txb_dimensions(xd, plane, plane_bsize, 0, 0, plane_bsize, NULL, NULL, &bw, + &bh); + const int num_samples = bw * bh; + const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; + const int q_step = p->dequant_QTX[1] >> dequant_shift; + const int shift = (xd->bd - 8); + + const double rate_norm = (double)rd_stats->rate / num_samples; + const double dist_norm = (double)rd_stats->dist / num_samples; + const double rdcost_norm = + (double)RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) / num_samples; + + fprintf(fout, "%g %g %g", rate_norm, dist_norm, rdcost_norm); + + const int src_stride = p->src.stride; + const uint8_t *const src = p->src.buf; + const int dst_stride = pd->dst.stride; + const uint8_t *const dst = pd->dst.buf; + const int16_t *const src_diff = p->src_diff; + + int64_t sse = calculate_sse(xd, p, pd, bw, bh); + const double sse_norm = (double)sse / num_samples; + + const unsigned int sad = + cpi->fn_ptr[plane_bsize].sdf(src, src_stride, dst, dst_stride); + const double sad_norm = + (double)sad / (1 << num_pels_log2_lookup[plane_bsize]); + + fprintf(fout, " %g %g", sse_norm, sad_norm); + + double sse_norm_arr[4], sad_norm_arr[4]; + get_2x2_normalized_sses_and_sads(cpi, plane_bsize, src, src_stride, dst, + dst_stride, src_diff, diff_stride, + sse_norm_arr, sad_norm_arr); + if (shift) { + for (int k = 0; k < 4; ++k) sse_norm_arr[k] /= (1 << (2 * shift)); + for (int k = 0; k < 4; ++k) sad_norm_arr[k] /= (1 << shift); + } + for (int i = 0; i < 4; ++i) { + fprintf(fout, " %g", sse_norm_arr[i]); + } + for (int i = 0; i < 4; ++i) { + fprintf(fout, " %g", sad_norm_arr[i]); + } + + fprintf(fout, " %d %d %d %d", q_step, x->rdmult, bw, bh); + + int model_rate; + int64_t model_dist; + model_rd_sse_fn[MODELRD_CURVFIT](cpi, x, plane_bsize, plane, sse, num_samples, + &model_rate, &model_dist); + const double model_rdcost_norm = + (double)RDCOST(x->rdmult, model_rate, model_dist) / num_samples; + const double model_rate_norm = (double)model_rate / num_samples; + const double model_dist_norm = (double)model_dist / num_samples; + fprintf(fout, " %g %g %g", model_rate_norm, model_dist_norm, + model_rdcost_norm); + + double mean; + if (is_cur_buf_hbd(xd)) { + mean = get_highbd_diff_mean(p->src.buf, p->src.stride, pd->dst.buf, + pd->dst.stride, bw, bh); + } else { + mean = get_diff_mean(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, + bw, bh); + } + mean /= (1 << shift); + float hor_corr, vert_corr; + av1_get_horver_correlation_full(src_diff, diff_stride, bw, bh, &hor_corr, + &vert_corr); + fprintf(fout, " %g %g %g", mean, hor_corr, vert_corr); + + double hdist[4] = { 0 }, vdist[4] = { 0 }; + get_energy_distribution_fine(cpi, plane_bsize, src, src_stride, dst, + dst_stride, 1, hdist, vdist); + fprintf(fout, " %g %g %g %g %g %g %g %g", hdist[0], hdist[1], hdist[2], + hdist[3], vdist[0], vdist[1], vdist[2], vdist[3]); + + if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1) { + assert(tile_data->inter_mode_rd_models[plane_bsize].ready); + const int64_t overall_sse = get_sse(cpi, x); + int est_residue_cost = 0; + int64_t est_dist = 0; + get_est_rate_dist(tile_data, plane_bsize, overall_sse, &est_residue_cost, + &est_dist); + const double est_residue_cost_norm = (double)est_residue_cost / num_samples; + const double est_dist_norm = (double)est_dist / num_samples; + const double est_rdcost_norm = + (double)RDCOST(x->rdmult, est_residue_cost, est_dist) / num_samples; + fprintf(fout, " %g %g %g", est_residue_cost_norm, est_dist_norm, + est_rdcost_norm); + } + + fprintf(fout, "\n"); + fclose(fout); +} +#endif // CONFIG_COLLECT_RD_STATS >= 2 +#endif // CONFIG_COLLECT_RD_STATS + +static AOM_INLINE void inverse_transform_block_facade(MACROBLOCKD *xd, + int plane, int block, + int blk_row, int blk_col, + int eob, + int reduced_tx_set) { + if (!eob) return; + + struct macroblockd_plane *const pd = &xd->plane[plane]; + tran_low_t *dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); + const PLANE_TYPE plane_type = get_plane_type(plane); + const TX_SIZE tx_size = av1_get_tx_size(plane, xd); + const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, + tx_size, reduced_tx_set); + const int dst_stride = pd->dst.stride; + uint8_t *dst = &pd->dst.buf[(blk_row * dst_stride + blk_col) << MI_SIZE_LOG2]; + av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, dst, + dst_stride, eob, reduced_tx_set); +} + +static INLINE void recon_intra(const AV1_COMP *cpi, MACROBLOCK *x, int plane, + int block, int blk_row, int blk_col, + BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + const TXB_CTX *const txb_ctx, int skip_trellis, + TX_TYPE best_tx_type, int do_quant, + int *rate_cost, uint16_t best_eob) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + const int is_inter = is_inter_block(mbmi); + if (!is_inter && best_eob && + (blk_row + tx_size_high_unit[tx_size] < mi_size_high[plane_bsize] || + blk_col + tx_size_wide_unit[tx_size] < mi_size_wide[plane_bsize])) { + // if the quantized coefficients are stored in the dqcoeff buffer, we don't + // need to do transform and quantization again. + if (do_quant) { + TxfmParam txfm_param_intra; + QUANT_PARAM quant_param_intra; + av1_setup_xform(cm, x, tx_size, best_tx_type, &txfm_param_intra); + av1_setup_quant(tx_size, !skip_trellis, + skip_trellis + ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B + : AV1_XFORM_QUANT_FP) + : AV1_XFORM_QUANT_FP, + cpi->oxcf.quant_b_adapt, &quant_param_intra); + av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, best_tx_type, + &quant_param_intra); + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, + &txfm_param_intra, &quant_param_intra); + if (quant_param_intra.use_optimize_b) { + av1_optimize_b(cpi, x, plane, block, tx_size, best_tx_type, txb_ctx, + cpi->sf.rd_sf.trellis_eob_fast, rate_cost); + } + } + + inverse_transform_block_facade(xd, plane, block, blk_row, blk_col, + x->plane[plane].eobs[block], + cm->features.reduced_tx_set_used); + + // This may happen because of hash collision. The eob stored in the hash + // table is non-zero, but the real eob is zero. We need to make sure tx_type + // is DCT_DCT in this case. + if (plane == 0 && x->plane[plane].eobs[block] == 0 && + best_tx_type != DCT_DCT) { + update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); + } + } +} + +static unsigned pixel_dist_visible_only( + const AV1_COMP *const cpi, const MACROBLOCK *x, const uint8_t *src, + const int src_stride, const uint8_t *dst, const int dst_stride, + const BLOCK_SIZE tx_bsize, int txb_rows, int txb_cols, int visible_rows, + int visible_cols) { + unsigned sse; + + if (txb_rows == visible_rows && txb_cols == visible_cols) { + cpi->fn_ptr[tx_bsize].vf(src, src_stride, dst, dst_stride, &sse); + return sse; + } + +#if CONFIG_AV1_HIGHBITDEPTH + const MACROBLOCKD *xd = &x->e_mbd; + if (is_cur_buf_hbd(xd)) { + uint64_t sse64 = aom_highbd_sse_odd_size(src, src_stride, dst, dst_stride, + visible_cols, visible_rows); + return (unsigned int)ROUND_POWER_OF_TWO(sse64, (xd->bd - 8) * 2); + } +#else + (void)x; +#endif + sse = aom_sse_odd_size(src, src_stride, dst, dst_stride, visible_cols, + visible_rows); + return sse; +} + +// Compute the pixel domain distortion from src and dst on all visible 4x4s in +// the +// transform block. +static unsigned pixel_dist(const AV1_COMP *const cpi, const MACROBLOCK *x, + int plane, const uint8_t *src, const int src_stride, + const uint8_t *dst, const int dst_stride, + int blk_row, int blk_col, + const BLOCK_SIZE plane_bsize, + const BLOCK_SIZE tx_bsize) { + int txb_rows, txb_cols, visible_rows, visible_cols; + const MACROBLOCKD *xd = &x->e_mbd; + + get_txb_dimensions(xd, plane, plane_bsize, blk_row, blk_col, tx_bsize, + &txb_cols, &txb_rows, &visible_cols, &visible_rows); + assert(visible_rows > 0); + assert(visible_cols > 0); + + unsigned sse = pixel_dist_visible_only(cpi, x, src, src_stride, dst, + dst_stride, tx_bsize, txb_rows, + txb_cols, visible_rows, visible_cols); + + return sse; +} + +static INLINE int64_t dist_block_px_domain(const AV1_COMP *cpi, MACROBLOCK *x, + int plane, BLOCK_SIZE plane_bsize, + int block, int blk_row, int blk_col, + TX_SIZE tx_size) { + MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblock_plane *const p = &x->plane[plane]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + const uint16_t eob = p->eobs[block]; + const BLOCK_SIZE tx_bsize = txsize_to_bsize[tx_size]; + const int bsw = block_size_wide[tx_bsize]; + const int bsh = block_size_high[tx_bsize]; + const int src_stride = x->plane[plane].src.stride; + const int dst_stride = xd->plane[plane].dst.stride; + // Scale the transform block index to pixel unit. + const int src_idx = (blk_row * src_stride + blk_col) << MI_SIZE_LOG2; + const int dst_idx = (blk_row * dst_stride + blk_col) << MI_SIZE_LOG2; + const uint8_t *src = &x->plane[plane].src.buf[src_idx]; + const uint8_t *dst = &xd->plane[plane].dst.buf[dst_idx]; + const tran_low_t *dqcoeff = pd->dqcoeff + BLOCK_OFFSET(block); + + assert(cpi != NULL); + assert(tx_size_wide_log2[0] == tx_size_high_log2[0]); + + uint8_t *recon; + DECLARE_ALIGNED(16, uint16_t, recon16[MAX_TX_SQUARE]); + +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) { + recon = CONVERT_TO_BYTEPTR(recon16); + av1_highbd_convolve_2d_copy_sr(CONVERT_TO_SHORTPTR(dst), dst_stride, + CONVERT_TO_SHORTPTR(recon), MAX_TX_SIZE, bsw, + bsh, NULL, NULL, 0, 0, NULL, xd->bd); + } else { + recon = (uint8_t *)recon16; + av1_convolve_2d_copy_sr(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh, NULL, + NULL, 0, 0, NULL); + } +#else + recon = (uint8_t *)recon16; + av1_convolve_2d_copy_sr(dst, dst_stride, recon, MAX_TX_SIZE, bsw, bsh, NULL, + NULL, 0, 0, NULL); +#endif + + const PLANE_TYPE plane_type = get_plane_type(plane); + TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size, + cpi->common.features.reduced_tx_set_used); + av1_inverse_transform_block(xd, dqcoeff, plane, tx_type, tx_size, recon, + MAX_TX_SIZE, eob, + cpi->common.features.reduced_tx_set_used); + + return 16 * pixel_dist(cpi, x, plane, src, src_stride, recon, MAX_TX_SIZE, + blk_row, blk_col, plane_bsize, tx_bsize); +} + +static uint32_t get_intra_txb_hash(MACROBLOCK *x, int plane, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, + TX_SIZE tx_size) { + int16_t tmp_data[64 * 64]; + const int diff_stride = block_size_wide[plane_bsize]; + const int16_t *diff = x->plane[plane].src_diff; + const int16_t *cur_diff_row = diff + 4 * blk_row * diff_stride + 4 * blk_col; + const int txb_w = tx_size_wide[tx_size]; + const int txb_h = tx_size_high[tx_size]; + uint8_t *hash_data = (uint8_t *)cur_diff_row; + if (txb_w != diff_stride) { + int16_t *cur_hash_row = tmp_data; + for (int i = 0; i < txb_h; i++) { + memcpy(cur_hash_row, cur_diff_row, sizeof(*diff) * txb_w); + cur_hash_row += txb_w; + cur_diff_row += diff_stride; + } + hash_data = (uint8_t *)tmp_data; + } + CRC32C *crc = &x->mb_rd_record.crc_calculator; + const uint32_t hash = av1_get_crc32c_value(crc, hash_data, 2 * txb_w * txb_h); + return (hash << 5) + tx_size; +} + +// pruning thresholds for prune_txk_type and prune_txk_type_separ +static const int prune_factors[5] = { 200, 200, 120, 80, 40 }; // scale 1000 +static const int mul_factors[5] = { 80, 80, 70, 50, 30 }; // scale 100 + +static INLINE int is_intra_hash_match(const AV1_COMP *cpi, MACROBLOCK *x, + int plane, int blk_row, int blk_col, + BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + const TXB_CTX *const txb_ctx, + TXB_RD_INFO **intra_txb_rd_info, + const int tx_type_map_idx, + uint16_t *cur_joint_ctx) { + MACROBLOCKD *xd = &x->e_mbd; + assert(cpi->sf.tx_sf.use_intra_txb_hash && + frame_is_intra_only(&cpi->common) && !is_inter_block(xd->mi[0]) && + plane == 0 && tx_size_wide[tx_size] == tx_size_high[tx_size]); + const uint32_t intra_hash = + get_intra_txb_hash(x, plane, blk_row, blk_col, plane_bsize, tx_size); + const int intra_hash_idx = + find_tx_size_rd_info(&x->txb_rd_record_intra, intra_hash); + *intra_txb_rd_info = &x->txb_rd_record_intra.tx_rd_info[intra_hash_idx]; + *cur_joint_ctx = (txb_ctx->dc_sign_ctx << 8) + txb_ctx->txb_skip_ctx; + if ((*intra_txb_rd_info)->entropy_context == *cur_joint_ctx && + x->txb_rd_record_intra.tx_rd_info[intra_hash_idx].valid) { + xd->tx_type_map[tx_type_map_idx] = (*intra_txb_rd_info)->tx_type; + const TX_TYPE ref_tx_type = + av1_get_tx_type(xd, get_plane_type(plane), blk_row, blk_col, tx_size, + cpi->common.features.reduced_tx_set_used); + return (ref_tx_type == (*intra_txb_rd_info)->tx_type); + } + return 0; +} + +// R-D costs are sorted in ascending order. +static INLINE void sort_rd(int64_t rds[], int txk[], int len) { + int i, j, k; + + for (i = 1; i <= len - 1; ++i) { + for (j = 0; j < i; ++j) { + if (rds[j] > rds[i]) { + int64_t temprd; + int tempi; + + temprd = rds[i]; + tempi = txk[i]; + + for (k = i; k > j; k--) { + rds[k] = rds[k - 1]; + txk[k] = txk[k - 1]; + } + + rds[j] = temprd; + txk[j] = tempi; + break; + } + } + } +} + +static INLINE void dist_block_tx_domain(MACROBLOCK *x, int plane, int block, + TX_SIZE tx_size, int64_t *out_dist, + int64_t *out_sse) { + MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblock_plane *const p = &x->plane[plane]; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + // Transform domain distortion computation is more efficient as it does + // not involve an inverse transform, but it is less accurate. + const int buffer_length = av1_get_max_eob(tx_size); + int64_t this_sse; + // TX-domain results need to shift down to Q2/D10 to match pixel + // domain distortion values which are in Q2^2 + int shift = (MAX_TX_SCALE - av1_get_tx_scale(tx_size)) * 2; + const int block_offset = BLOCK_OFFSET(block); + tran_low_t *const coeff = p->coeff + block_offset; + tran_low_t *const dqcoeff = pd->dqcoeff + block_offset; +#if CONFIG_AV1_HIGHBITDEPTH + if (is_cur_buf_hbd(xd)) + *out_dist = av1_highbd_block_error(coeff, dqcoeff, buffer_length, &this_sse, + xd->bd); + else + *out_dist = av1_block_error(coeff, dqcoeff, buffer_length, &this_sse); +#else + *out_dist = av1_block_error(coeff, dqcoeff, buffer_length, &this_sse); +#endif + *out_dist = RIGHT_SIGNED_SHIFT(*out_dist, shift); + *out_sse = RIGHT_SIGNED_SHIFT(this_sse, shift); +} + +uint16_t prune_txk_type_separ(const AV1_COMP *cpi, MACROBLOCK *x, int plane, + int block, TX_SIZE tx_size, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, int *txk_map, + int16_t allowed_tx_mask, int prune_factor, + const TXB_CTX *const txb_ctx, + int reduced_tx_set_used, int64_t ref_best_rd, + int num_sel) { + const AV1_COMMON *cm = &cpi->common; + + int idx; + + int64_t rds_v[4]; + int64_t rds_h[4]; + int idx_v[4] = { 0, 1, 2, 3 }; + int idx_h[4] = { 0, 1, 2, 3 }; + int skip_v[4] = { 0 }; + int skip_h[4] = { 0 }; + const int idx_map[16] = { + DCT_DCT, DCT_ADST, DCT_FLIPADST, V_DCT, + ADST_DCT, ADST_ADST, ADST_FLIPADST, V_ADST, + FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST, + H_DCT, H_ADST, H_FLIPADST, IDTX + }; + + const int sel_pattern_v[16] = { + 0, 0, 1, 1, 0, 2, 1, 2, 2, 0, 3, 1, 3, 2, 3, 3 + }; + const int sel_pattern_h[16] = { + 0, 1, 0, 1, 2, 0, 2, 1, 2, 3, 0, 3, 1, 3, 2, 3 + }; + + QUANT_PARAM quant_param; + TxfmParam txfm_param; + av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); + av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + &quant_param); + int tx_type; + // to ensure we can try ones even outside of ext_tx_set of current block + // this function should only be called for size < 16 + assert(txsize_sqr_up_map[tx_size] <= TX_16X16); + txfm_param.tx_set_type = EXT_TX_SET_ALL16; + + int rate_cost = 0; + int64_t dist = 0, sse = 0; + // evaluate horizontal with vertical DCT + for (idx = 0; idx < 4; ++idx) { + tx_type = idx_map[idx]; + txfm_param.tx_type = tx_type; + + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + + dist_block_tx_domain(x, plane, block, tx_size, &dist, &sse); + + rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type, + txb_ctx, reduced_tx_set_used, 0); + + rds_h[idx] = RDCOST(x->rdmult, rate_cost, dist); + + if ((rds_h[idx] - (rds_h[idx] >> 2)) > ref_best_rd) { + skip_h[idx] = 1; + } + } + sort_rd(rds_h, idx_h, 4); + for (idx = 1; idx < 4; idx++) { + if (rds_h[idx] > rds_h[0] * 1.2) skip_h[idx_h[idx]] = 1; + } + + if (skip_h[idx_h[0]]) return (uint16_t)0xFFFF; + + // evaluate vertical with the best horizontal chosen + rds_v[0] = rds_h[0]; + int start_v = 1, end_v = 4; + const int *idx_map_v = idx_map + idx_h[0]; + + for (idx = start_v; idx < end_v; ++idx) { + tx_type = idx_map_v[idx_v[idx] * 4]; + txfm_param.tx_type = tx_type; + + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + + dist_block_tx_domain(x, plane, block, tx_size, &dist, &sse); + + rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type, + txb_ctx, reduced_tx_set_used, 0); + + rds_v[idx] = RDCOST(x->rdmult, rate_cost, dist); + + if ((rds_v[idx] - (rds_v[idx] >> 2)) > ref_best_rd) { + skip_v[idx] = 1; + } + } + sort_rd(rds_v, idx_v, 4); + for (idx = 1; idx < 4; idx++) { + if (rds_v[idx] > rds_v[0] * 1.2) skip_v[idx_v[idx]] = 1; + } + + // combine rd_h and rd_v to prune tx candidates + int i_v, i_h; + int64_t rds[16]; + int num_cand = 0, last = TX_TYPES - 1; + + for (int i = 0; i < 16; i++) { + i_v = sel_pattern_v[i]; + i_h = sel_pattern_h[i]; + tx_type = idx_map[idx_v[i_v] * 4 + idx_h[i_h]]; + if (!(allowed_tx_mask & (1 << tx_type)) || skip_h[idx_h[i_h]] || + skip_v[idx_v[i_v]]) { + txk_map[last] = tx_type; + last--; + } else { + txk_map[num_cand] = tx_type; + rds[num_cand] = rds_v[i_v] + rds_h[i_h]; + if (rds[num_cand] == 0) rds[num_cand] = 1; + num_cand++; + } + } + sort_rd(rds, txk_map, num_cand); + + uint16_t prune = (uint16_t)(~(1 << txk_map[0])); + num_sel = AOMMIN(num_sel, num_cand); + + for (int i = 1; i < num_sel; i++) { + int64_t factor = 1800 * (rds[i] - rds[0]) / (rds[0]); + if (factor < (int64_t)prune_factor) + prune &= ~(1 << txk_map[i]); + else + break; + } + return prune; +} + +uint16_t prune_txk_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, + int block, TX_SIZE tx_size, int blk_row, int blk_col, + BLOCK_SIZE plane_bsize, int *txk_map, + uint16_t allowed_tx_mask, int prune_factor, + const TXB_CTX *const txb_ctx, int reduced_tx_set_used) { + const AV1_COMMON *cm = &cpi->common; + int tx_type; + + int64_t rds[TX_TYPES]; + + int num_cand = 0; + int last = TX_TYPES - 1; + + TxfmParam txfm_param; + QUANT_PARAM quant_param; + av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); + av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + &quant_param); + + for (int idx = 0; idx < TX_TYPES; idx++) { + tx_type = idx; + int rate_cost = 0; + int64_t dist = 0, sse = 0; + if (!(allowed_tx_mask & (1 << tx_type))) { + txk_map[last] = tx_type; + last--; + continue; + } + txfm_param.tx_type = tx_type; + + // do txfm and quantization + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + // estimate rate cost + rate_cost = av1_cost_coeffs_txb_laplacian(x, plane, block, tx_size, tx_type, + txb_ctx, reduced_tx_set_used, 0); + // tx domain dist + dist_block_tx_domain(x, plane, block, tx_size, &dist, &sse); + + txk_map[num_cand] = tx_type; + rds[num_cand] = RDCOST(x->rdmult, rate_cost, dist); + if (rds[num_cand] == 0) rds[num_cand] = 1; + num_cand++; + } + + if (num_cand == 0) return (uint16_t)0xFFFF; + + sort_rd(rds, txk_map, num_cand); + uint16_t prune = (uint16_t)(~(1 << txk_map[0])); + + // 0 < prune_factor <= 1000 controls aggressiveness + int64_t factor = 0; + for (int idx = 1; idx < num_cand; idx++) { + factor = 1000 * (rds[idx] - rds[0]) / rds[0]; + if (factor < (int64_t)prune_factor) + prune &= ~(1 << txk_map[idx]); + else + break; + } + return prune; +} + +// These thresholds were calibrated to provide a certain number of TX types +// pruned by the model on average, i.e. selecting a threshold with index i +// will lead to pruning i+1 TX types on average +static const float *prune_2D_adaptive_thresholds[] = { + // TX_4X4 + (float[]){ 0.00549f, 0.01306f, 0.02039f, 0.02747f, 0.03406f, 0.04065f, + 0.04724f, 0.05383f, 0.06067f, 0.06799f, 0.07605f, 0.08533f, + 0.09778f, 0.11780f }, + // TX_8X8 + (float[]){ 0.00037f, 0.00183f, 0.00525f, 0.01038f, 0.01697f, 0.02502f, + 0.03381f, 0.04333f, 0.05286f, 0.06287f, 0.07434f, 0.08850f, + 0.10803f, 0.14124f }, + // TX_16X16 + (float[]){ 0.01404f, 0.02000f, 0.04211f, 0.05164f, 0.05798f, 0.06335f, + 0.06897f, 0.07629f, 0.08875f, 0.11169f }, + // TX_32X32 + NULL, + // TX_64X64 + NULL, + // TX_4X8 + (float[]){ 0.00183f, 0.00745f, 0.01428f, 0.02185f, 0.02966f, 0.03723f, + 0.04456f, 0.05188f, 0.05920f, 0.06702f, 0.07605f, 0.08704f, + 0.10168f, 0.12585f }, + // TX_8X4 + (float[]){ 0.00085f, 0.00476f, 0.01135f, 0.01892f, 0.02698f, 0.03528f, + 0.04358f, 0.05164f, 0.05994f, 0.06848f, 0.07849f, 0.09021f, + 0.10583f, 0.13123f }, + // TX_8X16 + (float[]){ 0.00037f, 0.00232f, 0.00671f, 0.01257f, 0.01965f, 0.02722f, + 0.03552f, 0.04382f, 0.05237f, 0.06189f, 0.07336f, 0.08728f, + 0.10730f, 0.14221f }, + // TX_16X8 + (float[]){ 0.00061f, 0.00330f, 0.00818f, 0.01453f, 0.02185f, 0.02966f, + 0.03772f, 0.04578f, 0.05383f, 0.06262f, 0.07288f, 0.08582f, + 0.10339f, 0.13464f }, + // TX_16X32 + NULL, + // TX_32X16 + NULL, + // TX_32X64 + NULL, + // TX_64X32 + NULL, + // TX_4X16 + (float[]){ 0.00232f, 0.00671f, 0.01257f, 0.01941f, 0.02673f, 0.03430f, + 0.04211f, 0.04968f, 0.05750f, 0.06580f, 0.07507f, 0.08655f, + 0.10242f, 0.12878f }, + // TX_16X4 + (float[]){ 0.00110f, 0.00525f, 0.01208f, 0.01990f, 0.02795f, 0.03601f, + 0.04358f, 0.05115f, 0.05896f, 0.06702f, 0.07629f, 0.08752f, + 0.10217f, 0.12610f }, + // TX_8X32 + NULL, + // TX_32X8 + NULL, + // TX_16X64 + NULL, + // TX_64X16 + NULL, +}; + +// Probablities are sorted in descending order. +static INLINE void sort_probability(float prob[], int txk[], int len) { + int i, j, k; + + for (i = 1; i <= len - 1; ++i) { + for (j = 0; j < i; ++j) { + if (prob[j] < prob[i]) { + float temp; + int tempi; + + temp = prob[i]; + tempi = txk[i]; + + for (k = i; k > j; k--) { + prob[k] = prob[k - 1]; + txk[k] = txk[k - 1]; + } + + prob[j] = temp; + txk[j] = tempi; + break; + } + } + } +} + +static INLINE float get_adaptive_thresholds(TX_SIZE tx_size, + TxSetType tx_set_type, + TX_TYPE_PRUNE_MODE prune_mode) { + const int prune_aggr_table[4][2] = { { 4, 1 }, { 6, 3 }, { 9, 6 }, { 9, 6 } }; + int pruning_aggressiveness = 0; + if (tx_set_type == EXT_TX_SET_ALL16) + pruning_aggressiveness = + prune_aggr_table[prune_mode - PRUNE_2D_ACCURATE][0]; + else if (tx_set_type == EXT_TX_SET_DTT9_IDTX_1DDCT) + pruning_aggressiveness = + prune_aggr_table[prune_mode - PRUNE_2D_ACCURATE][1]; + + return prune_2D_adaptive_thresholds[tx_size][pruning_aggressiveness]; +} + +static AOM_INLINE void get_energy_distribution_finer(const int16_t *diff, + int stride, int bw, int bh, + float *hordist, + float *verdist) { + // First compute downscaled block energy values (esq); downscale factors + // are defined by w_shift and h_shift. + unsigned int esq[256]; + const int w_shift = bw <= 8 ? 0 : 1; + const int h_shift = bh <= 8 ? 0 : 1; + const int esq_w = bw >> w_shift; + const int esq_h = bh >> h_shift; + const int esq_sz = esq_w * esq_h; + int i, j; + memset(esq, 0, esq_sz * sizeof(esq[0])); + if (w_shift) { + for (i = 0; i < bh; i++) { + unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w; + const int16_t *cur_diff_row = diff + i * stride; + for (j = 0; j < bw; j += 2) { + cur_esq_row[j >> 1] += (cur_diff_row[j] * cur_diff_row[j] + + cur_diff_row[j + 1] * cur_diff_row[j + 1]); + } + } + } else { + for (i = 0; i < bh; i++) { + unsigned int *cur_esq_row = esq + (i >> h_shift) * esq_w; + const int16_t *cur_diff_row = diff + i * stride; + for (j = 0; j < bw; j++) { + cur_esq_row[j] += cur_diff_row[j] * cur_diff_row[j]; + } + } + } + + uint64_t total = 0; + for (i = 0; i < esq_sz; i++) total += esq[i]; + + // Output hordist and verdist arrays are normalized 1D projections of esq + if (total == 0) { + float hor_val = 1.0f / esq_w; + for (j = 0; j < esq_w - 1; j++) hordist[j] = hor_val; + float ver_val = 1.0f / esq_h; + for (i = 0; i < esq_h - 1; i++) verdist[i] = ver_val; + return; + } + + const float e_recip = 1.0f / (float)total; + memset(hordist, 0, (esq_w - 1) * sizeof(hordist[0])); + memset(verdist, 0, (esq_h - 1) * sizeof(verdist[0])); + const unsigned int *cur_esq_row; + for (i = 0; i < esq_h - 1; i++) { + cur_esq_row = esq + i * esq_w; + for (j = 0; j < esq_w - 1; j++) { + hordist[j] += (float)cur_esq_row[j]; + verdist[i] += (float)cur_esq_row[j]; + } + verdist[i] += (float)cur_esq_row[j]; + } + cur_esq_row = esq + i * esq_w; + for (j = 0; j < esq_w - 1; j++) hordist[j] += (float)cur_esq_row[j]; + + for (j = 0; j < esq_w - 1; j++) hordist[j] *= e_recip; + for (i = 0; i < esq_h - 1; i++) verdist[i] *= e_recip; +} + +static void prune_tx_2D(MACROBLOCK *x, BLOCK_SIZE bsize, TX_SIZE tx_size, + int blk_row, int blk_col, TxSetType tx_set_type, + TX_TYPE_PRUNE_MODE prune_mode, int *txk_map, + uint16_t *allowed_tx_mask) { + int tx_type_table_2D[16] = { + DCT_DCT, DCT_ADST, DCT_FLIPADST, V_DCT, + ADST_DCT, ADST_ADST, ADST_FLIPADST, V_ADST, + FLIPADST_DCT, FLIPADST_ADST, FLIPADST_FLIPADST, V_FLIPADST, + H_DCT, H_ADST, H_FLIPADST, IDTX + }; + if (tx_set_type != EXT_TX_SET_ALL16 && + tx_set_type != EXT_TX_SET_DTT9_IDTX_1DDCT) + return; +#if CONFIG_NN_V2 + NN_CONFIG_V2 *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size]; + NN_CONFIG_V2 *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size]; +#else + const NN_CONFIG *nn_config_hor = av1_tx_type_nnconfig_map_hor[tx_size]; + const NN_CONFIG *nn_config_ver = av1_tx_type_nnconfig_map_ver[tx_size]; +#endif + if (!nn_config_hor || !nn_config_ver) return; // Model not established yet. + + aom_clear_system_state(); + float hfeatures[16], vfeatures[16]; + float hscores[4], vscores[4]; + float scores_2D_raw[16]; + float scores_2D[16]; + const int bw = tx_size_wide[tx_size]; + const int bh = tx_size_high[tx_size]; + const int hfeatures_num = bw <= 8 ? bw : bw / 2; + const int vfeatures_num = bh <= 8 ? bh : bh / 2; + assert(hfeatures_num <= 16); + assert(vfeatures_num <= 16); + + const struct macroblock_plane *const p = &x->plane[0]; + const int diff_stride = block_size_wide[bsize]; + const int16_t *diff = p->src_diff + 4 * blk_row * diff_stride + 4 * blk_col; + get_energy_distribution_finer(diff, diff_stride, bw, bh, hfeatures, + vfeatures); + av1_get_horver_correlation_full(diff, diff_stride, bw, bh, + &hfeatures[hfeatures_num - 1], + &vfeatures[vfeatures_num - 1]); + aom_clear_system_state(); +#if CONFIG_NN_V2 + av1_nn_predict_v2(hfeatures, nn_config_hor, 0, hscores); + av1_nn_predict_v2(vfeatures, nn_config_ver, 0, vscores); +#else + av1_nn_predict(hfeatures, nn_config_hor, 1, hscores); + av1_nn_predict(vfeatures, nn_config_ver, 1, vscores); +#endif + aom_clear_system_state(); + + for (int i = 0; i < 4; i++) { + float *cur_scores_2D = scores_2D_raw + i * 4; + cur_scores_2D[0] = vscores[i] * hscores[0]; + cur_scores_2D[1] = vscores[i] * hscores[1]; + cur_scores_2D[2] = vscores[i] * hscores[2]; + cur_scores_2D[3] = vscores[i] * hscores[3]; + } + + av1_nn_softmax(scores_2D_raw, scores_2D, 16); + + const float score_thresh = + get_adaptive_thresholds(tx_size, tx_set_type, prune_mode); + + // Always keep the TX type with the highest score, prune all others with + // score below score_thresh. + int max_score_i = 0; + float max_score = 0.0f; + uint16_t allow_bitmask = 0; + float sum_score = 0.0; + // Calculate sum of allowed tx type score and Populate allow bit mask based + // on score_thresh and allowed_tx_mask + for (int tx_idx = 0; tx_idx < TX_TYPES; tx_idx++) { + int allow_tx_type = *allowed_tx_mask & (1 << tx_type_table_2D[tx_idx]); + if (scores_2D[tx_idx] > max_score && allow_tx_type) { + max_score = scores_2D[tx_idx]; + max_score_i = tx_idx; + } + if (scores_2D[tx_idx] >= score_thresh && allow_tx_type) { + // Set allow mask based on score_thresh + allow_bitmask |= (1 << tx_type_table_2D[tx_idx]); + + // Accumulate score of allowed tx type + sum_score += scores_2D[tx_idx]; + } + } + if (!((allow_bitmask >> max_score_i) & 0x01)) { + // Set allow mask based on tx type with max score + allow_bitmask |= (1 << tx_type_table_2D[max_score_i]); + sum_score += scores_2D[max_score_i]; + } + // Sort tx type probability of all types + sort_probability(scores_2D, tx_type_table_2D, TX_TYPES); + + // Enable more pruning based on tx type probability and number of allowed tx + // types + if (prune_mode == PRUNE_2D_AGGRESSIVE) { + float temp_score = 0.0; + float score_ratio = 0.0; + int tx_idx, tx_count = 0; + const float inv_sum_score = 100 / sum_score; + // Get allowed tx types based on sorted probability score and tx count + for (tx_idx = 0; tx_idx < TX_TYPES; tx_idx++) { + // Skip the tx type which has more than 30% of cumulative + // probability and allowed tx type count is more than 2 + if (score_ratio > 30.0 && tx_count >= 2) break; + + // Calculate cumulative probability of allowed tx types + if (allow_bitmask & (1 << tx_type_table_2D[tx_idx])) { + // Calculate cumulative probability + temp_score += scores_2D[tx_idx]; + + // Calculate percentage of cumulative probability of allowed tx type + score_ratio = temp_score * inv_sum_score; + tx_count++; + } + } + // Set remaining tx types as pruned + for (; tx_idx < TX_TYPES; tx_idx++) + allow_bitmask &= ~(1 << tx_type_table_2D[tx_idx]); + } + memcpy(txk_map, tx_type_table_2D, sizeof(tx_type_table_2D)); + *allowed_tx_mask = allow_bitmask; +} + +static float get_dev(float mean, double x2_sum, int num) { + const float e_x2 = (float)(x2_sum / num); + const float diff = e_x2 - mean * mean; + const float dev = (diff > 0) ? sqrtf(diff) : 0; + return dev; +} + +// Feature used by the model to predict tx split: the mean and standard +// deviation values of the block and sub-blocks. +static AOM_INLINE void get_mean_dev_features(const int16_t *data, int stride, + int bw, int bh, float *feature) { + const int16_t *const data_ptr = &data[0]; + const int subh = (bh >= bw) ? (bh >> 1) : bh; + const int subw = (bw >= bh) ? (bw >> 1) : bw; + const int num = bw * bh; + const int sub_num = subw * subh; + int feature_idx = 2; + int total_x_sum = 0; + int64_t total_x2_sum = 0; + int blk_idx = 0; + double mean2_sum = 0.0f; + float dev_sum = 0.0f; + + for (int row = 0; row < bh; row += subh) { + for (int col = 0; col < bw; col += subw) { + int x_sum; + int64_t x2_sum; + // TODO(any): Write a SIMD version. Clear registers. + aom_get_blk_sse_sum(data_ptr + row * stride + col, stride, subw, subh, + &x_sum, &x2_sum); + total_x_sum += x_sum; + total_x2_sum += x2_sum; + + aom_clear_system_state(); + const float mean = (float)x_sum / sub_num; + const float dev = get_dev(mean, (double)x2_sum, sub_num); + feature[feature_idx++] = mean; + feature[feature_idx++] = dev; + mean2_sum += (double)(mean * mean); + dev_sum += dev; + blk_idx++; + } + } + + const float lvl0_mean = (float)total_x_sum / num; + feature[0] = lvl0_mean; + feature[1] = get_dev(lvl0_mean, (double)total_x2_sum, num); + + if (blk_idx > 1) { + // Deviation of means. + feature[feature_idx++] = get_dev(lvl0_mean, mean2_sum, blk_idx); + // Mean of deviations. + feature[feature_idx++] = dev_sum / blk_idx; + } +} + +static int ml_predict_tx_split(MACROBLOCK *x, BLOCK_SIZE bsize, int blk_row, + int blk_col, TX_SIZE tx_size) { + const NN_CONFIG *nn_config = av1_tx_split_nnconfig_map[tx_size]; + if (!nn_config) return -1; + + const int diff_stride = block_size_wide[bsize]; + const int16_t *diff = + x->plane[0].src_diff + 4 * blk_row * diff_stride + 4 * blk_col; + const int bw = tx_size_wide[tx_size]; + const int bh = tx_size_high[tx_size]; + aom_clear_system_state(); + + float features[64] = { 0.0f }; + get_mean_dev_features(diff, diff_stride, bw, bh, features); + + float score = 0.0f; + av1_nn_predict(features, nn_config, 1, &score); + aom_clear_system_state(); + + int int_score = (int)(score * 10000); + return clamp(int_score, -80000, 80000); +} + +static INLINE uint16_t +get_tx_mask(const AV1_COMP *cpi, MACROBLOCK *x, int plane, int block, + int blk_row, int blk_col, BLOCK_SIZE plane_bsize, TX_SIZE tx_size, + const TXB_CTX *const txb_ctx, FAST_TX_SEARCH_MODE ftxs_mode, + int64_t ref_best_rd, TX_TYPE *allowed_txk_types, int *txk_map) { + const AV1_COMMON *cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MB_MODE_INFO *mbmi = xd->mi[0]; + const int is_inter = is_inter_block(mbmi); + const int fast_tx_search = ftxs_mode & FTXS_DCT_AND_1D_DCT_ONLY; + // if txk_allowed = TX_TYPES, >1 tx types are allowed, else, if txk_allowed < + // TX_TYPES, only that specific tx type is allowed. + TX_TYPE txk_allowed = TX_TYPES; + + if ((!is_inter && x->use_default_intra_tx_type) || + (is_inter && x->use_default_inter_tx_type)) { + txk_allowed = + get_default_tx_type(0, xd, tx_size, cpi->is_screen_content_type); + } else if (x->rd_model == LOW_TXFM_RD) { + if (plane == 0) txk_allowed = DCT_DCT; + } + + const TxSetType tx_set_type = av1_get_ext_tx_set_type( + tx_size, is_inter, cm->features.reduced_tx_set_used); + + TX_TYPE uv_tx_type = DCT_DCT; + if (plane) { + // tx_type of PLANE_TYPE_UV should be the same as PLANE_TYPE_Y + uv_tx_type = txk_allowed = + av1_get_tx_type(xd, get_plane_type(plane), blk_row, blk_col, tx_size, + cm->features.reduced_tx_set_used); + } + PREDICTION_MODE intra_dir = + mbmi->filter_intra_mode_info.use_filter_intra + ? fimode_to_intradir[mbmi->filter_intra_mode_info.filter_intra_mode] + : mbmi->mode; + uint16_t ext_tx_used_flag = + cpi->sf.tx_sf.tx_type_search.use_reduced_intra_txset && + tx_set_type == EXT_TX_SET_DTT4_IDTX_1DDCT + ? av1_reduced_intra_tx_used_flag[intra_dir] + : av1_ext_tx_used_flag[tx_set_type]; + if (xd->lossless[mbmi->segment_id] || txsize_sqr_up_map[tx_size] > TX_32X32 || + ext_tx_used_flag == 0x0001 || + (is_inter && cpi->oxcf.use_inter_dct_only) || + (!is_inter && cpi->oxcf.use_intra_dct_only)) { + txk_allowed = DCT_DCT; + } + + if (cpi->oxcf.enable_flip_idtx == 0) ext_tx_used_flag &= DCT_ADST_TX_MASK; + + uint16_t allowed_tx_mask = 0; // 1: allow; 0: skip. + if (txk_allowed < TX_TYPES) { + allowed_tx_mask = 1 << txk_allowed; + allowed_tx_mask &= ext_tx_used_flag; + } else if (fast_tx_search) { + allowed_tx_mask = 0x0c01; // V_DCT, H_DCT, DCT_DCT + allowed_tx_mask &= ext_tx_used_flag; + } else { + assert(plane == 0); + allowed_tx_mask = ext_tx_used_flag; + int num_allowed = 0; + const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group); + const int *tx_type_probs = + cpi->frame_probs.tx_type_probs[update_type][tx_size]; + int i; + + if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) { + static const int thresh_arr[2][7] = { { 10, 15, 15, 10, 15, 15, 15 }, + { 10, 17, 17, 10, 17, 17, 17 } }; + const int thresh = + thresh_arr[cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats - 1] + [update_type]; + uint16_t prune = 0; + int max_prob = -1; + int max_idx = 0; + for (i = 0; i < TX_TYPES; i++) { + if (tx_type_probs[i] > max_prob && (allowed_tx_mask & (1 << i))) { + max_prob = tx_type_probs[i]; + max_idx = i; + } + if (tx_type_probs[i] < thresh) prune |= (1 << i); + } + if ((prune >> max_idx) & 0x01) prune &= ~(1 << max_idx); + allowed_tx_mask &= (~prune); + } + for (i = 0; i < TX_TYPES; i++) { + if (allowed_tx_mask & (1 << i)) num_allowed++; + } + assert(num_allowed > 0); + + if (num_allowed > 2 && cpi->sf.tx_sf.tx_type_search.prune_tx_type_est_rd) { + int pf = prune_factors[x->prune_mode]; + int mf = mul_factors[x->prune_mode]; + if (num_allowed <= 7) { + const uint16_t prune = + prune_txk_type(cpi, x, plane, block, tx_size, blk_row, blk_col, + plane_bsize, txk_map, allowed_tx_mask, pf, txb_ctx, + cm->features.reduced_tx_set_used); + allowed_tx_mask &= (~prune); + } else { + const int num_sel = (num_allowed * mf + 50) / 100; + const uint16_t prune = prune_txk_type_separ( + cpi, x, plane, block, tx_size, blk_row, blk_col, plane_bsize, + txk_map, allowed_tx_mask, pf, txb_ctx, + cm->features.reduced_tx_set_used, ref_best_rd, num_sel); + + allowed_tx_mask &= (~prune); + } + } else { + assert(num_allowed > 0); + int allowed_tx_count = (x->prune_mode == PRUNE_2D_AGGRESSIVE) ? 1 : 5; + // !fast_tx_search && txk_end != txk_start && plane == 0 + if (x->prune_mode >= PRUNE_2D_ACCURATE && is_inter && + num_allowed > allowed_tx_count) { + prune_tx_2D(x, plane_bsize, tx_size, blk_row, blk_col, tx_set_type, + x->prune_mode, txk_map, &allowed_tx_mask); + } + } + } + + // Need to have at least one transform type allowed. + if (allowed_tx_mask == 0) { + txk_allowed = (plane ? uv_tx_type : DCT_DCT); + allowed_tx_mask = (1 << txk_allowed); + } + + assert(IMPLIES(txk_allowed < TX_TYPES, allowed_tx_mask == 1 << txk_allowed)); + *allowed_txk_types = txk_allowed; + return allowed_tx_mask; +} + +#if CONFIG_RD_DEBUG +static INLINE void update_txb_coeff_cost(RD_STATS *rd_stats, int plane, + TX_SIZE tx_size, int blk_row, + int blk_col, int txb_coeff_cost) { + (void)blk_row; + (void)blk_col; + (void)tx_size; + rd_stats->txb_coeff_cost[plane] += txb_coeff_cost; + + { + const int txb_h = tx_size_high_unit[tx_size]; + const int txb_w = tx_size_wide_unit[tx_size]; + int idx, idy; + for (idy = 0; idy < txb_h; ++idy) + for (idx = 0; idx < txb_w; ++idx) + rd_stats->txb_coeff_cost_map[plane][blk_row + idy][blk_col + idx] = 0; + + rd_stats->txb_coeff_cost_map[plane][blk_row][blk_col] = txb_coeff_cost; + } + assert(blk_row < TXB_COEFF_COST_MAP_SIZE); + assert(blk_col < TXB_COEFF_COST_MAP_SIZE); +} +#endif + +static INLINE int cost_coeffs(MACROBLOCK *x, int plane, int block, + TX_SIZE tx_size, const TX_TYPE tx_type, + const TXB_CTX *const txb_ctx, + int use_fast_coef_costing, + int reduced_tx_set_used) { +#if TXCOEFF_COST_TIMER + struct aom_usec_timer timer; + aom_usec_timer_start(&timer); +#endif + (void)use_fast_coef_costing; + const int cost = av1_cost_coeffs_txb(x, plane, block, tx_size, tx_type, + txb_ctx, reduced_tx_set_used); +#if TXCOEFF_COST_TIMER + AV1_COMMON *tmp_cm = (AV1_COMMON *)&cpi->common; + aom_usec_timer_mark(&timer); + const int64_t elapsed_time = aom_usec_timer_elapsed(&timer); + tmp_cm->txcoeff_cost_timer += elapsed_time; + ++tmp_cm->txcoeff_cost_count; +#endif + return cost; +} + +// Search for the best transform type for a given transform block. +// This function can be used for both inter and intra, both luma and chroma. +static void search_tx_type(const AV1_COMP *cpi, MACROBLOCK *x, int plane, + int block, int blk_row, int blk_col, + 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, 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]; + MB_MODE_INFO *mbmi = xd->mi[0]; + int64_t best_rd = INT64_MAX; + uint16_t best_eob = 0; + TX_TYPE best_tx_type = DCT_DCT; + int rate_cost = 0; + // The buffer used to swap dqcoeff in macroblockd_plane so we can keep dqcoeff + // of the best tx_type + DECLARE_ALIGNED(32, tran_low_t, this_dqcoeff[MAX_SB_SQUARE]); + tran_low_t *orig_dqcoeff = pd->dqcoeff; + tran_low_t *best_dqcoeff = this_dqcoeff; + const int tx_type_map_idx = + plane ? 0 : blk_row * xd->tx_type_map_stride + blk_col; + av1_invalid_rd_stats(best_rd_stats); + + skip_trellis |= !is_trellis_used(cpi->optimize_seg_arr[xd->mi[0]->segment_id], + DRY_RUN_NORMAL); + + // Hashing based speed feature for intra block. If the hash of the residue + // is found in the hash table, use the previous RD search results stored in + // the table and terminate early. + TXB_RD_INFO *intra_txb_rd_info = NULL; + uint16_t cur_joint_ctx = 0; + const int is_inter = is_inter_block(mbmi); + const int use_intra_txb_hash = + cpi->sf.tx_sf.use_intra_txb_hash && frame_is_intra_only(cm) && + !is_inter && plane == 0 && tx_size_wide[tx_size] == tx_size_high[tx_size]; + if (use_intra_txb_hash) { + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + const int within_border = + mi_row >= xd->tile.mi_row_start && + (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); + if (within_border && + is_intra_hash_match(cpi, x, plane, blk_row, blk_col, plane_bsize, + tx_size, txb_ctx, &intra_txb_rd_info, + tx_type_map_idx, &cur_joint_ctx)) { + best_rd_stats->rate = intra_txb_rd_info->rate; + best_rd_stats->dist = intra_txb_rd_info->dist; + best_rd_stats->sse = intra_txb_rd_info->sse; + best_rd_stats->skip = intra_txb_rd_info->eob == 0; + x->plane[plane].eobs[block] = intra_txb_rd_info->eob; + x->plane[plane].txb_entropy_ctx[block] = + intra_txb_rd_info->txb_entropy_ctx; + best_eob = intra_txb_rd_info->eob; + best_tx_type = intra_txb_rd_info->tx_type; + skip_trellis |= !intra_txb_rd_info->perform_block_coeff_opt; + update_txk_array(xd, blk_row, blk_col, tx_size, best_tx_type); + recon_intra(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, + txb_ctx, skip_trellis, best_tx_type, 1, &rate_cost, best_eob); + pd->dqcoeff = orig_dqcoeff; + return; + } + } + + uint8_t best_txb_ctx = 0; + // txk_allowed = TX_TYPES: >1 tx types are allowed + // txk_allowed < TX_TYPES: only that specific tx type is allowed. + TX_TYPE txk_allowed = TX_TYPES; + int txk_map[TX_TYPES] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + // Bit mask to indicate which transform types are allowed in the RD search. + const uint16_t allowed_tx_mask = + get_tx_mask(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, + txb_ctx, ftxs_mode, ref_best_rd, &txk_allowed, txk_map); + + unsigned int block_mse_q8; + int64_t block_sse = pixel_diff_dist(x, plane, blk_row, blk_col, plane_bsize, + txsize_to_bsize[tx_size], &block_mse_q8); + assert(block_mse_q8 != UINT_MAX); + if (is_cur_buf_hbd(xd)) { + block_sse = ROUND_POWER_OF_TWO(block_sse, (xd->bd - 8) * 2); + block_mse_q8 = ROUND_POWER_OF_TWO(block_mse_q8, (xd->bd - 8) * 2); + } + block_sse *= 16; + const int dequant_shift = (is_cur_buf_hbd(xd)) ? xd->bd - 5 : 3; + const int qstep = x->plane[plane].dequant_QTX[1] >> dequant_shift; + // Use mse / qstep^2 based threshold logic to take decision of R-D + // optimization of 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 + const int perform_block_coeff_opt = + ((uint64_t)block_mse_q8 <= + (uint64_t)x->coeff_opt_dist_threshold * qstep * qstep); + skip_trellis |= !perform_block_coeff_opt; + + // Flag to indicate if distortion should be calculated in transform domain or + // not during iterating through transform type candidates. + // Transform domain distortion is accurate for higher residuals. + // TODO(any): Experiment with variance and mean based thresholds + int use_transform_domain_distortion = + (x->use_transform_domain_distortion > 0) && + (block_mse_q8 >= x->tx_domain_dist_threshold) && + // Any 64-pt transforms only preserves half the coefficients. + // Therefore transform domain distortion is not valid for these + // transform sizes. + txsize_sqr_up_map[tx_size] != TX_64X64; + // Flag to indicate if an extra calculation of distortion in the pixel domain + // should be performed at the end, after the best transform type has been + // decided. + int calc_pixel_domain_distortion_final = + x->use_transform_domain_distortion == 1 && + use_transform_domain_distortion && x->rd_model != LOW_TXFM_RD; + if (calc_pixel_domain_distortion_final && + (txk_allowed < TX_TYPES || allowed_tx_mask == 0x0001)) + calc_pixel_domain_distortion_final = use_transform_domain_distortion = 0; + + const uint16_t *eobs_ptr = x->plane[plane].eobs; + + TxfmParam txfm_param; + QUANT_PARAM quant_param; + av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); + av1_setup_quant(tx_size, !skip_trellis, + skip_trellis ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B + : AV1_XFORM_QUANT_FP) + : AV1_XFORM_QUANT_FP, + cpi->oxcf.quant_b_adapt, &quant_param); + + // Iterate through all transform type candidates. + for (int idx = 0; idx < TX_TYPES; ++idx) { + const TX_TYPE tx_type = (TX_TYPE)txk_map[idx]; + if (!(allowed_tx_mask & (1 << tx_type))) continue; + txfm_param.tx_type = tx_type; + if (av1_use_qmatrix(&cm->quant_params, xd, mbmi->segment_id)) { + av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type, + &quant_param); + } + if (plane == 0) xd->tx_type_map[tx_type_map_idx] = tx_type; + RD_STATS this_rd_stats; + av1_invalid_rd_stats(&this_rd_stats); + + av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, + &quant_param); + + // Calculate rate cost of quantized coefficients. + if (quant_param.use_optimize_b) { + if (cpi->sf.rd_sf.optimize_b_precheck && best_rd < INT64_MAX && + eobs_ptr[block] >= 4) { + // Calculate distortion quickly in transform domain. + dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, + &this_rd_stats.sse); + + const int64_t best_rd_ = AOMMIN(best_rd, ref_best_rd); + const int64_t dist_cost_estimate = + 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, + cpi->sf.rd_sf.trellis_eob_fast, &rate_cost); + } else { + rate_cost = + cost_coeffs(x, plane, block, tx_size, tx_type, txb_ctx, + use_fast_coef_costing, cm->features.reduced_tx_set_used); + } + + // If rd cost based on coeff rate alone is already more than best_rd, + // terminate early. + if (RDCOST(x->rdmult, rate_cost, 0) > best_rd) continue; + + // Calculate distortion. + if (eobs_ptr[block] == 0) { + // When eob is 0, pixel domain distortion is more efficient and accurate. + this_rd_stats.dist = this_rd_stats.sse = block_sse; + } else if (use_transform_domain_distortion) { + dist_block_tx_domain(x, plane, block, tx_size, &this_rd_stats.dist, + &this_rd_stats.sse); + } else { + 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 { + assert(sse_diff < INT64_MAX); + this_rd_stats.dist += sse_diff; + } + this_rd_stats.sse = block_sse; + } + + this_rd_stats.rate = rate_cost; + + const int64_t rd = + RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); + + if (rd < best_rd) { + best_rd = rd; + *best_rd_stats = this_rd_stats; + best_tx_type = tx_type; + best_txb_ctx = x->plane[plane].txb_entropy_ctx[block]; + best_eob = x->plane[plane].eobs[block]; + // Swap dqcoeff buffers + tran_low_t *const tmp_dqcoeff = best_dqcoeff; + best_dqcoeff = pd->dqcoeff; + pd->dqcoeff = tmp_dqcoeff; + } + +#if CONFIG_COLLECT_RD_STATS == 1 + if (plane == 0) { + PrintTransformUnitStats(cpi, x, &this_rd_stats, blk_row, blk_col, + plane_bsize, tx_size, tx_type, rd); + } +#endif // CONFIG_COLLECT_RD_STATS == 1 + +#if COLLECT_TX_SIZE_DATA + // Generate small sample to restrict output size. + static unsigned int seed = 21743; + if (lcg_rand16(&seed) % 200 == 0) { + FILE *fp = NULL; + + if (within_border) { + fp = fopen(av1_tx_size_data_output_file, "a"); + } + + if (fp) { + // Transform info and RD + const int txb_w = tx_size_wide[tx_size]; + const int txb_h = tx_size_high[tx_size]; + + // Residue signal. + const int diff_stride = block_size_wide[plane_bsize]; + struct macroblock_plane *const p = &x->plane[plane]; + const int16_t *src_diff = + &p->src_diff[(blk_row * diff_stride + blk_col) * 4]; + + for (int r = 0; r < txb_h; ++r) { + for (int c = 0; c < txb_w; ++c) { + fprintf(fp, "%d,", src_diff[c]); + } + src_diff += diff_stride; + } + + fprintf(fp, "%d,%d,%d,%" PRId64, txb_w, txb_h, tx_type, rd); + fprintf(fp, "\n"); + fclose(fp); + } + } +#endif // COLLECT_TX_SIZE_DATA + + // If the current best RD cost is much worse than the reference RD cost, + // terminate early. + if (cpi->sf.tx_sf.adaptive_txb_search_level) { + if ((best_rd - (best_rd >> cpi->sf.tx_sf.adaptive_txb_search_level)) > + ref_best_rd) { + break; + } + } + + // Terminate transform type search if the block has been quantized to + // all zero. + if (cpi->sf.tx_sf.tx_type_search.skip_tx_search && !best_eob) break; + } + + assert(best_rd != INT64_MAX); + + best_rd_stats->skip = best_eob == 0; + if (plane == 0) update_txk_array(xd, blk_row, blk_col, tx_size, best_tx_type); + x->plane[plane].txb_entropy_ctx[block] = best_txb_ctx; + x->plane[plane].eobs[block] = best_eob; + + // Point dqcoeff to the quantized coefficients corresponding to the best + // transform type, then we can skip transform and quantization, e.g. in the + // final pixel domain distortion calculation and recon_intra(). + pd->dqcoeff = best_dqcoeff; + + if (calc_pixel_domain_distortion_final && best_eob) { + best_rd_stats->dist = dist_block_px_domain( + cpi, x, plane, plane_bsize, block, blk_row, blk_col, tx_size); + best_rd_stats->sse = block_sse; + } + + if (intra_txb_rd_info != NULL) { + intra_txb_rd_info->valid = 1; + intra_txb_rd_info->entropy_context = cur_joint_ctx; + intra_txb_rd_info->rate = best_rd_stats->rate; + intra_txb_rd_info->dist = best_rd_stats->dist; + intra_txb_rd_info->sse = best_rd_stats->sse; + intra_txb_rd_info->eob = best_eob; + intra_txb_rd_info->txb_entropy_ctx = best_txb_ctx; + intra_txb_rd_info->perform_block_coeff_opt = perform_block_coeff_opt; + if (plane == 0) intra_txb_rd_info->tx_type = best_tx_type; + } + + // Intra mode needs decoded pixels such that the next transform block + // can use them for prediction. + recon_intra(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, + txb_ctx, skip_trellis, best_tx_type, 0, &rate_cost, best_eob); + pd->dqcoeff = orig_dqcoeff; +} + +// Pick transform type for a luma transform block of tx_size. Note this function +// is used only for inter-predicted blocks. +static AOM_INLINE void tx_type_rd(const AV1_COMP *cpi, MACROBLOCK *x, + TX_SIZE tx_size, int blk_row, int blk_col, + int block, int plane_bsize, TXB_CTX *txb_ctx, + RD_STATS *rd_stats, + FAST_TX_SEARCH_MODE ftxs_mode, + int64_t ref_rdcost, + TXB_RD_INFO *rd_info_array) { + const struct macroblock_plane *const p = &x->plane[0]; + const uint16_t cur_joint_ctx = + (txb_ctx->dc_sign_ctx << 8) + txb_ctx->txb_skip_ctx; + MACROBLOCKD *xd = &x->e_mbd; + assert(is_inter_block(xd->mi[0])); + const int tx_type_map_idx = blk_row * xd->tx_type_map_stride + blk_col; + // Look up RD and terminate early in case when we've already processed exactly + // the same residue with exactly the same entropy context. + if (rd_info_array != NULL && rd_info_array->valid && + rd_info_array->entropy_context == cur_joint_ctx) { + xd->tx_type_map[tx_type_map_idx] = rd_info_array->tx_type; + const TX_TYPE ref_tx_type = + av1_get_tx_type(&x->e_mbd, get_plane_type(0), blk_row, blk_col, tx_size, + cpi->common.features.reduced_tx_set_used); + if (ref_tx_type == rd_info_array->tx_type) { + rd_stats->rate += rd_info_array->rate; + rd_stats->dist += rd_info_array->dist; + rd_stats->sse += rd_info_array->sse; + rd_stats->skip &= rd_info_array->eob == 0; + p->eobs[block] = rd_info_array->eob; + p->txb_entropy_ctx[block] = rd_info_array->txb_entropy_ctx; + return; + } + } + + RD_STATS this_rd_stats; + const int skip_trellis = 0; + search_tx_type(cpi, x, 0, block, blk_row, blk_col, plane_bsize, tx_size, + txb_ctx, ftxs_mode, 0, skip_trellis, ref_rdcost, + &this_rd_stats); + + av1_merge_rd_stats(rd_stats, &this_rd_stats); + + // Save RD results for possible reuse in future. + if (rd_info_array != NULL) { + rd_info_array->valid = 1; + rd_info_array->entropy_context = cur_joint_ctx; + rd_info_array->rate = this_rd_stats.rate; + rd_info_array->dist = this_rd_stats.dist; + rd_info_array->sse = this_rd_stats.sse; + rd_info_array->eob = p->eobs[block]; + rd_info_array->txb_entropy_ctx = p->txb_entropy_ctx[block]; + rd_info_array->tx_type = xd->tx_type_map[tx_type_map_idx]; + } +} + +static AOM_INLINE void try_tx_block_no_split( + const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, + TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, + const ENTROPY_CONTEXT *ta, const ENTROPY_CONTEXT *tl, + int txfm_partition_ctx, RD_STATS *rd_stats, int64_t ref_best_rd, + FAST_TX_SEARCH_MODE ftxs_mode, TXB_RD_INFO_NODE *rd_info_node, + TxCandidateInfo *no_split) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + struct macroblock_plane *const p = &x->plane[0]; + const int bw = mi_size_wide[plane_bsize]; + const ENTROPY_CONTEXT *const pta = ta + blk_col; + const ENTROPY_CONTEXT *const ptl = tl + blk_row; + const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); + TXB_CTX txb_ctx; + get_txb_ctx(plane_bsize, tx_size, 0, pta, ptl, &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->zero_rate = zero_blk_rate; + const int index = av1_get_txb_size_index(plane_bsize, blk_row, blk_col); + mbmi->inter_tx_size[index] = tx_size; + tx_type_rd(cpi, x, tx_size, blk_row, blk_col, block, plane_bsize, &txb_ctx, + rd_stats, ftxs_mode, ref_best_rd, + rd_info_node != NULL ? rd_info_node->rd_info_array : NULL); + assert(rd_stats->rate < INT_MAX); + + const int pick_skip = !xd->lossless[mbmi->segment_id] && + (rd_stats->skip == 1 || + RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >= + RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse)); + if (pick_skip) { +#if CONFIG_RD_DEBUG + update_txb_coeff_cost(rd_stats, 0, tx_size, blk_row, blk_col, + zero_blk_rate - rd_stats->rate); +#endif // CONFIG_RD_DEBUG + rd_stats->rate = zero_blk_rate; + rd_stats->dist = rd_stats->sse; + p->eobs[block] = 0; + update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); + } + rd_stats->skip = pick_skip; + set_blk_skip(x, 0, blk_row * bw + blk_col, pick_skip); + + if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) + rd_stats->rate += x->txfm_partition_cost[txfm_partition_ctx][0]; + + no_split->rd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); + no_split->txb_entropy_ctx = p->txb_entropy_ctx[block]; + no_split->tx_type = + xd->tx_type_map[blk_row * xd->tx_type_map_stride + blk_col]; +} + +static AOM_INLINE void try_tx_block_split( + const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, + TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, + ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, + int txfm_partition_ctx, int64_t no_split_rd, int64_t ref_best_rd, + FAST_TX_SEARCH_MODE ftxs_mode, TXB_RD_INFO_NODE *rd_info_node, + RD_STATS *split_rd_stats) { + assert(tx_size < TX_SIZES_ALL); + MACROBLOCKD *const xd = &x->e_mbd; + const int max_blocks_high = max_block_high(xd, plane_bsize, 0); + const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0); + const int txb_width = tx_size_wide_unit[tx_size]; + const int txb_height = tx_size_high_unit[tx_size]; + // Transform size after splitting current block. + const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; + const int sub_txb_width = tx_size_wide_unit[sub_txs]; + const int sub_txb_height = tx_size_high_unit[sub_txs]; + const int sub_step = sub_txb_width * sub_txb_height; + const int nblks = (txb_height / sub_txb_height) * (txb_width / sub_txb_width); + assert(nblks > 0); + av1_init_rd_stats(split_rd_stats); + split_rd_stats->rate = x->txfm_partition_cost[txfm_partition_ctx][1]; + + for (int r = 0, blk_idx = 0; r < txb_height; r += sub_txb_height) { + for (int c = 0; c < txb_width; c += sub_txb_width, ++blk_idx) { + assert(blk_idx < 4); + const int offsetr = blk_row + r; + const int offsetc = blk_col + c; + if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; + + RD_STATS this_rd_stats; + int this_cost_valid = 1; + select_tx_block( + cpi, x, offsetr, offsetc, block, sub_txs, depth + 1, plane_bsize, ta, + tl, tx_above, tx_left, &this_rd_stats, no_split_rd / nblks, + ref_best_rd - split_rd_stats->rdcost, &this_cost_valid, ftxs_mode, + (rd_info_node != NULL) ? rd_info_node->children[blk_idx] : NULL); + if (!this_cost_valid) { + split_rd_stats->rdcost = INT64_MAX; + return; + } + av1_merge_rd_stats(split_rd_stats, &this_rd_stats); + split_rd_stats->rdcost = + RDCOST(x->rdmult, split_rd_stats->rate, split_rd_stats->dist); + if (split_rd_stats->rdcost > ref_best_rd) { + split_rd_stats->rdcost = INT64_MAX; + return; + } + block += sub_step; + } + } +} + +// Search for the best transform partition(recursive)/type for a given +// inter-predicted luma block. The obtained transform selection will be saved +// in xd->mi[0], the corresponding RD stats will be saved in rd_stats. +static AOM_INLINE void select_tx_block( + const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, + TX_SIZE tx_size, int depth, BLOCK_SIZE plane_bsize, ENTROPY_CONTEXT *ta, + ENTROPY_CONTEXT *tl, TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, + RD_STATS *rd_stats, int64_t prev_level_rd, int64_t ref_best_rd, + int *is_cost_valid, FAST_TX_SEARCH_MODE ftxs_mode, + TXB_RD_INFO_NODE *rd_info_node) { + assert(tx_size < TX_SIZES_ALL); + av1_init_rd_stats(rd_stats); + if (ref_best_rd < 0) { + *is_cost_valid = 0; + return; + } + + MACROBLOCKD *const xd = &x->e_mbd; + assert(blk_row < max_block_high(xd, plane_bsize, 0) && + blk_col < max_block_wide(xd, plane_bsize, 0)); + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row, + mbmi->sb_type, tx_size); + struct macroblock_plane *const p = &x->plane[0]; + + const int try_no_split = + cpi->oxcf.enable_tx64 || txsize_sqr_up_map[tx_size] != TX_64X64; + int try_split = tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH; + TxCandidateInfo no_split = { INT64_MAX, 0, TX_TYPES }; + + // Try using current block as a single transform block without split. + if (try_no_split) { + try_tx_block_no_split(cpi, x, blk_row, blk_col, block, tx_size, depth, + plane_bsize, ta, tl, ctx, rd_stats, ref_best_rd, + ftxs_mode, rd_info_node, &no_split); + + // Speed features for early termination. + const int search_level = cpi->sf.tx_sf.adaptive_txb_search_level; + if (search_level) { + if ((no_split.rd - (no_split.rd >> (1 + search_level))) > ref_best_rd) { + *is_cost_valid = 0; + return; + } + if (no_split.rd - (no_split.rd >> (2 + search_level)) > prev_level_rd) { + try_split = 0; + } + } + if (cpi->sf.tx_sf.txb_split_cap) { + if (p->eobs[block] == 0) try_split = 0; + } + } + + // ML based speed feature to skip searching for split transform blocks. + if (x->e_mbd.bd == 8 && try_split && + !(ref_best_rd == INT64_MAX && no_split.rd == INT64_MAX)) { + const int threshold = cpi->sf.tx_sf.tx_type_search.ml_tx_split_thresh; + if (threshold >= 0) { + const int split_score = + ml_predict_tx_split(x, plane_bsize, blk_row, blk_col, tx_size); + if (split_score < -threshold) try_split = 0; + } + } + + RD_STATS split_rd_stats; + split_rd_stats.rdcost = INT64_MAX; + // Try splitting current block into smaller transform blocks. + if (try_split) { + try_tx_block_split(cpi, x, blk_row, blk_col, block, tx_size, depth, + plane_bsize, ta, tl, tx_above, tx_left, ctx, no_split.rd, + AOMMIN(no_split.rd, ref_best_rd), ftxs_mode, + rd_info_node, &split_rd_stats); + } + + if (no_split.rd < split_rd_stats.rdcost) { + ENTROPY_CONTEXT *pta = ta + blk_col; + ENTROPY_CONTEXT *ptl = tl + blk_row; + p->txb_entropy_ctx[block] = no_split.txb_entropy_ctx; + av1_set_txb_context(x, 0, block, tx_size, pta, ptl); + txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size, + tx_size); + for (int idy = 0; idy < tx_size_high_unit[tx_size]; ++idy) { + for (int idx = 0; idx < tx_size_wide_unit[tx_size]; ++idx) { + const int index = + av1_get_txb_size_index(plane_bsize, blk_row + idy, blk_col + idx); + mbmi->inter_tx_size[index] = tx_size; + } + } + mbmi->tx_size = tx_size; + update_txk_array(xd, blk_row, blk_col, tx_size, no_split.tx_type); + const int bw = mi_size_wide[plane_bsize]; + set_blk_skip(x, 0, blk_row * bw + blk_col, rd_stats->skip); + } else { + *rd_stats = split_rd_stats; + if (split_rd_stats.rdcost == INT64_MAX) *is_cost_valid = 0; + } +} + +static AOM_INLINE void choose_largest_tx_size(const AV1_COMP *const cpi, + MACROBLOCK *x, RD_STATS *rd_stats, + int64_t ref_best_rd, + BLOCK_SIZE bs) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + mbmi->tx_size = tx_size_from_tx_mode(bs, x->tx_mode_search_type); + + // If tx64 is not enabled, we need to go down to the next available size + if (!cpi->oxcf.enable_tx64) { + static const TX_SIZE tx_size_max_32[TX_SIZES_ALL] = { + TX_4X4, // 4x4 transform + TX_8X8, // 8x8 transform + TX_16X16, // 16x16 transform + TX_32X32, // 32x32 transform + TX_32X32, // 64x64 transform + TX_4X8, // 4x8 transform + TX_8X4, // 8x4 transform + TX_8X16, // 8x16 transform + TX_16X8, // 16x8 transform + TX_16X32, // 16x32 transform + TX_32X16, // 32x16 transform + TX_32X32, // 32x64 transform + TX_32X32, // 64x32 transform + TX_4X16, // 4x16 transform + TX_16X4, // 16x4 transform + TX_8X32, // 8x32 transform + TX_32X8, // 32x8 transform + TX_16X32, // 16x64 transform + TX_32X16, // 64x16 transform + }; + + mbmi->tx_size = tx_size_max_32[mbmi->tx_size]; + } + + const int skip_ctx = av1_get_skip_context(xd); + const int no_skip_flag_rate = x->skip_cost[skip_ctx][0]; + const int skip_flag_rate = x->skip_cost[skip_ctx][1]; + // Skip RDcost is used only for Inter blocks + const int64_t skip_rd = + is_inter_block(mbmi) ? RDCOST(x->rdmult, skip_flag_rate, 0) : INT64_MAX; + const int64_t no_skip_rd = RDCOST(x->rdmult, no_skip_flag_rate, 0); + const int skip_trellis = 0; + av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, + AOMMIN(no_skip_rd, skip_rd), AOM_PLANE_Y, bs, + mbmi->tx_size, cpi->sf.rd_sf.use_fast_coef_costing, + FTXS_NONE, skip_trellis); +} + +static AOM_INLINE void choose_smallest_tx_size(const AV1_COMP *const cpi, + MACROBLOCK *x, + RD_STATS *rd_stats, + int64_t ref_best_rd, + BLOCK_SIZE bs) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + + mbmi->tx_size = TX_4X4; + // TODO(any) : Pass this_rd based on skip/non-skip cost + const int skip_trellis = 0; + av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, 0, 0, bs, mbmi->tx_size, + cpi->sf.rd_sf.use_fast_coef_costing, FTXS_NONE, + skip_trellis); +} + +// Search for the best uniform transform size and type for current coding block. +static AOM_INLINE void choose_tx_size_type_from_rd(const AV1_COMP *const cpi, + MACROBLOCK *x, + RD_STATS *rd_stats, + int64_t ref_best_rd, + BLOCK_SIZE bs) { + av1_invalid_rd_stats(rd_stats); + + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const TX_SIZE max_rect_tx_size = max_txsize_rect_lookup[bs]; + const int tx_select = x->tx_mode_search_type == TX_MODE_SELECT; + int start_tx; + // The split depth can be at most MAX_TX_DEPTH, so the init_depth controls + // how many times of splitting is allowed during the RD search. + int init_depth; + + if (tx_select) { + start_tx = max_rect_tx_size; + init_depth = get_search_init_depth(mi_size_wide[bs], mi_size_high[bs], + is_inter_block(mbmi), &cpi->sf, + x->tx_size_search_method); + } else { + const TX_SIZE chosen_tx_size = + tx_size_from_tx_mode(bs, x->tx_mode_search_type); + start_tx = chosen_tx_size; + init_depth = MAX_TX_DEPTH; + } + + const int skip_trellis = 0; + uint8_t best_txk_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE]; + uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE]; + TX_SIZE best_tx_size = max_rect_tx_size; + int64_t best_rd = INT64_MAX; + const int num_blks = bsize_to_num_blk(bs); + x->rd_model = FULL_TXFM_RD; + int64_t rd[MAX_TX_DEPTH + 1] = { INT64_MAX, INT64_MAX, INT64_MAX }; + for (int tx_size = start_tx, depth = init_depth; depth <= MAX_TX_DEPTH; + depth++, tx_size = sub_tx_size_map[tx_size]) { + if (!cpi->oxcf.enable_tx64 && txsize_sqr_up_map[tx_size] == TX_64X64) { + continue; + } + + RD_STATS this_rd_stats; + rd[depth] = av1_uniform_txfm_yrd(cpi, x, &this_rd_stats, ref_best_rd, bs, + tx_size, FTXS_NONE, skip_trellis); + if (rd[depth] < best_rd) { + av1_copy_array(best_blk_skip, x->blk_skip, num_blks); + av1_copy_array(best_txk_type_map, xd->tx_type_map, num_blks); + best_tx_size = tx_size; + best_rd = rd[depth]; + *rd_stats = this_rd_stats; + } + if (tx_size == 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) { + mbmi->tx_size = best_tx_size; + av1_copy_array(xd->tx_type_map, best_txk_type_map, num_blks); + av1_copy_array(x->blk_skip, best_blk_skip, num_blks); + } +} + +// Search for the best transform type for the given transform block in the +// given plane/channel, and calculate the corresponding RD cost. +static AOM_INLINE void block_rd_txfm(int plane, int block, int blk_row, + int blk_col, BLOCK_SIZE plane_bsize, + TX_SIZE tx_size, void *arg) { + struct rdcost_block_args *args = arg; + if (args->exit_early) { + args->incomplete_exit = 1; + return; + } + + MACROBLOCK *const x = args->x; + MACROBLOCKD *const xd = &x->e_mbd; + const int is_inter = is_inter_block(xd->mi[0]); + const AV1_COMP *cpi = args->cpi; + ENTROPY_CONTEXT *a = args->t_above + blk_col; + ENTROPY_CONTEXT *l = args->t_left + blk_row; + const AV1_COMMON *cm = &cpi->common; + RD_STATS this_rd_stats; + av1_init_rd_stats(&this_rd_stats); + + if (!is_inter) { + av1_predict_intra_block_facade(cm, xd, plane, blk_col, blk_row, tx_size); + av1_subtract_txb(x, plane, plane_bsize, blk_col, blk_row, tx_size); + } + + TXB_CTX txb_ctx; + get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx); + search_tx_type(cpi, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, + &txb_ctx, args->ftxs_mode, args->use_fast_coef_costing, + args->skip_trellis, args->best_rd - args->current_rd, + &this_rd_stats); + + if (plane == AOM_PLANE_Y && xd->cfl.store_y) { + assert(!is_inter || plane_bsize < BLOCK_8X8); + cfl_store_tx(xd, blk_row, blk_col, tx_size, plane_bsize); + } + +#if CONFIG_RD_DEBUG + update_txb_coeff_cost(&this_rd_stats, plane, tx_size, blk_row, blk_col, + this_rd_stats.rate); +#endif // CONFIG_RD_DEBUG + av1_set_txb_context(x, plane, block, tx_size, a, l); + + const int blk_idx = + blk_row * (block_size_wide[plane_bsize] >> MI_SIZE_LOG2) + blk_col; + if (plane == 0) + set_blk_skip(x, plane, blk_idx, x->plane[plane].eobs[block] == 0); + else + set_blk_skip(x, plane, blk_idx, 0); + + int64_t rd; + if (is_inter) { + const int64_t no_skip_rd = + RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); + const int64_t skip_rd = RDCOST(x->rdmult, 0, this_rd_stats.sse); + rd = AOMMIN(no_skip_rd, skip_rd); + this_rd_stats.skip &= !x->plane[plane].eobs[block]; + } else { + // Signal non-skip for Intra blocks + rd = RDCOST(x->rdmult, this_rd_stats.rate, this_rd_stats.dist); + this_rd_stats.skip = 0; + } + + av1_merge_rd_stats(&args->rd_stats, &this_rd_stats); + + args->current_rd += rd; + if (args->current_rd > args->best_rd) args->exit_early = 1; +} + +// Search for the best transform type and return the transform coefficients RD +// cost of current luma coding block with the given uniform transform size. +int64_t av1_uniform_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, int skip_trellis) { + assert(IMPLIES(is_rect_tx(tx_size), is_rect_tx_allowed_bsize(bs))); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int is_inter = is_inter_block(mbmi); + const int tx_select = x->tx_mode_search_type == TX_MODE_SELECT && + block_signals_txsize(mbmi->sb_type); + int tx_size_rate = 0; + if (tx_select) { + const int ctx = txfm_partition_context( + xd->above_txfm_context, xd->left_txfm_context, mbmi->sb_type, tx_size); + tx_size_rate = is_inter ? x->txfm_partition_cost[ctx][0] + : tx_size_cost(x, bs, tx_size); + } + const int skip_ctx = av1_get_skip_context(xd); + const int no_skip_flag_rate = x->skip_cost[skip_ctx][0]; + const int skip_flag_rate = x->skip_cost[skip_ctx][1]; + const int64_t skip_rd = + is_inter ? RDCOST(x->rdmult, skip_flag_rate, 0) : INT64_MAX; + const int64_t no_this_rd = + RDCOST(x->rdmult, no_skip_flag_rate + tx_size_rate, 0); + + mbmi->tx_size = tx_size; + av1_txfm_rd_in_plane(x, cpi, rd_stats, ref_best_rd, + AOMMIN(no_this_rd, skip_rd), AOM_PLANE_Y, bs, tx_size, + cpi->sf.rd_sf.use_fast_coef_costing, ftxs_mode, + skip_trellis); + if (rd_stats->rate == INT_MAX) return INT64_MAX; + + int64_t rd; + // rdstats->rate should include all the rate except skip/non-skip cost as the + // same is accounted in the caller functions after rd evaluation of all + // planes. However the decisions should be done after considering the + // skip/non-skip header cost + if (rd_stats->skip && is_inter) { + rd = RDCOST(x->rdmult, skip_flag_rate, rd_stats->sse); + } else { + // Intra blocks are always signalled as non-skip + rd = RDCOST(x->rdmult, rd_stats->rate + no_skip_flag_rate + tx_size_rate, + rd_stats->dist); + rd_stats->rate += tx_size_rate; + } + // Check if forcing the block to skip transform leads to smaller RD cost. + if (is_inter && !rd_stats->skip && !xd->lossless[mbmi->segment_id]) { + int64_t temp_skip_rd = RDCOST(x->rdmult, skip_flag_rate, rd_stats->sse); + if (temp_skip_rd <= rd) { + rd = temp_skip_rd; + rd_stats->rate = 0; + rd_stats->dist = rd_stats->sse; + rd_stats->skip = 1; + } + } + + return rd; +} + +// Search for the best transform type for a luma inter-predicted block, given +// the transform block partitions. +// This function is used only when some speed features are enabled. +static AOM_INLINE void tx_block_yrd( + const AV1_COMP *cpi, MACROBLOCK *x, int blk_row, int blk_col, int block, + TX_SIZE tx_size, BLOCK_SIZE plane_bsize, int depth, + ENTROPY_CONTEXT *above_ctx, ENTROPY_CONTEXT *left_ctx, + TXFM_CONTEXT *tx_above, TXFM_CONTEXT *tx_left, int64_t ref_best_rd, + RD_STATS *rd_stats, FAST_TX_SEARCH_MODE ftxs_mode) { + assert(tx_size < TX_SIZES_ALL); + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(is_inter_block(mbmi)); + const int max_blocks_high = max_block_high(xd, plane_bsize, 0); + const int max_blocks_wide = max_block_wide(xd, plane_bsize, 0); + + if (blk_row >= max_blocks_high || blk_col >= max_blocks_wide) return; + + const TX_SIZE plane_tx_size = mbmi->inter_tx_size[av1_get_txb_size_index( + plane_bsize, blk_row, blk_col)]; + const int ctx = txfm_partition_context(tx_above + blk_col, tx_left + blk_row, + mbmi->sb_type, tx_size); + + av1_init_rd_stats(rd_stats); + if (tx_size == plane_tx_size) { + ENTROPY_CONTEXT *ta = above_ctx + blk_col; + ENTROPY_CONTEXT *tl = left_ctx + blk_row; + const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size); + TXB_CTX txb_ctx; + get_txb_ctx(plane_bsize, tx_size, 0, ta, tl, &txb_ctx); + + const int zero_blk_rate = x->coeff_costs[txs_ctx][get_plane_type(0)] + .txb_skip_cost[txb_ctx.txb_skip_ctx][1]; + rd_stats->zero_rate = zero_blk_rate; + tx_type_rd(cpi, x, tx_size, blk_row, blk_col, block, plane_bsize, &txb_ctx, + rd_stats, ftxs_mode, ref_best_rd, NULL); + const int mi_width = mi_size_wide[plane_bsize]; + if (RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist) >= + RDCOST(x->rdmult, zero_blk_rate, rd_stats->sse) || + rd_stats->skip == 1) { + rd_stats->rate = zero_blk_rate; + rd_stats->dist = rd_stats->sse; + rd_stats->skip = 1; + set_blk_skip(x, 0, blk_row * mi_width + blk_col, 1); + x->plane[0].eobs[block] = 0; + x->plane[0].txb_entropy_ctx[block] = 0; + update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT); + } else { + rd_stats->skip = 0; + set_blk_skip(x, 0, blk_row * mi_width + blk_col, 0); + } + if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) + rd_stats->rate += x->txfm_partition_cost[ctx][0]; + av1_set_txb_context(x, 0, block, tx_size, ta, tl); + txfm_partition_update(tx_above + blk_col, tx_left + blk_row, tx_size, + tx_size); + } else { + const TX_SIZE sub_txs = sub_tx_size_map[tx_size]; + const int txb_width = tx_size_wide_unit[sub_txs]; + const int txb_height = tx_size_high_unit[sub_txs]; + const int step = txb_height * txb_width; + RD_STATS pn_rd_stats; + int64_t this_rd = 0; + assert(txb_width > 0 && txb_height > 0); + + for (int row = 0; row < tx_size_high_unit[tx_size]; row += txb_height) { + for (int col = 0; col < tx_size_wide_unit[tx_size]; col += txb_width) { + const int offsetr = blk_row + row; + const int offsetc = blk_col + col; + if (offsetr >= max_blocks_high || offsetc >= max_blocks_wide) continue; + + av1_init_rd_stats(&pn_rd_stats); + tx_block_yrd(cpi, x, offsetr, offsetc, block, sub_txs, plane_bsize, + depth + 1, above_ctx, left_ctx, tx_above, tx_left, + ref_best_rd - this_rd, &pn_rd_stats, ftxs_mode); + if (pn_rd_stats.rate == INT_MAX) { + av1_invalid_rd_stats(rd_stats); + return; + } + av1_merge_rd_stats(rd_stats, &pn_rd_stats); + this_rd += RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist); + block += step; + } + } + + if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH) + rd_stats->rate += x->txfm_partition_cost[ctx][1]; + } +} + +// search for tx type with tx sizes already decided for a inter-predicted luma +// partition block. It's used only when some speed features are enabled. +// Return value 0: early termination triggered, no valid rd cost available; +// 1: rd cost values are valid. +static int inter_block_yrd(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bsize, + int64_t ref_best_rd, FAST_TX_SEARCH_MODE ftxs_mode) { + if (ref_best_rd < 0) { + av1_invalid_rd_stats(rd_stats); + return 0; + } + + av1_init_rd_stats(rd_stats); + + MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblockd_plane *const pd = &xd->plane[0]; + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, bsize, 0); + const int bh = tx_size_high_unit[max_tx_size]; + const int bw = tx_size_wide_unit[max_tx_size]; + const int step = bw * bh; + const int init_depth = get_search_init_depth(mi_width, mi_height, 1, &cpi->sf, + x->tx_size_search_method); + ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; + ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; + TXFM_CONTEXT tx_above[MAX_MIB_SIZE]; + TXFM_CONTEXT tx_left[MAX_MIB_SIZE]; + av1_get_entropy_contexts(bsize, pd, ctxa, ctxl); + memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width); + memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height); + + int64_t this_rd = 0; + for (int idy = 0, block = 0; idy < mi_height; idy += bh) { + for (int idx = 0; idx < mi_width; idx += bw) { + RD_STATS pn_rd_stats; + av1_init_rd_stats(&pn_rd_stats); + tx_block_yrd(cpi, x, idy, idx, block, max_tx_size, bsize, init_depth, + ctxa, ctxl, tx_above, tx_left, ref_best_rd - this_rd, + &pn_rd_stats, ftxs_mode); + if (pn_rd_stats.rate == INT_MAX) { + av1_invalid_rd_stats(rd_stats); + return 0; + } + av1_merge_rd_stats(rd_stats, &pn_rd_stats); + this_rd += + AOMMIN(RDCOST(x->rdmult, pn_rd_stats.rate, pn_rd_stats.dist), + RDCOST(x->rdmult, pn_rd_stats.zero_rate, pn_rd_stats.sse)); + block += step; + } + } + + const int skip_ctx = av1_get_skip_context(xd); + const int no_skip_flag_rate = x->skip_cost[skip_ctx][0]; + const int skip_flag_rate = x->skip_cost[skip_ctx][1]; + const int64_t skip_rd = RDCOST(x->rdmult, skip_flag_rate, rd_stats->sse); + this_rd = + RDCOST(x->rdmult, rd_stats->rate + no_skip_flag_rate, rd_stats->dist); + if (skip_rd < this_rd) { + this_rd = skip_rd; + rd_stats->rate = 0; + rd_stats->dist = rd_stats->sse; + rd_stats->skip = 1; + } + + const int is_cost_valid = this_rd > ref_best_rd; + if (!is_cost_valid) { + // reset cost value + av1_invalid_rd_stats(rd_stats); + } + return is_cost_valid; +} + +// Search for the best transform size and type for current inter-predicted +// luma block with recursive transform block partitioning. The obtained +// transform selection will be saved in xd->mi[0], the corresponding RD stats +// will be saved in rd_stats. The returned value is the corresponding RD cost. +static int64_t select_tx_size_and_type(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bsize, + int64_t ref_best_rd, + TXB_RD_INFO_NODE *rd_info_tree) { + MACROBLOCKD *const xd = &x->e_mbd; + assert(is_inter_block(xd->mi[0])); + assert(bsize < BLOCK_SIZES_ALL); + const int fast_tx_search = x->tx_size_search_method > USE_FULL_RD; + int64_t rd_thresh = ref_best_rd; + if (fast_tx_search && rd_thresh < INT64_MAX) { + if (INT64_MAX - rd_thresh > (rd_thresh >> 3)) rd_thresh += (rd_thresh >> 3); + } + assert(rd_thresh > 0); + const FAST_TX_SEARCH_MODE ftxs_mode = + fast_tx_search ? FTXS_DCT_AND_1D_DCT_ONLY : FTXS_NONE; + const struct macroblockd_plane *const pd = &xd->plane[0]; + assert(bsize < BLOCK_SIZES_ALL); + const int mi_width = mi_size_wide[bsize]; + const int mi_height = mi_size_high[bsize]; + ENTROPY_CONTEXT ctxa[MAX_MIB_SIZE]; + ENTROPY_CONTEXT ctxl[MAX_MIB_SIZE]; + TXFM_CONTEXT tx_above[MAX_MIB_SIZE]; + TXFM_CONTEXT tx_left[MAX_MIB_SIZE]; + av1_get_entropy_contexts(bsize, pd, ctxa, ctxl); + memcpy(tx_above, xd->above_txfm_context, sizeof(TXFM_CONTEXT) * mi_width); + memcpy(tx_left, xd->left_txfm_context, sizeof(TXFM_CONTEXT) * mi_height); + const int init_depth = get_search_init_depth(mi_width, mi_height, 1, &cpi->sf, + x->tx_size_search_method); + const TX_SIZE max_tx_size = max_txsize_rect_lookup[bsize]; + const int bh = tx_size_high_unit[max_tx_size]; + const int bw = tx_size_wide_unit[max_tx_size]; + const int step = bw * bh; + const int skip_ctx = av1_get_skip_context(xd); + const int no_skip_flag_cost = x->skip_cost[skip_ctx][0]; + const int skip_flag_cost = x->skip_cost[skip_ctx][1]; + int64_t skip_rd = RDCOST(x->rdmult, skip_flag_cost, 0); + int64_t no_skip_rd = RDCOST(x->rdmult, no_skip_flag_cost, 0); + int block = 0; + + av1_init_rd_stats(rd_stats); + for (int idy = 0; idy < max_block_high(xd, bsize, 0); idy += bh) { + for (int idx = 0; idx < max_block_wide(xd, bsize, 0); idx += bw) { + const int64_t best_rd_sofar = + (rd_thresh == INT64_MAX) + ? INT64_MAX + : (rd_thresh - (AOMMIN(skip_rd, no_skip_rd))); + int is_cost_valid = 1; + RD_STATS pn_rd_stats; + // Search for the best transform block size and type for the sub-block. + select_tx_block(cpi, x, idy, idx, block, max_tx_size, init_depth, bsize, + ctxa, ctxl, tx_above, tx_left, &pn_rd_stats, INT64_MAX, + best_rd_sofar, &is_cost_valid, ftxs_mode, rd_info_tree); + if (!is_cost_valid || pn_rd_stats.rate == INT_MAX) { + av1_invalid_rd_stats(rd_stats); + return INT64_MAX; + } + av1_merge_rd_stats(rd_stats, &pn_rd_stats); + skip_rd = RDCOST(x->rdmult, skip_flag_cost, rd_stats->sse); + no_skip_rd = + RDCOST(x->rdmult, rd_stats->rate + no_skip_flag_cost, rd_stats->dist); + block += step; + if (rd_info_tree != NULL) rd_info_tree += 1; + } + } + + if (rd_stats->rate == INT_MAX) return INT64_MAX; + + rd_stats->skip = (skip_rd <= no_skip_rd); + + // If fast_tx_search is true, only DCT and 1D DCT were tested in + // select_inter_block_yrd() above. Do a better search for tx type with + // tx sizes already decided. + if (fast_tx_search && cpi->sf.tx_sf.refine_fast_tx_search_results) { + if (!inter_block_yrd(cpi, x, rd_stats, bsize, ref_best_rd, FTXS_NONE)) + return INT64_MAX; + } + + int64_t final_rd; + if (rd_stats->skip) { + final_rd = RDCOST(x->rdmult, skip_flag_cost, rd_stats->sse); + } else { + final_rd = + RDCOST(x->rdmult, rd_stats->rate + no_skip_flag_cost, rd_stats->dist); + if (!xd->lossless[xd->mi[0]->segment_id]) { + final_rd = + AOMMIN(final_rd, RDCOST(x->rdmult, skip_flag_cost, rd_stats->sse)); + } + } + + return final_rd; +} + +// Return 1 to terminate transform search early. The decision is made based on +// the comparison with the reference RD cost and the model-estimated RD cost. +static AOM_INLINE int model_based_tx_search_prune(const AV1_COMP *cpi, + MACROBLOCK *x, + BLOCK_SIZE bsize, + int64_t ref_best_rd) { + const int level = cpi->sf.tx_sf.model_based_prune_tx_search_level; + assert(level >= 0 && level <= 2); + int model_rate; + int64_t model_dist; + int model_skip; + MACROBLOCKD *const xd = &x->e_mbd; + model_rd_sb_fn[MODELRD_TYPE_TX_SEARCH_PRUNE]( + cpi, bsize, x, xd, 0, 0, &model_rate, &model_dist, &model_skip, NULL, + NULL, NULL, NULL); + if (model_skip) return 0; + const int64_t model_rd = RDCOST(x->rdmult, model_rate, model_dist); + // TODO(debargha, urvang): Improve the model and make the check below + // tighter. + static const int prune_factor_by8[] = { 3, 5 }; + const int factor = prune_factor_by8[level - 1]; + return ((model_rd * factor) >> 3) > ref_best_rd; +} + +// Search for best transform size and type for luma inter blocks. The transform +// block partitioning can be recursive resulting in non-uniform transform sizes. +// The best transform size and type, if found, will be saved in the MB_MODE_INFO +// structure, and the corresponding RD stats will be saved in rd_stats. +void av1_pick_recursive_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bsize, + int64_t ref_best_rd) { + MACROBLOCKD *const xd = &x->e_mbd; + assert(is_inter_block(xd->mi[0])); + + av1_invalid_rd_stats(rd_stats); + + // If modeled RD cost is a lot worse than the best so far, terminate early. + if (cpi->sf.tx_sf.model_based_prune_tx_search_level && + ref_best_rd != INT64_MAX) { + if (model_based_tx_search_prune(cpi, x, bsize, ref_best_rd)) return; + } + + // Hashing based speed feature. If the hash of the prediction residue block is + // found in the hash table, use previous search results and terminate early. + uint32_t hash = 0; + MB_RD_RECORD *mb_rd_record = NULL; + const int mi_row = x->e_mbd.mi_row; + const int mi_col = x->e_mbd.mi_col; + const int within_border = + mi_row >= xd->tile.mi_row_start && + (mi_row + mi_size_high[bsize] < xd->tile.mi_row_end) && + mi_col >= xd->tile.mi_col_start && + (mi_col + mi_size_wide[bsize] < xd->tile.mi_col_end); + const int is_mb_rd_hash_enabled = + (within_border && cpi->sf.rd_sf.use_mb_rd_hash); + const int n4 = bsize_to_num_blk(bsize); + if (is_mb_rd_hash_enabled) { + hash = get_block_residue_hash(x, bsize); + mb_rd_record = &x->mb_rd_record; + const int 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; + } + } + + // If we predict that skip is the optimal RD decision - set the respective + // context and terminate early. + int64_t dist; + if (x->predict_skip_level && + predict_skip_flag(x, bsize, &dist, + cpi->common.features.reduced_tx_set_used)) { + set_skip_flag(x, rd_stats, bsize, 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); + return; + } +#if CONFIG_SPEED_STATS + ++x->tx_search_count; +#endif // CONFIG_SPEED_STATS + + // Pre-compute residue hashes (transform block level) and find existing or + // add new RD records to store and reuse rate and distortion values to speed + // up TX size/type search. + TXB_RD_INFO_NODE matched_rd_info[4 + 16 + 64]; + int found_rd_info = 0; + if (ref_best_rd != INT64_MAX && within_border && + cpi->sf.tx_sf.use_inter_txb_hash) { + found_rd_info = find_tx_size_rd_records(x, bsize, matched_rd_info); + } + + const int64_t rd = + select_tx_size_and_type(cpi, x, rd_stats, bsize, ref_best_rd, + found_rd_info ? matched_rd_info : NULL); + + if (rd == INT64_MAX) { + // We should always find at least one candidate unless ref_best_rd is less + // than INT64_MAX (in which case, all the calls to select_tx_size_fix_type + // might have failed to find something better) + assert(ref_best_rd != INT64_MAX); + av1_invalid_rd_stats(rd_stats); + return; + } + + // 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); + } +} + +// Search for the best transform size and type for current coding block, with +// the assumption that all the transform blocks have a uniform size (VP9 style). +// The selected transform size and type will be saved in the MB_MODE_INFO +// structure; the corresponding RD stats will be saved in rd_stats. +// This function may be used for both intra and inter predicted blocks. +void av1_pick_uniform_tx_size_type_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bs, + int64_t ref_best_rd) { + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + assert(bs == mbmi->sb_type); + const int is_inter = is_inter_block(mbmi); + const int mi_row = xd->mi_row; + const int mi_col = xd->mi_col; + + av1_init_rd_stats(rd_stats); + + // Hashing based speed feature for inter blocks. If the hash of the residue + // block is found in the table, use previously saved search results and + // terminate early. + uint32_t hash = 0; + MB_RD_RECORD *mb_rd_record = NULL; + const int num_blks = bsize_to_num_blk(bs); + if (is_inter && cpi->sf.rd_sf.use_mb_rd_hash) { + 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); + if (within_border) { + hash = get_block_residue_hash(x, bs); + mb_rd_record = &x->mb_rd_record; + const int 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(num_blks, tx_rd_info, rd_stats, x); + return; + } + } + } + + // If we predict that skip is the optimal RD decision - set the respective + // context and terminate early. + int64_t dist; + if (x->predict_skip_level && is_inter && !xd->lossless[mbmi->segment_id] && + predict_skip_flag(x, bs, &dist, + cpi->common.features.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 (mb_rd_record) { + save_tx_rd_info(num_blks, hash, x, rd_stats, mb_rd_record); + } + return; + } + + if (xd->lossless[mbmi->segment_id]) { + // Lossless mode can only pick the smallest (4x4) transform size. + choose_smallest_tx_size(cpi, x, rd_stats, ref_best_rd, bs); + } else if (x->tx_size_search_method == USE_LARGESTALL) { + choose_largest_tx_size(cpi, x, rd_stats, ref_best_rd, bs); + } else { + choose_tx_size_type_from_rd(cpi, x, rd_stats, ref_best_rd, bs); + } + + // Save the RD search results into tx_rd_record for possible reuse in future. + if (mb_rd_record) { + save_tx_rd_info(num_blks, hash, x, rd_stats, mb_rd_record); + } +} + +// Calculate the transform coefficient RD cost for the given chroma coding block +// Return value 0: early termination triggered, no valid rd cost available; +// 1: rd cost values are valid. +int av1_txfm_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, + BLOCK_SIZE bsize, int64_t ref_best_rd) { + av1_init_rd_stats(rd_stats); + if (ref_best_rd < 0) return 0; + if (!x->e_mbd.is_chroma_ref) return 1; + + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_U]; + const int is_inter = is_inter_block(mbmi); + int64_t this_rd = 0, skip_rd = 0; + const BLOCK_SIZE plane_bsize = + get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); + + if (is_inter) { + for (int plane = 1; plane < MAX_MB_PLANE; ++plane) + av1_subtract_plane(x, plane_bsize, plane); + } + + const int skip_trellis = 0; + const TX_SIZE uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd); + int is_cost_valid = 1; + for (int plane = 1; plane < MAX_MB_PLANE; ++plane) { + RD_STATS this_rd_stats; + 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.inter_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); + av1_txfm_rd_in_plane(x, cpi, &this_rd_stats, chroma_ref_best_rd, 0, plane, + plane_bsize, uv_tx_size, + cpi->sf.rd_sf.use_fast_coef_costing, FTXS_NONE, + skip_trellis); + if (this_rd_stats.rate == INT_MAX) { + is_cost_valid = 0; + break; + } + av1_merge_rd_stats(rd_stats, &this_rd_stats); + 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; + } + } + + if (!is_cost_valid) { + // reset cost value + av1_invalid_rd_stats(rd_stats); + } + + return is_cost_valid; +} + +// Search for the best transform type and calculate the transform coefficients +// RD cost of the current coding block with the specified (uniform) transform +// size and channel. The RD results will be saved in rd_stats. +void av1_txfm_rd_in_plane(MACROBLOCK *x, const AV1_COMP *cpi, + RD_STATS *rd_stats, int64_t ref_best_rd, + int64_t current_rd, int plane, BLOCK_SIZE plane_bsize, + TX_SIZE tx_size, int use_fast_coef_costing, + FAST_TX_SEARCH_MODE ftxs_mode, int skip_trellis) { + assert(IMPLIES(plane == 0, x->e_mbd.mi[0]->tx_size == tx_size)); + + if (!cpi->oxcf.enable_tx64 && txsize_sqr_up_map[tx_size] == TX_64X64) { + av1_invalid_rd_stats(rd_stats); + return; + } + + if (current_rd > ref_best_rd) { + av1_invalid_rd_stats(rd_stats); + return; + } + + MACROBLOCKD *const xd = &x->e_mbd; + const struct macroblockd_plane *const pd = &xd->plane[plane]; + struct rdcost_block_args args; + av1_zero(args); + args.x = x; + args.cpi = cpi; + args.best_rd = ref_best_rd; + args.current_rd = current_rd; + args.use_fast_coef_costing = use_fast_coef_costing; + args.ftxs_mode = ftxs_mode; + args.skip_trellis = skip_trellis; + av1_init_rd_stats(&args.rd_stats); + + av1_get_entropy_contexts(plane_bsize, pd, args.t_above, args.t_left); + av1_foreach_transformed_block_in_plane(xd, plane_bsize, plane, block_rd_txfm, + &args); + + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int is_inter = is_inter_block(mbmi); + const int invalid_rd = is_inter ? args.incomplete_exit : args.exit_early; + + if (invalid_rd) { + av1_invalid_rd_stats(rd_stats); + } else { + *rd_stats = args.rd_stats; + } +} + +// This function combines y and uv planes' transform search processes together +// for inter-predicted blocks (including IntraBC), when the prediction is +// already generated. It first does subtraction to obtain the prediction error. +// Then it calls +// av1_pick_recursive_tx_size_type_yrd/av1_pick_uniform_tx_size_type_yrd and +// av1_txfm_uvrd sequentially and handles the early terminations +// happening in those functions. At the end, it computes the +// rd_stats/_y/_uv accordingly. +int av1_txfm_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, + RD_STATS *rd_stats, RD_STATS *rd_stats_y, + RD_STATS *rd_stats_uv, int mode_rate, int64_t ref_best_rd) { + MACROBLOCKD *const xd = &x->e_mbd; + const int skip_ctx = av1_get_skip_context(xd); + const int skip_flag_cost[2] = { x->skip_cost[skip_ctx][0], + x->skip_cost[skip_ctx][1] }; + const int64_t min_header_rate = + mode_rate + AOMMIN(skip_flag_cost[0], skip_flag_cost[1]); + // Account for minimum skip and non_skip rd. + // Eventually either one of them will be added to mode_rate + const int64_t min_header_rd_possible = RDCOST(x->rdmult, min_header_rate, 0); + if (min_header_rd_possible > ref_best_rd) { + av1_invalid_rd_stats(rd_stats_y); + return 0; + } + + const AV1_COMMON *cm = &cpi->common; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int64_t mode_rd = RDCOST(x->rdmult, mode_rate, 0); + const int64_t rd_thresh = + ref_best_rd == INT64_MAX ? INT64_MAX : ref_best_rd - mode_rd; + av1_init_rd_stats(rd_stats); + av1_init_rd_stats(rd_stats_y); + rd_stats->rate = mode_rate; + + // cost and distortion + av1_subtract_plane(x, bsize, 0); + if (x->tx_mode_search_type == TX_MODE_SELECT && + !xd->lossless[mbmi->segment_id]) { + av1_pick_recursive_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, rd_thresh); +#if CONFIG_COLLECT_RD_STATS == 2 + PrintPredictionUnitStats(cpi, tile_data, x, rd_stats_y, bsize); +#endif // CONFIG_COLLECT_RD_STATS == 2 + } else { + av1_pick_uniform_tx_size_type_yrd(cpi, x, rd_stats_y, bsize, rd_thresh); + memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size)); + for (int i = 0; i < xd->height * xd->width; ++i) + set_blk_skip(x, 0, i, rd_stats_y->skip); + } + + if (rd_stats_y->rate == INT_MAX) return 0; + + av1_merge_rd_stats(rd_stats, rd_stats_y); + + const int64_t non_skip_rdcosty = + RDCOST(x->rdmult, rd_stats->rate + skip_flag_cost[0], rd_stats->dist); + const int64_t skip_rdcosty = + RDCOST(x->rdmult, mode_rate + skip_flag_cost[1], rd_stats->sse); + const int64_t min_rdcosty = AOMMIN(non_skip_rdcosty, skip_rdcosty); + if (min_rdcosty > ref_best_rd) { + const int64_t tokenonly_rdy = + AOMMIN(RDCOST(x->rdmult, rd_stats_y->rate, rd_stats_y->dist), + RDCOST(x->rdmult, 0, rd_stats_y->sse)); + // Invalidate rd_stats_y to skip the rest of the motion modes search + if (tokenonly_rdy - + (tokenonly_rdy >> cpi->sf.inter_sf.prune_motion_mode_level) > + rd_thresh) { + av1_invalid_rd_stats(rd_stats_y); + } + return 0; + } + + 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.inter_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 = + av1_txfm_uvrd(cpi, x, rd_stats_uv, bsize, ref_best_chroma_rd); + if (!is_cost_valid_uv) return 0; + av1_merge_rd_stats(rd_stats, rd_stats_uv); + } + + int choose_skip = rd_stats->skip; + if (!choose_skip && !xd->lossless[mbmi->segment_id]) { + const int64_t rdcost_no_skip = RDCOST( + x->rdmult, rd_stats_y->rate + rd_stats_uv->rate + skip_flag_cost[0], + rd_stats->dist); + const int64_t rdcost_skip = + RDCOST(x->rdmult, skip_flag_cost[1], rd_stats->sse); + if (rdcost_no_skip >= rdcost_skip) choose_skip = 1; + } + if (choose_skip) { + rd_stats_y->rate = 0; + rd_stats_uv->rate = 0; + rd_stats->rate = mode_rate + skip_flag_cost[1]; + rd_stats->dist = rd_stats->sse; + rd_stats_y->dist = rd_stats_y->sse; + rd_stats_uv->dist = rd_stats_uv->sse; + mbmi->skip = 1; + if (rd_stats->skip) { + const int64_t tmprd = RDCOST(x->rdmult, rd_stats->rate, rd_stats->dist); + if (tmprd > ref_best_rd) return 0; + } + } else { + rd_stats->rate += skip_flag_cost[0]; + mbmi->skip = 0; + } + + return 1; +} diff --git a/media/libaom/src/av1/encoder/tx_search.h b/media/libaom/src/av1/encoder/tx_search.h new file mode 100644 index 0000000000..82d56719d0 --- /dev/null +++ b/media/libaom/src/av1/encoder/tx_search.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, 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_TRANSFORM_SEARCH_H_ +#define AOM_AV1_ENCODER_TRANSFORM_SEARCH_H_ + +#include "av1/common/pred_common.h" +#include "av1/encoder/encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Set this macro as 1 to collect data about tx size selection. +#define COLLECT_TX_SIZE_DATA 0 + +#if COLLECT_TX_SIZE_DATA +static const char av1_tx_size_data_output_file[] = "tx_size_data.txt"; +#endif + +enum { + FTXS_NONE = 0, + FTXS_DCT_AND_1D_DCT_ONLY = 1 << 0, + FTXS_DISABLE_TRELLIS_OPT = 1 << 1, + FTXS_USE_TRANSFORM_DOMAIN = 1 << 2 +} UENUM1BYTE(FAST_TX_SEARCH_MODE); + +static AOM_INLINE int tx_size_cost(const MACROBLOCK *const x, BLOCK_SIZE bsize, + TX_SIZE tx_size) { + assert(bsize == x->e_mbd.mi[0]->sb_type); + if (x->tx_mode_search_type != TX_MODE_SELECT || !block_signals_txsize(bsize)) + return 0; + + const int32_t tx_size_cat = bsize_to_tx_size_cat(bsize); + const int depth = tx_size_to_depth(tx_size, bsize); + const MACROBLOCKD *const xd = &x->e_mbd; + const int tx_size_ctx = get_tx_size_context(xd); + return x->tx_size_cost[tx_size_cat][tx_size_ctx][depth]; +} + +int64_t av1_uniform_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, int skip_trellis); + +void av1_pick_recursive_tx_size_type_yrd(const AV1_COMP *cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bsize, + int64_t ref_best_rd); + +void av1_pick_uniform_tx_size_type_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, + RD_STATS *rd_stats, BLOCK_SIZE bs, + int64_t ref_best_rd); + +int av1_txfm_uvrd(const AV1_COMP *const cpi, MACROBLOCK *x, RD_STATS *rd_stats, + BLOCK_SIZE bsize, int64_t ref_best_rd); + +void av1_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 plane_bsize, + TX_SIZE tx_size, int use_fast_coef_costing, + FAST_TX_SEARCH_MODE ftxs_mode, int skip_trellis); + +int av1_txfm_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, + RD_STATS *rd_stats, RD_STATS *rd_stats_y, + RD_STATS *rd_stats_uv, int mode_rate, int64_t ref_best_rd); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AOM_AV1_ENCODER_TRANSFORM_SEARCH_H_ diff --git a/media/libaom/src/av1/encoder/var_based_part.c b/media/libaom/src/av1/encoder/var_based_part.c index 4f1bd9cc83..e3cb1fa8f6 100644 --- a/media/libaom/src/av1/encoder/var_based_part.c +++ b/media/libaom/src/av1/encoder/var_based_part.c @@ -34,57 +34,8 @@ 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]; + VPVariance *part_variances; + VPartVar *split[4]; } variance_node; static AOM_INLINE void tree_to_node(void *data, BLOCK_SIZE bsize, @@ -93,42 +44,42 @@ static AOM_INLINE void tree_to_node(void *data, BLOCK_SIZE bsize, node->part_variances = NULL; switch (bsize) { case BLOCK_128X128: { - v128x128 *vt = (v128x128 *)data; + VP128x128 *vt = (VP128x128 *)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; + VP64x64 *vt = (VP64x64 *)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; + VP32x32 *vt = (VP32x32 *)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; + VP16x16 *vt = (VP16x16 *)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; + VP8x8 *vt = (VP8x8 *)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; + VP4x4 *vt = (VP4x4 *)data; assert(bsize == BLOCK_4X4); node->part_variances = &vt->part_variances; for (i = 0; i < 4; i++) node->split[i] = &vt->split[i]; @@ -138,13 +89,14 @@ static AOM_INLINE void tree_to_node(void *data, BLOCK_SIZE bsize, } // Set variance values given sum square error, sum error, count. -static AOM_INLINE void fill_variance(uint32_t s2, int32_t s, int c, var *v) { +static AOM_INLINE void fill_variance(uint32_t s2, int32_t s, int c, + VPartVar *v) { v->sum_square_error = s2; v->sum_error = s; v->log2_count = c; } -static AOM_INLINE void get_variance(var *v) { +static AOM_INLINE void get_variance(VPartVar *v) { v->variance = (int)(256 * (v->sum_square_error - (uint32_t)(((int64_t)v->sum_error * v->sum_error) >> @@ -152,7 +104,8 @@ static AOM_INLINE void get_variance(var *v) { v->log2_count); } -static AOM_INLINE void sum_2_variances(const var *a, const var *b, var *r) { +static AOM_INLINE void sum_2_variances(const VPartVar *a, const VPartVar *b, + VPartVar *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); @@ -173,8 +126,10 @@ static AOM_INLINE void fill_variance_tree(void *data, BLOCK_SIZE bsize) { static AOM_INLINE 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); + if (cpi->common.mi_params.mi_cols > mi_col && + cpi->common.mi_params.mi_rows > mi_row) { + set_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, x, xd, + mi_row, mi_col); xd->mi[0]->sb_type = bsize; } } @@ -262,7 +217,7 @@ static int set_vt_partitioning(AV1_COMP *cpi, MACROBLOCK *const x, static AOM_INLINE void fill_variance_8x8avg(const uint8_t *s, int sp, const uint8_t *d, int dp, int x16_idx, int y16_idx, - v16x16 *vst, + VP16x16 *vst, #if CONFIG_AV1_HIGHBITDEPTH int highbd_flag, #endif @@ -334,7 +289,7 @@ static int compute_minmax_8x8(const uint8_t *s, int sp, const uint8_t *d, static AOM_INLINE 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 x8_idx, int y8_idx, VP8x8 *vst, #if CONFIG_AV1_HIGHBITDEPTH int highbd_flag, #endif @@ -393,7 +348,8 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[], 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]); + (int64_t)(threshold_multiplier * + cpi->enc_quant_dequant_params.dequants.y_dequant_QTX[q][1]); if (is_key_frame) { thresholds[0] = threshold_base; @@ -416,7 +372,7 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[], if (last_qindex >= QINDEX_HIGH_THR) { threshold_base = (5 * threshold_base) >> 1; thresholds[1] = threshold_base >> 3; - thresholds[2] = threshold_base; + thresholds[2] = threshold_base << 2; thresholds[3] = threshold_base << 5; } else if (last_qindex < QINDEX_LOW_THR) { thresholds[1] = threshold_base >> 3; @@ -450,77 +406,127 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[], } } -static AOM_INLINE void set_low_temp_var_flag( - AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, v128x128 *vt, - int64_t thresholds[], MV_REFERENCE_FRAME ref_frame_partition, int mi_col, - int mi_row) { - int i, j, k; - AV1_COMMON *const cm = &cpi->common; - const int mv_thr = cm->width > 640 ? 8 : 4; - // Check temporal variance for bsize >= 16x16, if LAST_FRAME was selected and - // int_pro mv is small. If the temporal variance is small set the flag - // variance_low for the block. The variance threshold can be adjusted, the - // higher the more aggressive. - if (ref_frame_partition == LAST_FRAME && - (cpi->sf.short_circuit_low_temp_var == 1 || - (xd->mi[0]->mv[0].as_mv.col < mv_thr && - xd->mi[0]->mv[0].as_mv.col > -mv_thr && - xd->mi[0]->mv[0].as_mv.row < mv_thr && - xd->mi[0]->mv[0].as_mv.row > -mv_thr))) { - if (xd->mi[0]->sb_type == BLOCK_128X128 || - xd->mi[0]->sb_type == BLOCK_64X128 || - xd->mi[0]->sb_type == BLOCK_128X64) { - if ((vt->part_variances).none.variance < (thresholds[0] >> 1)) - x->variance_low[0] = 1; - } else { - for (i = 0; i < 4; i++) { - const int idx[4][2] = { { 0, 0 }, { 0, 16 }, { 16, 0 }, { 16, 16 } }; - const int idx_str = - cm->mi_stride * (mi_row + idx[i][0]) + mi_col + idx[i][1]; - MB_MODE_INFO **mi_64 = cm->mi_grid_base + idx_str; +// Set temporal variance low flag for superblock 64x64. +// Only first 25 in the array are used in this case. +static AOM_INLINE void set_low_temp_var_flag_64x64( + CommonModeInfoParams *mi_params, MACROBLOCK *x, MACROBLOCKD *xd, + VP64x64 *vt, const int64_t thresholds[], int mi_col, int mi_row) { + if (xd->mi[0]->sb_type == BLOCK_64X64) { + if ((vt->part_variances).none.variance < (thresholds[0] >> 1)) + x->variance_low[0] = 1; + } else if (xd->mi[0]->sb_type == BLOCK_64X32) { + for (int i = 0; i < 2; i++) { + if (vt->part_variances.horz[i].variance < (thresholds[0] >> 2)) + x->variance_low[i + 1] = 1; + } + } else if (xd->mi[0]->sb_type == BLOCK_32X64) { + for (int i = 0; i < 2; i++) { + if (vt->part_variances.vert[i].variance < (thresholds[0] >> 2)) + x->variance_low[i + 3] = 1; + } + } else { + static const int idx[4][2] = { { 0, 0 }, { 0, 8 }, { 8, 0 }, { 8, 8 } }; + for (int i = 0; i < 4; i++) { + const int idx_str = + mi_params->mi_stride * (mi_row + idx[i][0]) + mi_col + idx[i][1]; + MB_MODE_INFO **this_mi = mi_params->mi_grid_base + idx_str; - if (cm->mi_cols <= mi_col + idx[i][1] || - cm->mi_rows <= mi_row + idx[i][0]) - continue; + if (mi_params->mi_cols <= mi_col + idx[i][1] || + mi_params->mi_rows <= mi_row + idx[i][0]) + continue; - if ((*mi_64)->sb_type == BLOCK_64X64 || - (*mi_64)->sb_type == BLOCK_64X32 || - (*mi_64)->sb_type == BLOCK_32X64) { - int64_t threshold_64x64 = (cpi->sf.short_circuit_low_temp_var == 1 || - cpi->sf.short_circuit_low_temp_var == 3) - ? ((5 * thresholds[1]) >> 3) - : (thresholds[1] >> 1); - if (vt->split[i].part_variances.none.variance < threshold_64x64) - x->variance_low[1 + i] = 1; - } else { - for (k = 0; k < 4; k++) { - const int idx1[4][2] = { { 0, 0 }, { 0, 8 }, { 8, 0 }, { 8, 8 } }; - const int idx_str1 = cm->mi_stride * idx1[k][0] + idx1[k][1]; - MB_MODE_INFO **mi_32 = cm->mi_grid_base + idx_str + idx_str1; + if (*this_mi == NULL) continue; - if (cm->mi_cols <= mi_col + idx[i][1] + idx1[k][1] || - cm->mi_rows <= mi_row + idx[i][0] + idx1[k][0]) - continue; - if ((*mi_32)->sb_type == BLOCK_32X32) { - int64_t threshold_32x32 = - (cpi->sf.short_circuit_low_temp_var == 1 || - cpi->sf.short_circuit_low_temp_var == 3) - ? ((5 * thresholds[2]) >> 3) - : (thresholds[2] >> 1); - if (vt->split[i].split[k].part_variances.none.variance < - threshold_32x32) - x->variance_low[5 + (i << 2) + k] = 1; - } else if (cpi->sf.short_circuit_low_temp_var >= 2) { - if ((*mi_32)->sb_type == BLOCK_16X16 || - (*mi_32)->sb_type == BLOCK_32X16 || - (*mi_32)->sb_type == BLOCK_16X32) { - for (j = 0; j < 4; j++) { - if (vt->split[i] - .split[k] - .split[j] - .part_variances.none.variance < (thresholds[3] >> 8)) - x->variance_low[21 + (i << 4) + (k << 2) + j] = 1; - } + if ((*this_mi)->sb_type == BLOCK_32X32) { + int64_t threshold_32x32 = (5 * thresholds[1]) >> 3; + if (vt->split[i].part_variances.none.variance < threshold_32x32) + x->variance_low[i + 5] = 1; + } else { + // For 32x16 and 16x32 blocks, the flag is set on each 16x16 block + // inside. + if ((*this_mi)->sb_type == BLOCK_16X16 || + (*this_mi)->sb_type == BLOCK_32X16 || + (*this_mi)->sb_type == BLOCK_16X32) { + for (int j = 0; j < 4; j++) { + if (vt->split[i].split[j].part_variances.none.variance < + (thresholds[2] >> 8)) + x->variance_low[(i << 2) + j + 9] = 1; + } + } + } + } + } +} + +static AOM_INLINE void set_low_temp_var_flag_128x128( + CommonModeInfoParams *mi_params, MACROBLOCK *x, MACROBLOCKD *xd, + VP128x128 *vt, const int64_t thresholds[], int mi_col, int mi_row) { + if (xd->mi[0]->sb_type == BLOCK_128X128) { + if (vt->part_variances.none.variance < (thresholds[0] >> 1)) + x->variance_low[0] = 1; + } else if (xd->mi[0]->sb_type == BLOCK_128X64) { + for (int i = 0; i < 2; i++) { + if (vt->part_variances.horz[i].variance < (thresholds[0] >> 2)) + x->variance_low[i + 1] = 1; + } + } else if (xd->mi[0]->sb_type == BLOCK_64X128) { + for (int i = 0; i < 2; i++) { + if (vt->part_variances.vert[i].variance < (thresholds[0] >> 2)) + x->variance_low[i + 3] = 1; + } + } else { + static const int idx64[4][2] = { + { 0, 0 }, { 0, 16 }, { 16, 0 }, { 16, 16 } + }; + static const int idx32[4][2] = { { 0, 0 }, { 0, 8 }, { 8, 0 }, { 8, 8 } }; + for (int i = 0; i < 4; i++) { + const int idx_str = + mi_params->mi_stride * (mi_row + idx64[i][0]) + mi_col + idx64[i][1]; + MB_MODE_INFO **mi_64 = mi_params->mi_grid_base + idx_str; + if (*mi_64 == NULL) continue; + if (mi_params->mi_cols <= mi_col + idx64[i][1] || + mi_params->mi_rows <= mi_row + idx64[i][0]) + continue; + const int64_t threshold_64x64 = (5 * thresholds[1]) >> 3; + if ((*mi_64)->sb_type == BLOCK_64X64) { + if (vt->split[i].part_variances.none.variance < threshold_64x64) + x->variance_low[5 + i] = 1; + } else if ((*mi_64)->sb_type == BLOCK_64X32) { + for (int j = 0; j < 2; j++) + if (vt->split[i].part_variances.horz[j].variance < + (threshold_64x64 >> 1)) + x->variance_low[9 + (i << 1) + j] = 1; + } else if ((*mi_64)->sb_type == BLOCK_32X64) { + for (int j = 0; j < 2; j++) + if (vt->split[i].part_variances.vert[j].variance < + (threshold_64x64 >> 1)) + x->variance_low[17 + (i << 1) + j] = 1; + } else { + for (int k = 0; k < 4; k++) { + const int idx_str1 = mi_params->mi_stride * idx32[k][0] + idx32[k][1]; + MB_MODE_INFO **mi_32 = mi_params->mi_grid_base + idx_str + idx_str1; + if (*mi_32 == NULL) continue; + + if (mi_params->mi_cols <= mi_col + idx64[i][1] + idx32[k][1] || + mi_params->mi_rows <= mi_row + idx64[i][0] + idx32[k][0]) + continue; + const int64_t threshold_32x32 = (5 * thresholds[2]) >> 3; + if ((*mi_32)->sb_type == BLOCK_32X32) { + if (vt->split[i].split[k].part_variances.none.variance < + threshold_32x32) + x->variance_low[25 + (i << 2) + k] = 1; + } else { + // For 32x16 and 16x32 blocks, the flag is set on each 16x16 block + // inside. + if ((*mi_32)->sb_type == BLOCK_16X16 || + (*mi_32)->sb_type == BLOCK_32X16 || + (*mi_32)->sb_type == BLOCK_16X32) { + for (int j = 0; j < 4; j++) { + if (vt->split[i] + .split[k] + .split[j] + .part_variances.none.variance < (thresholds[3] >> 8)) + x->variance_low[41 + (i << 4) + (k << 2) + j] = 1; } } } @@ -530,39 +536,42 @@ static AOM_INLINE void set_low_temp_var_flag( } } +static AOM_INLINE void set_low_temp_var_flag( + AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, VP128x128 *vt, + int64_t thresholds[], MV_REFERENCE_FRAME ref_frame_partition, int mi_col, + int mi_row) { + AV1_COMMON *const cm = &cpi->common; + const int mv_thr = cm->width > 640 ? 8 : 4; + // Check temporal variance for bsize >= 16x16, if LAST_FRAME was selected and + // int_pro mv is small. If the temporal variance is small set the flag + // variance_low for the block. The variance threshold can be adjusted, the + // higher the more aggressive. + if (ref_frame_partition == LAST_FRAME && + (cpi->sf.rt_sf.short_circuit_low_temp_var == 1 || + (cpi->sf.rt_sf.estimate_motion_for_var_based_partition && + xd->mi[0]->mv[0].as_mv.col < mv_thr && + xd->mi[0]->mv[0].as_mv.col > -mv_thr && + xd->mi[0]->mv[0].as_mv.row < mv_thr && + xd->mi[0]->mv[0].as_mv.row > -mv_thr))) { + const int is_small_sb = (cm->seq_params.sb_size == BLOCK_64X64); + if (is_small_sb) + set_low_temp_var_flag_64x64(&cm->mi_params, x, xd, &(vt->split[0]), + thresholds, mi_col, mi_row); + else + set_low_temp_var_flag_128x128(&cm->mi_params, x, xd, vt, thresholds, + mi_col, mi_row); + } +} + 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) { + if (sf->part_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); + set_vbp_thresholds(cpi, cpi->vbp_info.thresholds, q, content_state); + // The threshold below is not changed locally. + cpi->vbp_info.threshold_minmax = 15 + (q >> 3); } } @@ -572,7 +581,7 @@ static AOM_INLINE void chroma_check(AV1_COMP *cpi, MACROBLOCK *x, int i; MACROBLOCKD *xd = &x->e_mbd; - if (is_key_frame) return; + if (is_key_frame || cpi->oxcf.monochrome) return; for (i = 1; i <= 2; ++i) { unsigned int uv_sad = UINT_MAX; @@ -594,13 +603,15 @@ static AOM_INLINE void chroma_check(AV1_COMP *cpi, MACROBLOCK *x, // 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) { + ThreadData *td, MACROBLOCK *x, int mi_row, + int mi_col) { AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *xd = &x->e_mbd; + const int64_t *const vbp_thresholds = cpi->vbp_info.thresholds; int i, j, k, m; - v128x128 *vt; - v16x16 *vt2 = NULL; + VP128x128 *vt; + VP16x16 *vt2 = NULL; unsigned char force_split[85]; int avg_32x32; int max_var_32x32[4]; @@ -628,6 +639,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, const int num_64x64_blocks = is_small_sb ? 1 : 4; unsigned int y_sad = UINT_MAX; + unsigned int y_sad_g = UINT_MAX; BLOCK_SIZE bsize = is_small_sb ? BLOCK_64X64 : BLOCK_128X128; // Ref frame used in partitioning. @@ -635,9 +647,11 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, CHECK_MEM_ERROR(cm, vt, aom_malloc(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] }; + vt->split = td->vt64x64; + + int64_t thresholds[5] = { vbp_thresholds[0], vbp_thresholds[1], + vbp_thresholds[2], vbp_thresholds[3], + vbp_thresholds[4] }; const int low_res = (cm->width <= 352 && cm->height <= 288); int variance4x4downsample[64]; @@ -646,7 +660,15 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, segment_id = xd->mi[0]->segment_id; - set_vbp_thresholds(cpi, thresholds, cm->base_qindex, content_state); + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled && + cyclic_refresh_segment_id_boosted(segment_id) && + cpi->sf.rt_sf.use_nonrd_pick_mode) { + int q = av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex); + set_vbp_thresholds(cpi, thresholds, q, content_state); + } else { + set_vbp_thresholds(cpi, thresholds, cm->quant_params.base_qindex, + content_state); + } if (is_small_sb) { pixels_wide = 64; @@ -672,8 +694,23 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, // is!! MB_MODE_INFO *mi = xd->mi[0]; const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, LAST_FRAME); - assert(yv12 != NULL); + const YV12_BUFFER_CONFIG *yv12_g = NULL; + + // For non-SVC GOLDEN is another temporal reference. Check if it should be + // used as reference for partitioning. + if (!cpi->use_svc && (cpi->ref_frame_flags & AOM_GOLD_FLAG) && + cpi->sf.rt_sf.use_nonrd_pick_mode) { + yv12_g = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME); + if (yv12_g && yv12_g != yv12) { + av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col, + get_ref_scale_factors(cm, GOLDEN_FRAME), + num_planes); + y_sad_g = 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); + } + } av1_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, get_ref_scale_factors(cm, LAST_FRAME), num_planes); @@ -682,7 +719,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, mi->sb_type = cm->seq_params.sb_size; mi->mv[0].as_int = 0; mi->interp_filters = av1_broadcast_interp_filter(BILINEAR); - if (cpi->sf.estimate_motion_for_var_based_partition) { + if (cpi->sf.rt_sf.estimate_motion_for_var_based_partition) { if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) { const MV dummy_mv = { 0, 0 }; y_sad = av1_int_pro_motion_estimation(cpi, x, cm->seq_params.sb_size, @@ -695,7 +732,22 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, xd->plane[0].pre[0].stride); } - x->pred_mv[LAST_FRAME] = mi->mv[0].as_mv; + // Pick the ref frame for partitioning, use golden frame only if its + // lower sad. + if (y_sad_g < 0.9 * y_sad) { + av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col, + get_ref_scale_factors(cm, GOLDEN_FRAME), num_planes); + mi->ref_frame[0] = GOLDEN_FRAME; + mi->mv[0].as_int = 0; + y_sad = y_sad_g; + ref_frame_partition = GOLDEN_FRAME; + x->nonrd_prune_ref_frame_search = 0; + } else { + x->pred_mv[LAST_FRAME] = mi->mv[0].as_mv; + ref_frame_partition = LAST_FRAME; + x->nonrd_prune_ref_frame_search = + cpi->sf.rt_sf.nonrd_prune_ref_frame_search; + } 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, @@ -704,20 +756,6 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, 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; @@ -746,7 +784,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, 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]; + VP16x16 *vst = &vt->split[m].split[i].split[j]; force_split[split_index] = 0; variance4x4downsample[i2 + j] = 0; if (!is_key_frame) { @@ -790,7 +828,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, xd->cur_buf->flags, #endif pixels_wide, pixels_high); - int thresh_minmax = (int)cpi->vbp_threshold_minmax; + int thresh_minmax = (int)cpi->vbp_info.threshold_minmax; if (minmax > thresh_minmax) { force_split[split_index] = 1; force_split[5 + m2 + i] = 1; @@ -806,7 +844,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, 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]; + VP8x8 *vst2 = is_key_frame ? &vst->split[k] : &vt2[i2 + j].split[k]; fill_variance_4x4avg(s, sp, d, dp, x8_idx, y8_idx, vst2, #if CONFIG_AV1_HIGHBITDEPTH xd->cur_buf->flags, @@ -827,7 +865,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, for (j = 0; j < 4; j++) { const int split_index = 21 + i2 + j; if (variance4x4downsample[i2 + j] == 1) { - v16x16 *vtemp = + VP16x16 *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); @@ -930,7 +968,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, // 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 = + VP16x16 *vtemp = (!is_key_frame && variance4x4downsample[i2 + j] == 1) ? &vt2[i2 + j] : &vt->split[m].split[i].split[j]; @@ -956,7 +994,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile, } } - if (cpi->sf.short_circuit_low_temp_var && !is_small_sb) { + if (cpi->sf.rt_sf.short_circuit_low_temp_var) { set_low_temp_var_flag(cpi, x, xd, vt, thresholds, ref_frame_partition, mi_col, mi_row); } diff --git a/media/libaom/src/av1/encoder/var_based_part.h b/media/libaom/src/av1/encoder/var_based_part.h index a2b6532ad6..a80e25c329 100644 --- a/media/libaom/src/av1/encoder/var_based_part.h +++ b/media/libaom/src/av1/encoder/var_based_part.h @@ -35,7 +35,8 @@ 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); + ThreadData *td, MACROBLOCK *x, int mi_row, + int mi_col); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm1d_sse4.c b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm1d_sse4.c index 865ac31494..62eaa30747 100644 --- a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm1d_sse4.c +++ b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm1d_sse4.c @@ -11,8 +11,8 @@ #include "av1/encoder/x86/av1_txfm1d_sse4.h" -void av1_fdct32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit, - const int stride) { +void av1_fdct32_sse4_1(__m128i *input, __m128i *output, int cos_bit, + const int stride) { __m128i buf0[32]; __m128i buf1[32]; const int32_t *cospi; @@ -396,8 +396,8 @@ void av1_fdct32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit, output[endidx] = buf0[1]; } -void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range) { +void av1_fadst4_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range) { const int txfm_size = 4; const int num_per_128 = 4; const int32_t *cospi; @@ -459,8 +459,8 @@ void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output, } } -void av1_fdct64_new_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit, - const int instride, const int outstride) { +void av1_fdct64_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit, + const int instride, const int outstride) { const int32_t *cospi = cospi_arr(cos_bit); const __m128i __rounding = _mm_set1_epi32(1 << (cos_bit - 1)); @@ -1408,8 +1408,8 @@ void av1_fdct64_new_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit, output[endidx] = x10[1]; } -void av1_idtx32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit, - const int col_num) { +void av1_idtx32_sse4_1(__m128i *input, __m128i *output, int cos_bit, + const int col_num) { (void)cos_bit; for (int i = 0; i < 32; i++) { output[i * col_num] = _mm_slli_epi32(input[i * col_num], 2); diff --git a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_avx2.c b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_avx2.c index f97cf71296..634d50bb22 100644 --- a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_avx2.c +++ b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_avx2.c @@ -113,8 +113,8 @@ static INLINE void fdct16x16_new_avx2(const __m256i *input, __m256i *output, output[15] = x1[15]; } -static INLINE void fdct16x32_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static INLINE void fdct16x32_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { const int32_t *cospi = cospi_arr(cos_bit); const __m256i _r = _mm256_set1_epi32(1 << (cos_bit - 1)); @@ -711,8 +711,8 @@ static INLINE void fdct16x64_new_avx2(const __m256i *input, __m256i *output, output[63] = x1[63]; } -static INLINE void fdct32_new_avx2(const __m256i *input, __m256i *output, - int8_t cos_bit) { +static INLINE void fdct32_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { __m256i x1[32]; const int32_t *cospi = cospi_arr(cos_bit); const __m256i _r = _mm256_set1_epi32(1 << (cos_bit - 1)); @@ -1422,8 +1422,8 @@ static INLINE void fidentity16x16_new_avx2(const __m256i *input, } } -static INLINE void fidentity16x32_new_avx2(const __m256i *input, - __m256i *output, int8_t cos_bit) { +static INLINE void fidentity16x32_avx2(const __m256i *input, __m256i *output, + int8_t cos_bit) { (void)cos_bit; for (int i = 0; i < 32; ++i) { output[i] = _mm256_slli_epi16(input[i], 2); @@ -1499,41 +1499,41 @@ typedef void (*transform_1d_avx2)(const __m256i *input, __m256i *output, int8_t cos_bit); static const transform_1d_avx2 col_txfm16x32_arr[TX_TYPES] = { - fdct16x32_new_avx2, // DCT_DCT - NULL, // ADST_DCT - NULL, // DCT_ADST - NULL, // ADST_ADST - NULL, // FLIPADST_DCT - NULL, // DCT_FLIPADST - NULL, // FLIPADST_FLIPADST - NULL, // ADST_FLIPADST - NULL, // FLIPADST_ADST - fidentity16x32_new_avx2, // IDTX - fdct16x32_new_avx2, // V_DCT - fidentity16x32_new_avx2, // H_DCT - NULL, // V_ADST - NULL, // H_ADST - NULL, // V_FLIPADST - NULL // H_FLIPADST + fdct16x32_avx2, // DCT_DCT + NULL, // ADST_DCT + NULL, // DCT_ADST + NULL, // ADST_ADST + NULL, // FLIPADST_DCT + NULL, // DCT_FLIPADST + NULL, // FLIPADST_FLIPADST + NULL, // ADST_FLIPADST + NULL, // FLIPADST_ADST + fidentity16x32_avx2, // IDTX + fdct16x32_avx2, // V_DCT + fidentity16x32_avx2, // H_DCT + NULL, // V_ADST + NULL, // H_ADST + NULL, // V_FLIPADST + NULL // H_FLIPADST }; static const transform_1d_avx2 row_txfm16x32_arr[TX_TYPES] = { - fdct16x32_new_avx2, // DCT_DCT - NULL, // ADST_DCT - NULL, // DCT_ADST - NULL, // ADST_ADST - NULL, // FLIPADST_DCT - NULL, // DCT_FLIPADST - NULL, // FLIPADST_FLIPADST - NULL, // ADST_FLIPADST - NULL, // FLIPADST_ADST - fidentity16x32_new_avx2, // IDTX - fidentity16x32_new_avx2, // V_DCT - fdct16x32_new_avx2, // H_DCT - NULL, // V_ADST - NULL, // H_ADST - NULL, // V_FLIPADST - NULL // H_FLIPADST + fdct16x32_avx2, // DCT_DCT + NULL, // ADST_DCT + NULL, // DCT_ADST + NULL, // ADST_ADST + NULL, // FLIPADST_DCT + NULL, // DCT_FLIPADST + NULL, // FLIPADST_FLIPADST + NULL, // ADST_FLIPADST + NULL, // FLIPADST_ADST + fidentity16x32_avx2, // IDTX + fidentity16x32_avx2, // V_DCT + fdct16x32_avx2, // H_DCT + NULL, // V_ADST + NULL, // H_ADST + NULL, // V_FLIPADST + NULL // H_FLIPADST }; static const transform_1d_avx2 col_txfm16x16_arr[TX_TYPES] = { @@ -1891,8 +1891,8 @@ static void lowbd_fwd_txfm2d_32x64_avx2(const int16_t *input, int32_t *output, bufA[j] = _mm256_cvtepi16_epi32(buf[j * 2]); bufB[j] = _mm256_cvtepi16_epi32(buf[j * 2 + 1]); } - fdct32_new_avx2(bufA, bufA, cos_bit_row); - fdct32_new_avx2(bufB, bufB, cos_bit_row); + fdct32_avx2(bufA, bufA, cos_bit_row); + fdct32_avx2(bufB, bufB, cos_bit_row); av1_round_shift_rect_array_32_avx2(bufA, bufA, 32, -shift[2], NewSqrt2); av1_round_shift_rect_array_32_avx2(bufB, bufB, 32, -shift[2], NewSqrt2); diff --git a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_sse4.c b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_sse4.c index 84b7229a1b..0bc3fbc2d6 100644 --- a/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_sse4.c +++ b/media/libaom/src/av1/encoder/x86/av1_fwd_txfm2d_sse4.c @@ -32,15 +32,15 @@ static INLINE void int16_array_with_stride_to_int32_array_without_stride( typedef void (*TxfmFuncSSE2)(__m128i *input, __m128i *output, const int8_t cos_bit, const int8_t *stage_range); -static void fdct32_new_sse4_1(__m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range) { +static void fdct32_sse4_1(__m128i *input, __m128i *output, const int8_t cos_bit, + const int8_t *stage_range) { const int txfm_size = 32; const int num_per_128 = 4; int col_num = txfm_size / num_per_128; int col; (void)stage_range; for (col = 0; col < col_num; col++) { - av1_fdct32_new_sse4_1((input + col), (output + col), cos_bit, col_num); + av1_fdct32_sse4_1((input + col), (output + col), cos_bit, col_num); } } @@ -51,8 +51,7 @@ static void fdct64_new_sse4_1(__m128i *input, __m128i *output, int col_num = txfm_size / num_per_128; (void)stage_range; for (int col = 0; col < col_num; col++) { - av1_fdct64_new_sse4_1((input + col), (output + col), cos_bit, col_num, - col_num); + av1_fdct64_sse4_1((input + col), (output + col), cos_bit, col_num, col_num); } } static void idtx32x32_sse4_1(__m128i *input, __m128i *output, @@ -60,13 +59,13 @@ static void idtx32x32_sse4_1(__m128i *input, __m128i *output, (void)stage_range; for (int i = 0; i < 8; i++) { - av1_idtx32_new_sse4_1(&input[i * 32], &output[i * 32], cos_bit, 1); + av1_idtx32_sse4_1(&input[i * 32], &output[i * 32], cos_bit, 1); } } static INLINE TxfmFuncSSE2 fwd_txfm_type_to_func(TXFM_TYPE txfm_type) { switch (txfm_type) { - case TXFM_TYPE_DCT32: return fdct32_new_sse4_1; break; + case TXFM_TYPE_DCT32: return fdct32_sse4_1; break; case TXFM_TYPE_DCT64: return fdct64_new_sse4_1; break; case TXFM_TYPE_IDENTITY32: return idtx32x32_sse4_1; break; default: assert(0); @@ -136,8 +135,8 @@ static INLINE void fwd_txfm2d_64x64_sse4_1(const int16_t *input, /*row wise transform*/ for (int col = 0; col < (col_num >> 1); col++) { - av1_fdct64_new_sse4_1((buf_128 + col), (out_128 + col), cos_bit_row, - col_num, (col_num >> 1)); + av1_fdct64_sse4_1((buf_128 + col), (out_128 + col), cos_bit_row, col_num, + (col_num >> 1)); } txfm2d_size_128 = (col_num >> 1) * (txfm_size >> 1); @@ -221,8 +220,8 @@ static void lowbd_fwd_txfm2d_64x64_sse4_1(const int16_t *input, int32_t *output, bufA[j] = _mm_cvtepi16_epi32(buf[j]); bufB[j] = _mm_cvtepi16_epi32(_mm_unpackhi_epi64(buf[j], buf[j])); } - av1_fdct64_new_sse4_1(bufA, bufA, cos_bit_row, 1, 1); - av1_fdct64_new_sse4_1(bufB, bufB, cos_bit_row, 1, 1); + av1_fdct64_sse4_1(bufA, bufA, cos_bit_row, 1, 1); + av1_fdct64_sse4_1(bufB, bufB, cos_bit_row, 1, 1); av1_round_shift_array_32_sse4_1(bufA, bufA, 32, -shift[2]); av1_round_shift_array_32_sse4_1(bufB, bufB, 32, -shift[2]); @@ -268,8 +267,8 @@ static void lowbd_fwd_txfm2d_64x32_sse4_1(const int16_t *input, int32_t *output, bufA[j] = _mm_cvtepi16_epi32(buf[j]); bufB[j] = _mm_cvtepi16_epi32(_mm_unpackhi_epi64(buf[j], buf[j])); } - av1_fdct64_new_sse4_1(bufA, bufA, cos_bit_row, 1, 1); - av1_fdct64_new_sse4_1(bufB, bufB, cos_bit_row, 1, 1); + av1_fdct64_sse4_1(bufA, bufA, cos_bit_row, 1, 1); + av1_fdct64_sse4_1(bufB, bufB, cos_bit_row, 1, 1); av1_round_shift_rect_array_32_sse4_1(bufA, bufA, 32, -shift[2], NewSqrt2); av1_round_shift_rect_array_32_sse4_1(bufB, bufB, 32, -shift[2], NewSqrt2); @@ -317,8 +316,8 @@ static void lowbd_fwd_txfm2d_32x64_sse4_1(const int16_t *input, int32_t *output, bufA[j] = _mm_cvtepi16_epi32(buf[j]); bufB[j] = _mm_cvtepi16_epi32(_mm_unpackhi_epi64(buf[j], buf[j])); } - av1_fdct32_new_sse4_1(bufA, bufA, cos_bit_row, 1); - av1_fdct32_new_sse4_1(bufB, bufB, cos_bit_row, 1); + av1_fdct32_sse4_1(bufA, bufA, cos_bit_row, 1); + av1_fdct32_sse4_1(bufB, bufB, cos_bit_row, 1); av1_round_shift_rect_array_32_sse4_1(bufA, bufA, 32, -shift[2], NewSqrt2); av1_round_shift_rect_array_32_sse4_1(bufB, bufB, 32, -shift[2], NewSqrt2); diff --git a/media/libaom/src/av1/encoder/x86/av1_quantize_avx2.c b/media/libaom/src/av1/encoder/x86/av1_quantize_avx2.c index df22aaba7c..f5f7ee115d 100644 --- a/media/libaom/src/av1/encoder/x86/av1_quantize_avx2.c +++ b/media/libaom/src/av1/encoder/x86/av1_quantize_avx2.c @@ -132,6 +132,121 @@ static INLINE void quantize(const __m256i *thr, const __m256i *qp, __m256i *c, } } +static INLINE __m256i scan_eob_256(const __m256i *iscan_ptr, + __m256i *coeff256) { + const __m256i iscan = _mm256_loadu_si256(iscan_ptr); + const __m256i zero256 = _mm256_setzero_si256(); + const __m256i zero_coeff0 = _mm256_cmpeq_epi16(*coeff256, zero256); + const __m256i nzero_coeff0 = _mm256_cmpeq_epi16(zero_coeff0, zero256); + // Add one to convert from indices to counts + const __m256i iscan_plus_one = _mm256_sub_epi16(iscan, nzero_coeff0); + return _mm256_and_si256(iscan_plus_one, nzero_coeff0); +} + +static INLINE int16_t accumulate_eob(__m128i eob) { + __m128i eob_shuffled; + eob_shuffled = _mm_shuffle_epi32(eob, 0xe); + eob = _mm_max_epi16(eob, eob_shuffled); + eob_shuffled = _mm_shufflelo_epi16(eob, 0xe); + eob = _mm_max_epi16(eob, eob_shuffled); + eob_shuffled = _mm_shufflelo_epi16(eob, 0x1); + eob = _mm_max_epi16(eob, eob_shuffled); + return _mm_extract_epi16(eob, 1); +} + +static INLINE void store_zero_tran_low(int16_t *a) { + const __m256i zero = _mm256_setzero_si256(); + _mm256_storeu_si256((__m256i *)(a), zero); +} + +void av1_quantize_lp_avx2(const int16_t *coeff_ptr, intptr_t n_coeffs, + const int16_t *round_ptr, const int16_t *quant_ptr, + int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr, + const int16_t *dequant_ptr, uint16_t *eob_ptr, + const int16_t *scan) { + __m128i eob; + __m256i round256, quant256, dequant256; + __m256i eob256, thr256; + + coeff_ptr += n_coeffs; + scan += n_coeffs; + qcoeff_ptr += n_coeffs; + dqcoeff_ptr += n_coeffs; + n_coeffs = -n_coeffs; + + { + __m256i coeff256; + + // Setup global values + { + const __m128i round = _mm_load_si128((const __m128i *)round_ptr); + const __m128i quant = _mm_load_si128((const __m128i *)quant_ptr); + const __m128i dequant = _mm_load_si128((const __m128i *)dequant_ptr); + round256 = _mm256_castsi128_si256(round); + round256 = _mm256_permute4x64_epi64(round256, 0x54); + + quant256 = _mm256_castsi128_si256(quant); + quant256 = _mm256_permute4x64_epi64(quant256, 0x54); + + dequant256 = _mm256_castsi128_si256(dequant); + dequant256 = _mm256_permute4x64_epi64(dequant256, 0x54); + } + + { + __m256i qcoeff256; + __m256i qtmp256; + coeff256 = _mm256_loadu_si256((const __m256i *)(coeff_ptr + n_coeffs)); + qcoeff256 = _mm256_abs_epi16(coeff256); + qcoeff256 = _mm256_adds_epi16(qcoeff256, round256); + qtmp256 = _mm256_mulhi_epi16(qcoeff256, quant256); + qcoeff256 = _mm256_sign_epi16(qtmp256, coeff256); + _mm256_storeu_si256((__m256i *)(qcoeff_ptr + n_coeffs), qcoeff256); + coeff256 = _mm256_mullo_epi16(qcoeff256, dequant256); + _mm256_storeu_si256((__m256i *)(dqcoeff_ptr + n_coeffs), coeff256); + } + + eob256 = scan_eob_256((const __m256i *)(scan + n_coeffs), &coeff256); + n_coeffs += 8 * 2; + } + + // remove dc constants + dequant256 = _mm256_permute2x128_si256(dequant256, dequant256, 0x31); + quant256 = _mm256_permute2x128_si256(quant256, quant256, 0x31); + round256 = _mm256_permute2x128_si256(round256, round256, 0x31); + + thr256 = _mm256_srai_epi16(dequant256, 1); + + // AC only loop + while (n_coeffs < 0) { + __m256i coeff256 = + _mm256_loadu_si256((const __m256i *)(coeff_ptr + n_coeffs)); + __m256i qcoeff256 = _mm256_abs_epi16(coeff256); + int32_t nzflag = + _mm256_movemask_epi8(_mm256_cmpgt_epi16(qcoeff256, thr256)); + + if (nzflag) { + __m256i qtmp256; + qcoeff256 = _mm256_adds_epi16(qcoeff256, round256); + qtmp256 = _mm256_mulhi_epi16(qcoeff256, quant256); + qcoeff256 = _mm256_sign_epi16(qtmp256, coeff256); + _mm256_storeu_si256((__m256i *)(qcoeff_ptr + n_coeffs), qcoeff256); + coeff256 = _mm256_mullo_epi16(qcoeff256, dequant256); + _mm256_storeu_si256((__m256i *)(dqcoeff_ptr + n_coeffs), coeff256); + eob256 = _mm256_max_epi16( + eob256, scan_eob_256((const __m256i *)(scan + n_coeffs), &coeff256)); + } else { + store_zero_tran_low(qcoeff_ptr + n_coeffs); + store_zero_tran_low(dqcoeff_ptr + n_coeffs); + } + n_coeffs += 8 * 2; + } + + eob = _mm_max_epi16(_mm256_castsi256_si128(eob256), + _mm256_extracti128_si256(eob256, 1)); + + *eob_ptr = accumulate_eob(eob); +} + void av1_quantize_fp_avx2(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, diff --git a/media/libaom/src/av1/encoder/x86/av1_txfm1d_sse4.h b/media/libaom/src/av1/encoder/x86/av1_txfm1d_sse4.h index b3d5b22d79..7a0f32898b 100644 --- a/media/libaom/src/av1/encoder/x86/av1_txfm1d_sse4.h +++ b/media/libaom/src/av1/encoder/x86/av1_txfm1d_sse4.h @@ -20,43 +20,43 @@ extern "C" { #endif -void av1_fdct4_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_fdct8_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_fdct16_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_fdct32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit, - const int stride); -void av1_fdct64_new_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit, - const int instride, const int outstride); -void av1_fadst4_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_fadst8_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_fadst16_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); +void av1_fdct4_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_fdct8_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_fdct16_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_fdct32_sse4_1(__m128i *input, __m128i *output, int cos_bit, + const int stride); +void av1_fdct64_sse4_1(__m128i *input, __m128i *output, int8_t cos_bit, + const int instride, const int outstride); +void av1_fadst4_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_fadst8_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_fadst16_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); -void av1_idct4_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_idct8_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_idct16_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_idct32_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_idct64_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); +void av1_idct4_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_idct8_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_idct16_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_idct32_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_idct64_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); -void av1_iadst4_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_iadst8_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); -void av1_iadst16_new_sse4_1(const __m128i *input, __m128i *output, - const int8_t cos_bit, const int8_t *stage_range); +void av1_iadst4_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_iadst8_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); +void av1_iadst16_sse4_1(const __m128i *input, __m128i *output, + const int8_t cos_bit, const int8_t *stage_range); -void av1_idtx32_new_sse4_1(__m128i *input, __m128i *output, int cos_bit, - const int col_num); +void av1_idtx32_sse4_1(__m128i *input, __m128i *output, int cos_bit, + const int col_num); static INLINE void transpose_32_4x4(int stride, const __m128i *input, __m128i *output) { diff --git a/media/libaom/src/av1/encoder/x86/encodetxb_avx2.c b/media/libaom/src/av1/encoder/x86/encodetxb_avx2.c index 2621301859..30a4129091 100644 --- a/media/libaom/src/av1/encoder/x86/encodetxb_avx2.c +++ b/media/libaom/src/av1/encoder/x86/encodetxb_avx2.c @@ -16,7 +16,7 @@ #include "aom/aom_integer.h" #include "aom_dsp/x86/mem_sse2.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/txb_common.h" #include "aom_dsp/x86/synonyms.h" #include "aom_dsp/x86/synonyms_avx2.h" diff --git a/media/libaom/src/av1/encoder/x86/encodetxb_sse2.c b/media/libaom/src/av1/encoder/x86/encodetxb_sse2.c index dedb4d02f6..394befb7b1 100644 --- a/media/libaom/src/av1/encoder/x86/encodetxb_sse2.c +++ b/media/libaom/src/av1/encoder/x86/encodetxb_sse2.c @@ -14,7 +14,7 @@ #include "aom/aom_integer.h" #include "aom_dsp/x86/mem_sse2.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/txb_common.h" static INLINE void load_levels_4x4x5_sse2(const uint8_t *const src, diff --git a/media/libaom/src/av1/encoder/x86/encodetxb_sse4.c b/media/libaom/src/av1/encoder/x86/encodetxb_sse4.c index 34c9e4f266..aeb57f2cd3 100644 --- a/media/libaom/src/av1/encoder/x86/encodetxb_sse4.c +++ b/media/libaom/src/av1/encoder/x86/encodetxb_sse4.c @@ -14,7 +14,7 @@ #include /* SSE4.1 */ #include "aom/aom_integer.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/common/txb_common.h" #include "aom_dsp/x86/synonyms.h" diff --git a/media/libaom/src/av1/encoder/x86/error_intrin_avx2.c b/media/libaom/src/av1/encoder/x86/error_intrin_avx2.c index 7d4f695854..12dda3ad01 100644 --- a/media/libaom/src/av1/encoder/x86/error_intrin_avx2.c +++ b/media/libaom/src/av1/encoder/x86/error_intrin_avx2.c @@ -29,6 +29,59 @@ static INLINE void read_coeff(const tran_low_t *coeff, intptr_t offset, } } +int64_t av1_block_error_lp_avx2(const int16_t *coeff, const int16_t *dqcoeff, + intptr_t block_size) { + const __m256i zero = _mm256_setzero_si256(); + __m256i sse_256 = zero; + __m256i sse_hi; + __m128i sse_128; + int64_t sse; + + if (block_size == 16) { + // Load 16 elements for coeff and dqcoeff. + const __m256i _coeff = _mm256_loadu_si256((const __m256i *)coeff); + const __m256i _dqcoeff = _mm256_loadu_si256((const __m256i *)dqcoeff); + // dqcoeff - coeff + const __m256i diff = _mm256_sub_epi16(_dqcoeff, _coeff); + // madd (dqcoeff - coeff) + const __m256i error_lo = _mm256_madd_epi16(diff, diff); + // Save the higher 64 bit of each 128 bit lane. + const __m256i error_hi = _mm256_srli_si256(error_lo, 8); + // Add the higher 64 bit to the low 64 bit. + const __m256i error = _mm256_add_epi32(error_lo, error_hi); + // Expand each double word in the lower 64 bits to quad word. + sse_256 = _mm256_unpacklo_epi32(error, zero); + } else { + for (int i = 0; i < block_size; i += 16) { + // Load 16 elements for coeff and dqcoeff. + const __m256i _coeff = _mm256_loadu_si256((const __m256i *)coeff); + const __m256i _dqcoeff = _mm256_loadu_si256((const __m256i *)dqcoeff); + const __m256i diff = _mm256_sub_epi16(_dqcoeff, _coeff); + const __m256i error = _mm256_madd_epi16(diff, diff); + // Expand each double word of madd (dqcoeff - coeff) to quad word. + const __m256i exp_error_lo = _mm256_unpacklo_epi32(error, zero); + const __m256i exp_error_hi = _mm256_unpackhi_epi32(error, zero); + // Add each quad word of madd (dqcoeff - coeff). + sse_256 = _mm256_add_epi64(sse_256, exp_error_lo); + sse_256 = _mm256_add_epi64(sse_256, exp_error_hi); + coeff += 16; + dqcoeff += 16; + } + } + // Save the higher 64 bit of each 128 bit lane. + sse_hi = _mm256_srli_si256(sse_256, 8); + // Add the higher 64 bit to the low 64 bit. + sse_256 = _mm256_add_epi64(sse_256, sse_hi); + + // Add each 64 bit from each of the 128 bit lane of the 256 bit. + sse_128 = _mm_add_epi64(_mm256_castsi256_si128(sse_256), + _mm256_extractf128_si256(sse_256, 1)); + + // Store the results. + _mm_storel_epi64((__m128i *)&sse, sse_128); + return sse; +} + int64_t av1_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz) { __m256i sse_reg, ssz_reg, coeff_reg, dqcoeff_reg; diff --git a/media/libaom/src/av1/encoder/x86/highbd_fwd_txfm_sse4.c b/media/libaom/src/av1/encoder/x86/highbd_fwd_txfm_sse4.c index d2ed007ca9..73afc5d039 100644 --- a/media/libaom/src/av1/encoder/x86/highbd_fwd_txfm_sse4.c +++ b/media/libaom/src/av1/encoder/x86/highbd_fwd_txfm_sse4.c @@ -2094,22 +2094,22 @@ static const fwd_transform_1d_sse4_1 col_highbd_txfm4x4_arr[TX_TYPES] = { }; static const fwd_transform_1d_sse4_1 col_highbd_txfm8x32_arr[TX_TYPES] = { - av1_fdct32_new_sse4_1, // DCT_DCT - NULL, // ADST_DCT - NULL, // DCT_ADST - NULL, // ADST_ADST - NULL, // FLIPADST_DCT - NULL, // DCT_FLIPADST - NULL, // FLIPADST_FLIPADST - NULL, // ADST_FLIPADST - NULL, // FLIPADST_ADST - av1_idtx32_new_sse4_1, // IDTX - NULL, // V_DCT - NULL, // H_DCT - NULL, // V_ADST - NULL, // H_ADST - NULL, // V_FLIPADST - NULL // H_FLIPADST + av1_fdct32_sse4_1, // DCT_DCT + NULL, // ADST_DCT + NULL, // DCT_ADST + NULL, // ADST_ADST + NULL, // FLIPADST_DCT + NULL, // DCT_FLIPADST + NULL, // FLIPADST_FLIPADST + NULL, // ADST_FLIPADST + NULL, // FLIPADST_ADST + av1_idtx32_sse4_1, // IDTX + NULL, // V_DCT + NULL, // H_DCT + NULL, // V_ADST + NULL, // H_ADST + NULL, // V_FLIPADST + NULL // H_FLIPADST }; static const fwd_transform_1d_sse4_1 row_highbd_txfm8x32_arr[TX_TYPES] = { @@ -2303,7 +2303,7 @@ void av1_fwd_txfm2d_32x64_sse4_1(const int16_t *input, int32_t *coeff, // column transform load_buffer_32x8n(input, in, stride, 0, 0, shift[0], txfm_size_row); for (int i = 0; i < num_col; i++) { - av1_fdct64_new_sse4_1((in + i), (in + i), bitcol, num_col, num_col); + av1_fdct64_sse4_1((in + i), (in + i), bitcol, num_col, num_col); } for (int i = 0; i < num_col; i++) { col_txfm_16x16_rounding((in + i * txfm_size_row), -shift[1]); @@ -2312,7 +2312,7 @@ void av1_fwd_txfm2d_32x64_sse4_1(const int16_t *input, int32_t *coeff, // row transform for (int i = 0; i < num_row; i++) { - av1_fdct32_new_sse4_1((outcoef128 + i), (in + i), bitrow, num_row); + av1_fdct32_sse4_1((outcoef128 + i), (in + i), bitrow, num_row); } transpose_8nx8n(in, outcoef128, txfm_size_row, txfm_size_col); av1_round_shift_rect_array_32_sse4_1(outcoef128, outcoef128, 512, -shift[2], @@ -2347,7 +2347,7 @@ void av1_fwd_txfm2d_64x32_sse4_1(const int16_t *input, int32_t *coeff, } for (int i = 0; i < num_col; i++) { - av1_fdct32_new_sse4_1((in + i), (in + i), bitcol, num_col); + av1_fdct32_sse4_1((in + i), (in + i), bitcol, num_col); } for (int i = 0; i < num_row; i++) { @@ -2357,7 +2357,7 @@ void av1_fwd_txfm2d_64x32_sse4_1(const int16_t *input, int32_t *coeff, // row transform for (int i = 0; i < num_row; i++) { - av1_fdct64_new_sse4_1((outcoef128 + i), (in + i), bitrow, num_row, num_row); + av1_fdct64_sse4_1((outcoef128 + i), (in + i), bitrow, num_row, num_row); } transpose_8nx8n(in, outcoef128, txfm_size_row, txfm_size_col >> 1); av1_round_shift_rect_array_32_sse4_1(outcoef128, outcoef128, 512 >> 1, @@ -2549,7 +2549,7 @@ void av1_fwd_txfm2d_16x64_sse4_1(const int16_t *input, int32_t *coeff, } for (int i = 0; i < num_col; i++) { - av1_fdct64_new_sse4_1(in + i, outcoeff128 + i, bitcol, num_col, num_col); + av1_fdct64_sse4_1(in + i, outcoeff128 + i, bitcol, num_col, num_col); } col_txfm_16x16_rounding(outcoeff128, -shift[1]); @@ -2597,7 +2597,7 @@ void av1_fwd_txfm2d_64x16_sse4_1(const int16_t *input, int32_t *coeff, transpose_8nx8n(outcoeff128, in, txfm_size_col, txfm_size_row); for (int i = 0; i < 4; i++) { - av1_fdct64_new_sse4_1(in + i, in + i, bitrow, 4, 4); + av1_fdct64_sse4_1(in + i, in + i, bitrow, 4, 4); } transpose_8nx8n(in, outcoeff128, txfm_size_row, 32); (void)bd; diff --git a/media/libaom/src/av1/encoder/x86/highbd_temporal_filter_sse4.c b/media/libaom/src/av1/encoder/x86/highbd_temporal_filter_sse4.c deleted file mode 100644 index 768e19398b..0000000000 --- a/media/libaom/src/av1/encoder/x86/highbd_temporal_filter_sse4.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * 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 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 >= 0 && 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 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; - 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) { - 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) { - 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; - 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 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 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) { - 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 { - 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; - } - - 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) { - 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) { - 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; - } - - 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 >= 0 && 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; - - 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); - - 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/media/libaom/src/av1/encoder/x86/ml_sse3.c b/media/libaom/src/av1/encoder/x86/ml_sse3.c index 8a6c57071d..89b1e6a05b 100644 --- a/media/libaom/src/av1/encoder/x86/ml_sse3.c +++ b/media/libaom/src/av1/encoder/x86/ml_sse3.c @@ -162,7 +162,7 @@ void av1_nn_predict_sse3(const float *input_nodes, const float *layer_weights = nn_config->weights[layer]; const float *layer_bias = nn_config->bias[layer]; bool output_layer = (layer == nn_config->num_hidden_layers); - float *const output_nodes = output_layer ? output : buf[buf_index]; + float *const output_nodes = output_layer ? output : &buf[buf_index][0]; const int num_outputs = output_layer ? nn_config->num_outputs : nn_config->num_hidden_nodes[layer]; diff --git a/media/libaom/src/av1/encoder/x86/pickrst_avx2.c b/media/libaom/src/av1/encoder/x86/pickrst_avx2.c index 627ee6c06a..f8703a23ca 100644 --- a/media/libaom/src/av1/encoder/x86/pickrst_avx2.c +++ b/media/libaom/src/av1/encoder/x86/pickrst_avx2.c @@ -640,8 +640,8 @@ static AOM_INLINE void calc_proj_params_r0_r1_avx2( const uint8_t *src = src8; const uint8_t *dat = dat8; __m256i h00, h01, h11, c0, c1; - h00 = _mm256_setzero_si256(); - h01 = h11 = c0 = c1 = h00; + const __m256i zero = _mm256_setzero_si256(); + h01 = h11 = c0 = c1 = h00 = zero; for (int i = 0; i < height; ++i) { for (int j = 0; j < width; j += 8) { @@ -688,46 +688,36 @@ static AOM_INLINE void calc_proj_params_r0_r1_avx2( c1 = _mm256_add_epi64(c1, c1_odd); } } - const __m128i h00_128bit = _mm_add_epi64(_mm256_extracti128_si256(h00, 1), - _mm256_castsi256_si128(h00)); - const __m128i h00_val = - _mm_add_epi64(h00_128bit, _mm_srli_si128(h00_128bit, 8)); - const __m128i h01_128bit = _mm_add_epi64(_mm256_extracti128_si256(h01, 1), - _mm256_castsi256_si128(h01)); - const __m128i h01_val = - _mm_add_epi64(h01_128bit, _mm_srli_si128(h01_128bit, 8)); + __m256i c_low = _mm256_unpacklo_epi64(c0, c1); + const __m256i c_high = _mm256_unpackhi_epi64(c0, c1); + c_low = _mm256_add_epi64(c_low, c_high); + const __m128i c_128bit = _mm_add_epi64(_mm256_extracti128_si256(c_low, 1), + _mm256_castsi256_si128(c_low)); - const __m128i h11_128bit = _mm_add_epi64(_mm256_extracti128_si256(h11, 1), - _mm256_castsi256_si128(h11)); - const __m128i h11_val = - _mm_add_epi64(h11_128bit, _mm_srli_si128(h11_128bit, 8)); + __m256i h0x_low = _mm256_unpacklo_epi64(h00, h01); + const __m256i h0x_high = _mm256_unpackhi_epi64(h00, h01); + h0x_low = _mm256_add_epi64(h0x_low, h0x_high); + const __m128i h0x_128bit = _mm_add_epi64(_mm256_extracti128_si256(h0x_low, 1), + _mm256_castsi256_si128(h0x_low)); - const __m128i c0_128bit = _mm_add_epi64(_mm256_extracti128_si256(c0, 1), - _mm256_castsi256_si128(c0)); - const __m128i c0_val = _mm_add_epi64(c0_128bit, _mm_srli_si128(c0_128bit, 8)); + // Using the symmetric properties of H, calculations of H[1][0] are not + // needed. + __m256i h1x_low = _mm256_unpacklo_epi64(zero, h11); + const __m256i h1x_high = _mm256_unpackhi_epi64(zero, h11); + h1x_low = _mm256_add_epi64(h1x_low, h1x_high); + const __m128i h1x_128bit = _mm_add_epi64(_mm256_extracti128_si256(h1x_low, 1), + _mm256_castsi256_si128(h1x_low)); - const __m128i c1_128bit = _mm_add_epi64(_mm256_extracti128_si256(c1, 1), - _mm256_castsi256_si128(c1)); - const __m128i c1_val = _mm_add_epi64(c1_128bit, _mm_srli_si128(c1_128bit, 8)); - -#if ARCH_X86_64 - H[0][0] = _mm_extract_epi64(h00_val, 0); - H[0][1] = _mm_extract_epi64(h01_val, 0); - H[1][1] = _mm_extract_epi64(h11_val, 0); - C[0] = _mm_extract_epi64(c0_val, 0); - C[1] = _mm_extract_epi64(c1_val, 0); -#else - xx_storel_64(&H[0][0], h00_val); - xx_storel_64(&H[0][1], h01_val); - xx_storel_64(&H[1][1], h11_val); - xx_storel_64(&C[0], c0_val); - xx_storel_64(&C[1], c1_val); -#endif + xx_storeu_128(C, c_128bit); + xx_storeu_128(H[0], h0x_128bit); + xx_storeu_128(H[1], h1x_128bit); H[0][0] /= size; H[0][1] /= size; H[1][1] /= size; + + // Since H is a symmetric matrix H[1][0] = H[0][1]; C[0] /= size; C[1] /= size; @@ -745,8 +735,8 @@ static AOM_INLINE void calc_proj_params_r0_avx2(const uint8_t *src8, int width, const uint8_t *src = src8; const uint8_t *dat = dat8; __m256i h00, c0; - h00 = _mm256_setzero_si256(); - c0 = h00; + const __m256i zero = _mm256_setzero_si256(); + c0 = h00 = zero; for (int i = 0; i < height; ++i) { for (int j = 0; j < width; j += 8) { @@ -782,13 +772,11 @@ static AOM_INLINE void calc_proj_params_r0_avx2(const uint8_t *src8, int width, _mm256_castsi256_si128(c0)); const __m128i c0_val = _mm_add_epi64(c0_128bit, _mm_srli_si128(c0_128bit, 8)); -#if ARCH_X86_64 - H[0][0] = _mm_extract_epi64(h00_val, 0); - C[0] = _mm_extract_epi64(c0_val, 0); -#else - xx_storel_64(&H[0][0], h00_val); - xx_storel_64(&C[0], c0_val); -#endif + const __m128i c = _mm_unpacklo_epi64(c0_val, _mm256_castsi256_si128(zero)); + const __m128i h0x = _mm_unpacklo_epi64(h00_val, _mm256_castsi256_si128(zero)); + + xx_storeu_128(C, c); + xx_storeu_128(H[0], h0x); H[0][0] /= size; C[0] /= size; @@ -806,8 +794,8 @@ static AOM_INLINE void calc_proj_params_r1_avx2(const uint8_t *src8, int width, const uint8_t *src = src8; const uint8_t *dat = dat8; __m256i h11, c1; - h11 = _mm256_setzero_si256(); - c1 = h11; + const __m256i zero = _mm256_setzero_si256(); + c1 = h11 = zero; for (int i = 0; i < height; ++i) { for (int j = 0; j < width; j += 8) { @@ -844,13 +832,11 @@ static AOM_INLINE void calc_proj_params_r1_avx2(const uint8_t *src8, int width, _mm256_castsi256_si128(c1)); const __m128i c1_val = _mm_add_epi64(c1_128bit, _mm_srli_si128(c1_128bit, 8)); -#if ARCH_X86_64 - H[1][1] = _mm_extract_epi64(h11_val, 0); - C[1] = _mm_extract_epi64(c1_val, 0); -#else - xx_storel_64(&H[1][1], h11_val); - xx_storel_64(&C[1], c1_val); -#endif + const __m128i c = _mm_unpacklo_epi64(_mm256_castsi256_si128(zero), c1_val); + const __m128i h1x = _mm_unpacklo_epi64(_mm256_castsi256_si128(zero), h11_val); + + xx_storeu_128(C, c); + xx_storeu_128(H[1], h1x); H[1][1] /= size; C[1] /= size; diff --git a/media/libaom/src/av1/encoder/x86/temporal_filter_avx2.c b/media/libaom/src/av1/encoder/x86/temporal_filter_avx2.c new file mode 100644 index 0000000000..847f7283ce --- /dev/null +++ b/media/libaom/src/av1/encoder/x86/temporal_filter_avx2.c @@ -0,0 +1,284 @@ +/* + * 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 "av1/encoder/encoder.h" +#include "av1/encoder/temporal_filter.h" + +#define SSE_STRIDE (BW + 2) + +DECLARE_ALIGNED(32, static const uint32_t, sse_bytemask[4][8]) = { + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0 }, + { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0 }, + { 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0 }, + { 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } +}; + +DECLARE_ALIGNED(32, static const uint8_t, shufflemask_16b[2][16]) = { + { 0, 1, 0, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 11, 10, 11 } +}; + +static AOM_FORCE_INLINE void get_squared_error_16x16_avx2( + const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2, + const unsigned int stride2, const int block_width, const int block_height, + uint16_t *frame_sse, const unsigned int sse_stride) { + (void)block_width; + const uint8_t *src1 = frame1; + const uint8_t *src2 = frame2; + uint16_t *dst = frame_sse; + for (int i = 0; i < block_height; i++) { + __m128i vf1_128, vf2_128; + __m256i vf1, vf2, vdiff1, vsqdiff1; + + vf1_128 = _mm_loadu_si128((__m128i *)(src1)); + vf2_128 = _mm_loadu_si128((__m128i *)(src2)); + vf1 = _mm256_cvtepu8_epi16(vf1_128); + vf2 = _mm256_cvtepu8_epi16(vf2_128); + vdiff1 = _mm256_sub_epi16(vf1, vf2); + vsqdiff1 = _mm256_mullo_epi16(vdiff1, vdiff1); + + _mm256_storeu_si256((__m256i *)(dst), vsqdiff1); + // Set zero to uninitialized memory to avoid uninitialized loads later + *(uint32_t *)(dst + 16) = _mm_cvtsi128_si32(_mm_setzero_si128()); + + src1 += stride, src2 += stride2; + dst += sse_stride; + } +} + +static AOM_FORCE_INLINE void get_squared_error_32x32_avx2( + const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2, + const unsigned int stride2, const int block_width, const int block_height, + uint16_t *frame_sse, const unsigned int sse_stride) { + (void)block_width; + const uint8_t *src1 = frame1; + const uint8_t *src2 = frame2; + uint16_t *dst = frame_sse; + for (int i = 0; i < block_height; i++) { + __m256i vsrc1, vsrc2, vmin, vmax, vdiff, vdiff1, vdiff2, vres1, vres2; + + vsrc1 = _mm256_loadu_si256((__m256i *)src1); + vsrc2 = _mm256_loadu_si256((__m256i *)src2); + vmax = _mm256_max_epu8(vsrc1, vsrc2); + vmin = _mm256_min_epu8(vsrc1, vsrc2); + vdiff = _mm256_subs_epu8(vmax, vmin); + + __m128i vtmp1 = _mm256_castsi256_si128(vdiff); + __m128i vtmp2 = _mm256_extracti128_si256(vdiff, 1); + vdiff1 = _mm256_cvtepu8_epi16(vtmp1); + vdiff2 = _mm256_cvtepu8_epi16(vtmp2); + + vres1 = _mm256_mullo_epi16(vdiff1, vdiff1); + vres2 = _mm256_mullo_epi16(vdiff2, vdiff2); + _mm256_storeu_si256((__m256i *)(dst), vres1); + _mm256_storeu_si256((__m256i *)(dst + 16), vres2); + // Set zero to uninitialized memory to avoid uninitialized loads later + *(uint32_t *)(dst + 32) = _mm_cvtsi128_si32(_mm_setzero_si128()); + + src1 += stride; + src2 += stride2; + dst += sse_stride; + } +} + +static AOM_FORCE_INLINE __m256i xx_load_and_pad(uint16_t *src, int col, + int block_width) { + __m128i v128tmp = _mm_loadu_si128((__m128i *)(src)); + if (col == 0) { + // For the first column, replicate the first element twice to the left + v128tmp = _mm_shuffle_epi8(v128tmp, *(__m128i *)shufflemask_16b[0]); + } + if (col == block_width - 4) { + // For the last column, replicate the last element twice to the right + v128tmp = _mm_shuffle_epi8(v128tmp, *(__m128i *)shufflemask_16b[1]); + } + return _mm256_cvtepu16_epi32(v128tmp); +} + +static AOM_FORCE_INLINE int32_t xx_mask_and_hadd(__m256i vsum, int i) { + // Mask the required 5 values inside the vector + __m256i vtmp = _mm256_and_si256(vsum, *(__m256i *)sse_bytemask[i]); + __m128i v128a, v128b; + // Extract 256b as two 128b registers A and B + v128a = _mm256_castsi256_si128(vtmp); + v128b = _mm256_extracti128_si256(vtmp, 1); + // A = [A0+B0, A1+B1, A2+B2, A3+B3] + v128a = _mm_add_epi32(v128a, v128b); + // B = [A2+B2, A3+B3, 0, 0] + v128b = _mm_srli_si128(v128a, 8); + // A = [A0+B0+A2+B2, A1+B1+A3+B3, X, X] + v128a = _mm_add_epi32(v128a, v128b); + // B = [A1+B1+A3+B3, 0, 0, 0] + v128b = _mm_srli_si128(v128a, 4); + // A = [A0+B0+A2+B2+A1+B1+A3+B3, X, X, X] + v128a = _mm_add_epi32(v128a, v128b); + return _mm_extract_epi32(v128a, 0); +} + +static void apply_temporal_filter_planewise( + const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2, + const unsigned int stride2, const int block_width, const int block_height, + const double sigma, const int decay_control, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + unsigned int *accumulator, uint16_t *count, uint16_t *luma_sq_error, + uint16_t *chroma_sq_error, int plane, int ss_x_shift, int ss_y_shift) { + assert(TF_PLANEWISE_FILTER_WINDOW_LENGTH == 5); + assert(((block_width == 16) || (block_width == 32)) && + ((block_height == 16) || (block_height == 32))); + if (plane > PLANE_TYPE_Y) assert(chroma_sq_error != NULL); + + uint32_t acc_5x5_sse[BH][BW]; + const double h = decay_control * (0.7 + log(sigma + 1.0)); + const double q = AOMMIN((double)(q_factor * q_factor) / 256.0, 1); + uint16_t *frame_sse = + (plane == PLANE_TYPE_Y) ? luma_sq_error : chroma_sq_error; + + if (block_width == 32) { + get_squared_error_32x32_avx2(frame1, stride, frame2, stride2, block_width, + block_height, frame_sse, SSE_STRIDE); + } else { + get_squared_error_16x16_avx2(frame1, stride, frame2, stride2, block_width, + block_height, frame_sse, SSE_STRIDE); + } + + __m256i vsrc[5]; + + // Traverse 4 columns at a time + // First and last columns will require padding + for (int col = 0; col < block_width; col += 4) { + uint16_t *src = (col) ? frame_sse + col - 2 : frame_sse; + + // Load and pad(for first and last col) 3 rows from the top + for (int i = 2; i < 5; i++) { + vsrc[i] = xx_load_and_pad(src, col, block_width); + src += SSE_STRIDE; + } + + // Copy first row to first 2 vectors + vsrc[0] = vsrc[2]; + vsrc[1] = vsrc[2]; + + for (int row = 0; row < block_height; row++) { + __m256i vsum = _mm256_setzero_si256(); + + // Add 5 consecutive rows + for (int i = 0; i < 5; i++) { + vsum = _mm256_add_epi32(vsum, vsrc[i]); + } + + // Push all elements by one element to the top + for (int i = 0; i < 4; i++) { + vsrc[i] = vsrc[i + 1]; + } + + // Load next row to the last element + if (row <= block_height - 4) { + vsrc[4] = xx_load_and_pad(src, col, block_width); + src += SSE_STRIDE; + } else { + vsrc[4] = vsrc[3]; + } + + // Accumulate the sum horizontally + for (int i = 0; i < 4; i++) { + acc_5x5_sse[row][col + i] = xx_mask_and_hadd(vsum, i); + } + } + } + + for (int i = 0, k = 0; i < block_height; i++) { + for (int j = 0; j < block_width; j++, k++) { + const int pixel_value = frame2[i * stride2 + j]; + + int diff_sse = acc_5x5_sse[i][j]; + int num_ref_pixels = + TF_PLANEWISE_FILTER_WINDOW_LENGTH * TF_PLANEWISE_FILTER_WINDOW_LENGTH; + + // Filter U-plane and V-plane using Y-plane. This is because motion + // search is only done on Y-plane, so the information from Y-plane will + // be more accurate. + if (plane != PLANE_TYPE_Y) { + for (int ii = 0; ii < (1 << ss_y_shift); ++ii) { + for (int jj = 0; jj < (1 << ss_x_shift); ++jj) { + const int yy = (i << ss_y_shift) + ii; // Y-coord on Y-plane. + const int xx = (j << ss_x_shift) + jj; // X-coord on Y-plane. + diff_sse += luma_sq_error[yy * SSE_STRIDE + xx]; + ++num_ref_pixels; + } + } + } + + const double window_error = (double)(diff_sse) / num_ref_pixels; + const int subblock_idx = + (i >= block_height / 2) * 2 + (j >= block_width / 2); + const double block_error = + (double)(use_subblock ? subblock_mses[subblock_idx] : block_mse); + + const double scaled_diff = + AOMMAX(-(window_error + block_error / 10) / (2 * h * h * q), -15.0); + const int adjusted_weight = + (int)(exp(scaled_diff) * TF_PLANEWISE_FILTER_WEIGHT_SCALE); + + count[k] += adjusted_weight; + accumulator[k] += adjusted_weight * pixel_value; + } + } +} + +void av1_apply_temporal_filter_planewise_avx2( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_levels, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + const uint8_t *pred, uint32_t *accum, uint16_t *count) { + const int is_high_bitdepth = ref_frame->flags & YV12_FLAG_HIGHBITDEPTH; + if (is_high_bitdepth) { + assert(0 && "Only support low bit-depth with avx2!"); + } + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + + const int frame_height = ref_frame->heights[0] << mbd->plane[0].subsampling_y; + const int decay_control = frame_height >= 720 ? 4 : 3; + + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + uint16_t luma_sq_error[SSE_STRIDE * BH]; + uint16_t *chroma_sq_error = + (num_planes > 0) + ? (uint16_t *)aom_malloc(SSE_STRIDE * BH * sizeof(uint16_t)) + : NULL; + + for (int plane = 0; plane < num_planes; ++plane) { + const uint32_t plane_h = mb_height >> mbd->plane[plane].subsampling_y; + const uint32_t plane_w = mb_width >> mbd->plane[plane].subsampling_x; + const uint32_t frame_stride = ref_frame->strides[plane == 0 ? 0 : 1]; + const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w; + + const uint8_t *ref = ref_frame->buffers[plane] + frame_offset; + const int ss_x_shift = + mbd->plane[plane].subsampling_x - mbd->plane[0].subsampling_x; + const int ss_y_shift = + mbd->plane[plane].subsampling_y - mbd->plane[0].subsampling_y; + + apply_temporal_filter_planewise( + ref, frame_stride, pred + mb_pels * plane, plane_w, plane_w, plane_h, + noise_levels[plane], decay_control, use_subblock, block_mse, + subblock_mses, q_factor, accum + mb_pels * plane, + count + mb_pels * plane, luma_sq_error, chroma_sq_error, plane, + ss_x_shift, ss_y_shift); + } + if (chroma_sq_error != NULL) aom_free(chroma_sq_error); +} diff --git a/media/libaom/src/av1/encoder/x86/temporal_filter_sse2.c b/media/libaom/src/av1/encoder/x86/temporal_filter_sse2.c new file mode 100644 index 0000000000..1722fac86c --- /dev/null +++ b/media/libaom/src/av1/encoder/x86/temporal_filter_sse2.c @@ -0,0 +1,262 @@ +/* + * 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 "av1/encoder/encoder.h" +#include "av1/encoder/temporal_filter.h" + +// For the squared error buffer, keep a padding for 4 samples +#define SSE_STRIDE (BW + 4) + +DECLARE_ALIGNED(32, static const uint32_t, sse_bytemask_2x4[4][2][4]) = { + { { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 } }, + { { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 } }, + { { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 } }, + { { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF } } +}; + +static void get_squared_error(const uint8_t *frame1, const unsigned int stride, + const uint8_t *frame2, const unsigned int stride2, + const int block_width, const int block_height, + uint16_t *frame_sse, + const unsigned int dst_stride) { + const uint8_t *src1 = frame1; + const uint8_t *src2 = frame2; + uint16_t *dst = frame_sse; + + for (int i = 0; i < block_height; i++) { + for (int j = 0; j < block_width; j += 16) { + // Set zero to uninitialized memory to avoid uninitialized loads later + *(uint32_t *)(dst) = _mm_cvtsi128_si32(_mm_setzero_si128()); + + __m128i vsrc1 = _mm_loadu_si128((__m128i *)(src1 + j)); + __m128i vsrc2 = _mm_loadu_si128((__m128i *)(src2 + j)); + + __m128i vmax = _mm_max_epu8(vsrc1, vsrc2); + __m128i vmin = _mm_min_epu8(vsrc1, vsrc2); + __m128i vdiff = _mm_subs_epu8(vmax, vmin); + + __m128i vzero = _mm_setzero_si128(); + __m128i vdiff1 = _mm_unpacklo_epi8(vdiff, vzero); + __m128i vdiff2 = _mm_unpackhi_epi8(vdiff, vzero); + + __m128i vres1 = _mm_mullo_epi16(vdiff1, vdiff1); + __m128i vres2 = _mm_mullo_epi16(vdiff2, vdiff2); + + _mm_storeu_si128((__m128i *)(dst + j + 2), vres1); + _mm_storeu_si128((__m128i *)(dst + j + 10), vres2); + } + + // Set zero to uninitialized memory to avoid uninitialized loads later + *(uint32_t *)(dst + block_width + 2) = + _mm_cvtsi128_si32(_mm_setzero_si128()); + + src1 += stride; + src2 += stride2; + dst += dst_stride; + } +} + +static void xx_load_and_pad(uint16_t *src, __m128i *dstvec, int col, + int block_width) { + __m128i vtmp = _mm_loadu_si128((__m128i *)src); + __m128i vzero = _mm_setzero_si128(); + __m128i vtmp1 = _mm_unpacklo_epi16(vtmp, vzero); + __m128i vtmp2 = _mm_unpackhi_epi16(vtmp, vzero); + // For the first column, replicate the first element twice to the left + dstvec[0] = (col) ? vtmp1 : _mm_shuffle_epi32(vtmp1, 0xEA); + // For the last column, replicate the last element twice to the right + dstvec[1] = (col < block_width - 4) ? vtmp2 : _mm_shuffle_epi32(vtmp2, 0x54); +} + +static int32_t xx_mask_and_hadd(__m128i vsum1, __m128i vsum2, int i) { + __m128i veca, vecb; + // Mask and obtain the required 5 values inside the vector + veca = _mm_and_si128(vsum1, *(__m128i *)sse_bytemask_2x4[i][0]); + vecb = _mm_and_si128(vsum2, *(__m128i *)sse_bytemask_2x4[i][1]); + // A = [A0+B0, A1+B1, A2+B2, A3+B3] + veca = _mm_add_epi32(veca, vecb); + // B = [A2+B2, A3+B3, 0, 0] + vecb = _mm_srli_si128(veca, 8); + // A = [A0+B0+A2+B2, A1+B1+A3+B3, X, X] + veca = _mm_add_epi32(veca, vecb); + // B = [A1+B1+A3+B3, 0, 0, 0] + vecb = _mm_srli_si128(veca, 4); + // A = [A0+B0+A2+B2+A1+B1+A3+B3, X, X, X] + veca = _mm_add_epi32(veca, vecb); + return _mm_cvtsi128_si32(veca); +} + +static void apply_temporal_filter_planewise( + const uint8_t *frame1, const unsigned int stride, const uint8_t *frame2, + const unsigned int stride2, const int block_width, const int block_height, + const double sigma, const int decay_control, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + unsigned int *accumulator, uint16_t *count, uint16_t *luma_sq_error, + uint16_t *chroma_sq_error, int plane, int ss_x_shift, int ss_y_shift) { + assert(TF_PLANEWISE_FILTER_WINDOW_LENGTH == 5); + assert(((block_width == 16) || (block_width == 32)) && + ((block_height == 16) || (block_height == 32))); + if (plane > PLANE_TYPE_Y) assert(chroma_sq_error != NULL); + + uint32_t acc_5x5_sse[BH][BW]; + const double h = decay_control * (0.7 + log(sigma + 1.0)); + const double q = AOMMIN((double)(q_factor * q_factor) / 256.0, 1); + uint16_t *frame_sse = + (plane == PLANE_TYPE_Y) ? luma_sq_error : chroma_sq_error; + + get_squared_error(frame1, stride, frame2, stride2, block_width, block_height, + frame_sse, SSE_STRIDE); + + __m128i vsrc[5][2]; + + // Traverse 4 columns at a time + // First and last columns will require padding + for (int col = 0; col < block_width; col += 4) { + uint16_t *src = frame_sse + col; + + // Load and pad(for first and last col) 3 rows from the top + for (int i = 2; i < 5; i++) { + xx_load_and_pad(src, vsrc[i], col, block_width); + src += SSE_STRIDE; + } + + // Padding for top 2 rows + vsrc[0][0] = vsrc[2][0]; + vsrc[0][1] = vsrc[2][1]; + vsrc[1][0] = vsrc[2][0]; + vsrc[1][1] = vsrc[2][1]; + + for (int row = 0; row < block_height; row++) { + __m128i vsum1 = _mm_setzero_si128(); + __m128i vsum2 = _mm_setzero_si128(); + + // Add 5 consecutive rows + for (int i = 0; i < 5; i++) { + vsum1 = _mm_add_epi32(vsrc[i][0], vsum1); + vsum2 = _mm_add_epi32(vsrc[i][1], vsum2); + } + + // Push all elements by one element to the top + for (int i = 0; i < 4; i++) { + vsrc[i][0] = vsrc[i + 1][0]; + vsrc[i][1] = vsrc[i + 1][1]; + } + + if (row <= block_height - 4) { + // Load next row + xx_load_and_pad(src, vsrc[4], col, block_width); + src += SSE_STRIDE; + } else { + // Padding for bottom 2 rows + vsrc[4][0] = vsrc[3][0]; + vsrc[4][1] = vsrc[3][1]; + } + + // Accumulate the sum horizontally + for (int i = 0; i < 4; i++) { + acc_5x5_sse[row][col + i] = xx_mask_and_hadd(vsum1, vsum2, i); + } + } + } + + for (int i = 0, k = 0; i < block_height; i++) { + for (int j = 0; j < block_width; j++, k++) { + const int pixel_value = frame2[i * stride2 + j]; + + int diff_sse = acc_5x5_sse[i][j]; + int num_ref_pixels = + TF_PLANEWISE_FILTER_WINDOW_LENGTH * TF_PLANEWISE_FILTER_WINDOW_LENGTH; + + // Filter U-plane and V-plane using Y-plane. This is because motion + // search is only done on Y-plane, so the information from Y-plane will + // be more accurate. + if (plane != PLANE_TYPE_Y) { + for (int ii = 0; ii < (1 << ss_y_shift); ++ii) { + for (int jj = 0; jj < (1 << ss_x_shift); ++jj) { + const int yy = (i << ss_y_shift) + ii; // Y-coord on Y-plane. + const int xx = (j << ss_x_shift) + jj + 2; // X-coord on Y-plane. + const int ww = SSE_STRIDE; // Stride of Y-plane. + diff_sse += luma_sq_error[yy * ww + xx]; + ++num_ref_pixels; + } + } + } + + const double window_error = (double)(diff_sse) / num_ref_pixels; + const int subblock_idx = + (i >= block_height / 2) * 2 + (j >= block_width / 2); + const double block_error = + (double)(use_subblock ? subblock_mses[subblock_idx] : block_mse); + + const double scaled_diff = + AOMMAX(-(window_error + block_error / 10) / (2 * h * h * q), -15.0); + const int adjusted_weight = + (int)(exp(scaled_diff) * TF_PLANEWISE_FILTER_WEIGHT_SCALE); + + count[k] += adjusted_weight; + accumulator[k] += adjusted_weight * pixel_value; + } + } +} + +void av1_apply_temporal_filter_planewise_sse2( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_levels, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + const uint8_t *pred, uint32_t *accum, uint16_t *count) { + const int is_high_bitdepth = ref_frame->flags & YV12_FLAG_HIGHBITDEPTH; + if (is_high_bitdepth) { + assert(0 && "Only support low bit-depth with sse2!"); + } + assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE); + + const int frame_height = ref_frame->heights[0] << mbd->plane[0].subsampling_y; + const int decay_control = frame_height >= 720 ? 4 : 3; + + const int mb_height = block_size_high[block_size]; + const int mb_width = block_size_wide[block_size]; + const int mb_pels = mb_height * mb_width; + uint16_t luma_sq_error[SSE_STRIDE * BH]; + uint16_t *chroma_sq_error = + (num_planes > 0) + ? (uint16_t *)aom_malloc(SSE_STRIDE * BH * sizeof(uint16_t)) + : NULL; + + for (int plane = 0; plane < num_planes; ++plane) { + const uint32_t plane_h = mb_height >> mbd->plane[plane].subsampling_y; + const uint32_t plane_w = mb_width >> mbd->plane[plane].subsampling_x; + const uint32_t frame_stride = ref_frame->strides[plane == 0 ? 0 : 1]; + const int frame_offset = mb_row * plane_h * frame_stride + mb_col * plane_w; + + const uint8_t *ref = ref_frame->buffers[plane] + frame_offset; + const int ss_x_shift = + mbd->plane[plane].subsampling_x - mbd->plane[0].subsampling_x; + const int ss_y_shift = + mbd->plane[plane].subsampling_y - mbd->plane[0].subsampling_y; + + apply_temporal_filter_planewise( + ref, frame_stride, pred + mb_pels * plane, plane_w, plane_w, plane_h, + noise_levels[plane], decay_control, use_subblock, block_mse, + subblock_mses, q_factor, accum + mb_pels * plane, + count + mb_pels * plane, luma_sq_error, chroma_sq_error, plane, + ss_x_shift, ss_y_shift); + } + if (chroma_sq_error != NULL) aom_free(chroma_sq_error); +} diff --git a/media/libaom/src/av1/encoder/x86/temporal_filter_sse4.c b/media/libaom/src/av1/encoder/x86/temporal_filter_sse4.c index 6151e87559..e3f9f5f276 100644 --- a/media/libaom/src/av1/encoder/x86/temporal_filter_sse4.c +++ b/media/libaom/src/av1/encoder/x86/temporal_filter_sse4.c @@ -18,6 +18,10 @@ #include "av1/encoder/temporal_filter.h" #include "av1/encoder/x86/temporal_filter_constants.h" +////////////////////////// +// Low bit-depth Begins // +////////////////////////// + // 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, @@ -921,14 +925,47 @@ static void apply_temporal_filter_chroma( 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) { +static void apply_temporal_filter_yuv( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int strength, const int use_subblock, + const int *subblock_filter_weights, const uint8_t *pred, uint32_t *accum, + uint16_t *count) { + const int use_whole_blk = !use_subblock; + const int *blk_fw = subblock_filter_weights; + + // Block information (Y-plane). + const unsigned int block_height = block_size_high[block_size]; + const unsigned int block_width = block_size_wide[block_size]; + const int mb_pels = block_height * block_width; + const int y_src_stride = ref_frame->y_stride; + const int y_pre_stride = block_width; + const int mb_y_src_offset = + mb_row * block_height * ref_frame->y_stride + mb_col * block_width; + + // Block information (UV-plane). + const int ss_y = mbd->plane[1].subsampling_y; + const int ss_x = mbd->plane[1].subsampling_x; + const unsigned int uv_height = block_height >> ss_y; + const unsigned int uv_width = block_width >> ss_x; + const int uv_src_stride = ref_frame->uv_stride; + const int uv_pre_stride = block_width >> ss_x; + const int mb_uv_src_offset = + mb_row * uv_height * ref_frame->uv_stride + mb_col * uv_width; + + const uint8_t *y_src = ref_frame->y_buffer + mb_y_src_offset; + const uint8_t *u_src = ref_frame->u_buffer + mb_uv_src_offset; + const uint8_t *v_src = ref_frame->v_buffer + mb_uv_src_offset; + const uint8_t *y_pre = pred; + const uint8_t *u_pre = pred + mb_pels; + const uint8_t *v_pre = pred + mb_pels * 2; + uint32_t *y_accum = accum; + uint32_t *u_accum = accum + mb_pels; + uint32_t *v_accum = accum + mb_pels * 2; + uint16_t *y_count = count; + uint16_t *u_count = count + mb_pels; + uint16_t *v_count = count + mb_pels * 2; + const unsigned int chroma_height = block_height >> ss_y, chroma_width = block_width >> ss_x; @@ -1004,3 +1041,1004 @@ void av1_apply_temporal_filter_sse4_1( strength, blk_fw_ptr, use_whole_blk, u_accum, u_count, v_accum, v_count, y_dist_ptr, u_dist_ptr, v_dist_ptr); } + +//////////////////////// +// Low bit-depth Ends // +//////////////////////// + +/////////////////////////// +// High bit-depth Begins // +/////////////////////////// + +// 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 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 >= 0 && 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 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; + 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) { + 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) { + 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; + 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 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 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) { + 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 { + 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; + } + + 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) { + 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) { + 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; + } + + 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); +} + +static void highbd_apply_temporal_filter_yuv( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int strength, const int use_subblock, + const int *subblock_filter_weights, const uint8_t *pred, uint32_t *accum, + uint16_t *count) { + const int use_whole_blk = !use_subblock; + const int *blk_fw = subblock_filter_weights; + + // Block information (Y-plane). + const unsigned int block_height = block_size_high[block_size]; + const unsigned int block_width = block_size_wide[block_size]; + const int mb_pels = block_height * block_width; + const int y_src_stride = ref_frame->y_stride; + const int y_pre_stride = block_width; + const int mb_y_src_offset = + mb_row * block_height * ref_frame->y_stride + mb_col * block_width; + + // Block information (UV-plane). + const int ss_y = mbd->plane[1].subsampling_y; + const int ss_x = mbd->plane[1].subsampling_x; + const unsigned int uv_height = block_height >> ss_y; + const unsigned int uv_width = block_width >> ss_x; + const int uv_src_stride = ref_frame->uv_stride; + const int uv_pre_stride = block_width >> ss_x; + const int mb_uv_src_offset = + mb_row * uv_height * ref_frame->uv_stride + mb_col * uv_width; + + const uint8_t *y_src = ref_frame->y_buffer + mb_y_src_offset; + const uint8_t *u_src = ref_frame->u_buffer + mb_uv_src_offset; + const uint8_t *v_src = ref_frame->v_buffer + mb_uv_src_offset; + const uint8_t *y_pre = pred; + const uint8_t *u_pre = pred + mb_pels; + const uint8_t *v_pre = pred + mb_pels * 2; + uint32_t *y_accum = accum; + uint32_t *u_accum = accum + mb_pels; + uint32_t *v_accum = accum + mb_pels * 2; + uint16_t *y_count = count; + uint16_t *u_count = count + mb_pels; + uint16_t *v_count = count + mb_pels * 2; + + 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 >= 0 && 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; + + 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); + + 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); +} + +///////////////////////// +// High bit-depth Ends // +///////////////////////// + +void av1_apply_temporal_filter_yuv_sse4_1( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const int strength, const int use_subblock, + const int *subblock_filter_weights, const uint8_t *pred, uint32_t *accum, + uint16_t *count) { + const int is_high_bitdepth = ref_frame->flags & YV12_FLAG_HIGHBITDEPTH; + // TODO(any): Need to support when `num_planes != 3`, like C implementation. + assert(num_planes == 3); + (void)num_planes; + if (is_high_bitdepth) { + highbd_apply_temporal_filter_yuv( + ref_frame, mbd, block_size, mb_row, mb_col, strength, use_subblock, + subblock_filter_weights, pred, accum, count); + } else { + apply_temporal_filter_yuv(ref_frame, mbd, block_size, mb_row, mb_col, + strength, use_subblock, subblock_filter_weights, + pred, accum, count); + } +} diff --git a/media/libaom/src/build/.gitattributes b/media/libaom/src/build/.gitattributes new file mode 100644 index 0000000000..03db79bc08 --- /dev/null +++ b/media/libaom/src/build/.gitattributes @@ -0,0 +1,2 @@ +*-vs8/*.rules -crlf +*-msvs/*.rules -crlf diff --git a/media/libaom/src/build/cmake/aom_config_defaults.cmake b/media/libaom/src/build/cmake/aom_config_defaults.cmake index 5a043eca4b..f9e70eb248 100644 --- a/media/libaom/src/build/cmake/aom_config_defaults.cmake +++ b/media/libaom/src/build/cmake/aom_config_defaults.cmake @@ -81,7 +81,6 @@ set_aom_config_var(CONFIG_OS_SUPPORT 0 "Internal flag.") set_aom_config_var(CONFIG_PIC 0 "Build with PIC enabled.") set_aom_config_var(CONFIG_RUNTIME_CPU_DETECT 1 "Runtime CPU detection support.") set_aom_config_var(CONFIG_SHARED 0 "Build shared libs.") -set_aom_config_var(CONFIG_STATIC 1 "Build static libs.") set_aom_config_var(CONFIG_WEBM_IO 1 "Enables WebM support.") # Debugging flags. @@ -108,6 +107,7 @@ set_aom_config_var(CONFIG_SIZE_LIMIT 0 "Limit max decode width/height.") set_aom_config_var(CONFIG_SPATIAL_RESAMPLING 1 "Spatial resampling.") set_aom_config_var(DECODE_HEIGHT_LIMIT 0 "Set limit for decode height.") set_aom_config_var(DECODE_WIDTH_LIMIT 0 "Set limit for decode width.") +set_aom_config_var(CONFIG_TUNE_VMAF 0 "Enable encoding tuning for VMAF.") # AV1 experiment flags. set_aom_config_var(CONFIG_SPEED_STATS 0 "AV1 experiment flag.") diff --git a/media/libaom/src/build/cmake/aom_configure.cmake b/media/libaom/src/build/cmake/aom_configure.cmake index a89336b810..224a46587c 100644 --- a/media/libaom/src/build/cmake/aom_configure.cmake +++ b/media/libaom/src/build/cmake/aom_configure.cmake @@ -112,7 +112,6 @@ endif() if(BUILD_SHARED_LIBS) set(CONFIG_PIC 1) set(CONFIG_SHARED 1) - set(CONFIG_STATIC 0) endif() if(NOT MSVC) @@ -154,21 +153,26 @@ elseif("${AOM_TARGET_CPU}" MATCHES "arm") if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin") set(AS_EXECUTABLE as) set(AOM_AS_FLAGS -arch ${AOM_TARGET_CPU} -isysroot ${CMAKE_OSX_SYSROOT}) - elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Linux") - if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE as) - endif() elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Windows") if(NOT AS_EXECUTABLE) set(AS_EXECUTABLE ${CMAKE_C_COMPILER} -c -mimplicit-it=always) endif() + else() + if(NOT AS_EXECUTABLE) + set(AS_EXECUTABLE as) + endif() endif() - if(NOT AS_EXECUTABLE) + find_program(as_executable_found ${AS_EXECUTABLE}) + if(NOT as_executable_found) message( FATAL_ERROR - "Unknown assembler for: ${AOM_TARGET_CPU}-${AOM_TARGET_SYSTEM}") + "Unable to find assembler and optimizations are enabled." + "Searched for ${AS_EXECUTABLE}. Install it, add it to your path, or " + "set the assembler directly by adding -DAS_EXECUTABLE= " + "to your CMake command line." + "To build without optimizations, add -DAOM_TARGET_CPU=generic to your " + "cmake command line.") endif() - string(STRIP "${AOM_AS_FLAGS}" AOM_AS_FLAGS) endif() @@ -273,9 +277,10 @@ else() add_compiler_flag_if_supported("-Wdisabled-optimization") add_compiler_flag_if_supported("-Wextra") add_compiler_flag_if_supported("-Wfloat-conversion") - add_compiler_flag_if_supported("-Wimplicit-function-declaration") + add_c_flag_if_supported("-Wimplicit-function-declaration") add_compiler_flag_if_supported("-Wlogical-op") add_compiler_flag_if_supported("-Wpointer-arith") + add_compiler_flag_if_supported("-Wshorten-64-to-32") add_compiler_flag_if_supported("-Wsign-compare") add_compiler_flag_if_supported("-Wstring-conversion") add_compiler_flag_if_supported("-Wtype-limits") @@ -291,17 +296,13 @@ else() add_c_flag_if_supported("-Wstack-usage=170000") add_cxx_flag_if_supported("-Wstack-usage=270000") elseif(CONFIG_RD_DEBUG) # Another case where higher stack usage is expected. - add_c_flag_if_supported("-Wstack-usage=111000") + add_c_flag_if_supported("-Wstack-usage=117000") add_cxx_flag_if_supported("-Wstack-usage=240000") else() add_c_flag_if_supported("-Wstack-usage=100000") add_cxx_flag_if_supported("-Wstack-usage=240000") endif() - # TODO(jzern): this could be added as a cxx flags for test/*.cc only, avoiding - # third_party. - add_c_flag_if_supported("-Wshorten-64-to-32") - # Add -Wshadow only for C files to avoid massive gtest warning spam. add_c_flag_if_supported("-Wshadow") diff --git a/media/libaom/src/build/cmake/aom_install.cmake b/media/libaom/src/build/cmake/aom_install.cmake index 02ee9eeffc..cd40fe4245 100644 --- a/media/libaom/src/build/cmake/aom_install.cmake +++ b/media/libaom/src/build/cmake/aom_install.cmake @@ -72,7 +72,11 @@ macro(setup_aom_install_targets) endif() endif() - set(AOM_INSTALL_LIBS aom) + if(BUILD_SHARED_LIBS) + set(AOM_INSTALL_LIBS aom aom_static) + else() + set(AOM_INSTALL_LIBS aom) + endif() # Setup the install rules. install( diff --git a/media/libaom/src/build/cmake/aom_optimization.cmake b/media/libaom/src/build/cmake/aom_optimization.cmake index 9879ea7451..d8b258f1e6 100644 --- a/media/libaom/src/build/cmake/aom_optimization.cmake +++ b/media/libaom/src/build/cmake/aom_optimization.cmake @@ -35,11 +35,10 @@ endfunction() # $opt_name is used to name the target. $target_to_update is made dependent upon # the created target. # -# Note: the libaom target is always updated because OBJECT libraries have rules -# that disallow the direct addition of .o files to them as dependencies. Static -# libraries do not have this limitation. -function(add_intrinsics_object_library flag opt_name target_to_update sources - dependent_target) +# Note: this function always updates the aom, and aom_static targets because +# OBJECT libraries have rules that disallow the direct addition of .o files to +# them as dependencies. Static and shared libraries do not have this limitation. +function(add_intrinsics_object_library flag opt_name target_to_update sources) if("${${sources}}" STREQUAL "") return() endif() @@ -50,12 +49,29 @@ function(add_intrinsics_object_library flag opt_name target_to_update sources get_msvc_intrinsic_flag(${flag} "flag") endif() + if("${flag}" STREQUAL "-mavx2") + unset(FLAG_SUPPORTED) + check_c_compiler_flag("-mno-avx256-split-unaligned-load" FLAG_SUPPORTED) + if(${FLAG_SUPPORTED}) + set(flag "${flag} -mno-avx256-split-unaligned-load") + endif() + + unset(FLAG_SUPPORTED) + check_c_compiler_flag("-mno-avx256-split-unaligned-store" FLAG_SUPPORTED) + if(${FLAG_SUPPORTED}) + set(flag "${flag} -mno-avx256-split-unaligned-store") + endif() + endif() + if(flag) separate_arguments(flag) target_compile_options(${target_name} PUBLIC ${flag}) endif() - target_sources(${dependent_target} PRIVATE $) + target_sources(aom PRIVATE $) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE $) + endif() # Add the new lib target to the global list of aom library targets. list(APPEND AOM_LIB_TARGETS ${target_name}) @@ -83,24 +99,20 @@ function(get_asm_obj_format out_format) if("${AOM_TARGET_CPU}" STREQUAL "x86_64") if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin") set(objformat "macho64") - elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Linux") - set(objformat "elf64") elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS" OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows") set(objformat "win64") else() - message(FATAL_ERROR "Unknown obj format: ${AOM_TARGET_SYSTEM}") + set(objformat "elf64") endif() elseif("${AOM_TARGET_CPU}" STREQUAL "x86") if("${AOM_TARGET_SYSTEM}" STREQUAL "Darwin") set(objformat "macho32") - elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Linux") - set(objformat "elf32") elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS" OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows") set(objformat "win32") else() - message(FATAL_ERROR "Unknown obj format: ${AOM_TARGET_SYSTEM}") + set(objformat "elf32") endif() else() message( @@ -112,10 +124,10 @@ endfunction() # Adds library target named $lib_name for ASM files in variable named by # $asm_sources. Builds an output directory path from $lib_name. Links $lib_name -# into $dependent_target. Generates a dummy C file with a dummy function to -# ensure that all cmake generators can determine the linker language, and that -# build tools don't complain that an object exposes no symbols. -function(add_asm_library lib_name asm_sources dependent_target) +# into the aom library target(s). Generates a dummy C file with a dummy function +# to ensure that all cmake generators can determine the linker language, and +# that build tools don't complain that an object exposes no symbols. +function(add_asm_library lib_name asm_sources) if("${${asm_sources}}" STREQUAL "") return() endif() @@ -141,6 +153,9 @@ function(add_asm_library lib_name asm_sources dependent_target) WORKING_DIRECTORY "${AOM_CONFIG_DIR}" VERBATIM) target_sources(aom PRIVATE "${asm_object}") + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE "${asm_object}") + endif() endforeach() # The above created a target containing only ASM sources. Cmake needs help @@ -172,7 +187,13 @@ function(test_nasm) message( FATAL_ERROR "Unsupported nasm: macho32 object format not supported.") endif() - elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Linux") + elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS" + OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows") + if(NOT "${nasm_helptext}" MATCHES "win32") + message( + FATAL_ERROR "Unsupported nasm: win32 object format not supported.") + endif() + else() if(NOT "${nasm_helptext}" MATCHES "elf32") message( FATAL_ERROR "Unsupported nasm: elf32 object format not supported.") @@ -184,7 +205,13 @@ function(test_nasm) message( FATAL_ERROR "Unsupported nasm: macho64 object format not supported.") endif() - elseif("${AOM_TARGET_SYSTEM}" STREQUAL "Linux") + elseif("${AOM_TARGET_SYSTEM}" STREQUAL "MSYS" + OR "${AOM_TARGET_SYSTEM}" STREQUAL "Windows") + if(NOT "${nasm_helptext}" MATCHES "win64") + message( + FATAL_ERROR "Unsupported nasm: win64 object format not supported.") + endif() + else() if(NOT "${nasm_helptext}" MATCHES "elf64") message( FATAL_ERROR "Unsupported nasm: elf64 object format not supported.") diff --git a/media/libaom/src/common/args.c b/media/libaom/src/common/args.c index 7131e24dee..ec2a863534 100644 --- a/media/libaom/src/common/args.c +++ b/media/libaom/src/common/args.c @@ -17,6 +17,7 @@ #include "aom/aom_integer.h" #include "aom_ports/msvc.h" +#include "aom/aom_codec.h" #if defined(__GNUC__) && __GNUC__ extern void die(const char *fmt, ...) __attribute__((noreturn)); @@ -48,20 +49,31 @@ void ignore_end_spaces(char *str) { if (end >= str) end[1] = '\0'; } -int arg_cfg(int *argc, char ***argv, const char *file) { - char **argv_local = (char **)*argv; - char **argv_org = (char **)*argv; +static const char kSbSizeWarningString[] = + "super_block_size has to be 64 or 128."; +static const char kMinpartWarningString[] = + "min_partition_size has to be smaller or equal to max_partition_size."; +static const char kMaxpartWarningString[] = + "max_partition_size has to be smaller or equal to super_block_size."; + +int parse_cfg(const char *file, cfg_options_t *config) { char line[1024 * 10]; FILE *f = fopen(file, "r"); if (!f) return 1; +#define GET_PARAMS(field) \ + if (strcmp(left, #field) == 0) { \ + config->field = atoi(right); \ + continue; \ + } + while (fgets(line, sizeof(line) - 1, f)) { char *actual_line = ignore_front_spaces(line); char *left, *right, *comment; size_t length = strlen(actual_line); if (length == 0 || actual_line[0] == '#') continue; - right = strchr(actual_line, ':'); + right = strchr(actual_line, '='); if (right == NULL) continue; right[0] = '\0'; @@ -74,23 +86,61 @@ int arg_cfg(int *argc, char ***argv, const char *file) { ignore_end_spaces(left); ignore_end_spaces(right); - char **new_args = argv_dup(*argc, (const char **)argv_local); - char *new_line = (char *)malloc(sizeof(*new_line) * 128); + GET_PARAMS(super_block_size); + GET_PARAMS(max_partition_size); + GET_PARAMS(min_partition_size); + GET_PARAMS(disable_ab_partition_type); + GET_PARAMS(disable_rect_partition_type); + GET_PARAMS(disable_1to4_partition_type); + GET_PARAMS(disable_flip_idtx); + GET_PARAMS(disable_cdef); + GET_PARAMS(disable_lr); + GET_PARAMS(disable_obmc); + GET_PARAMS(disable_warp_motion); + GET_PARAMS(disable_global_motion); + GET_PARAMS(disable_dist_wtd_comp); + GET_PARAMS(disable_diff_wtd_comp); + GET_PARAMS(disable_inter_intra_comp); + GET_PARAMS(disable_masked_comp); + GET_PARAMS(disable_one_sided_comp); + GET_PARAMS(disable_palette); + GET_PARAMS(disable_intrabc); + GET_PARAMS(disable_cfl); + GET_PARAMS(disable_smooth_intra); + GET_PARAMS(disable_filter_intra); + GET_PARAMS(disable_dual_filter); + GET_PARAMS(disable_intra_angle_delta); + GET_PARAMS(disable_intra_edge_filter); + GET_PARAMS(disable_tx_64x64); + GET_PARAMS(disable_smooth_inter_intra); + GET_PARAMS(disable_inter_inter_wedge); + GET_PARAMS(disable_inter_intra_wedge); + GET_PARAMS(disable_paeth_intra); + GET_PARAMS(disable_trellis_quant); + GET_PARAMS(disable_ref_frame_mv); + GET_PARAMS(reduced_reference_set); + GET_PARAMS(reduced_tx_type_set); - if (argv_local != argv_org) free(argv_local); - - if (!strcmp(right, "ON")) - snprintf(new_line, sizeof(*new_line) * 128, "--%s", left); - else - snprintf(new_line, sizeof(*new_line) * 128, "--%s=%s", left, right); - - new_args[(*argc) - 1] = new_args[(*argc) - 2]; - new_args[(*argc) - 2] = new_line; - argv_local = new_args; - *argv = new_args; - (*argc)++; + fprintf(stderr, "\nInvalid parameter: %s", left); + exit(-1); } + + if (config->super_block_size != 128 && config->super_block_size != 64) { + fprintf(stderr, "\n%s", kSbSizeWarningString); + exit(-1); + } + if (config->min_partition_size > config->max_partition_size) { + fprintf(stderr, "\n%s", kMinpartWarningString); + exit(-1); + } + if (config->max_partition_size > config->super_block_size) { + fprintf(stderr, "\n%s", kMaxpartWarningString); + exit(-1); + } + fclose(f); + config->init_by_cfg_file = 1; + return 0; } @@ -209,10 +259,6 @@ int arg_parse_int(const struct arg *arg) { return 0; } -struct aom_rational { - int num; /**< fraction numerator */ - int den; /**< fraction denominator */ -}; struct aom_rational arg_parse_rational(const struct arg *arg) { long int rawval; char *endptr; diff --git a/media/libaom/src/common/args.h b/media/libaom/src/common/args.h index 6a26642692..286f7dd1ac 100644 --- a/media/libaom/src/common/args.h +++ b/media/libaom/src/common/args.h @@ -13,6 +13,9 @@ #define AOM_COMMON_ARGS_H_ #include +#include "aom/aom_codec.h" +#include "aom/aom_encoder.h" + #ifdef __cplusplus extern "C" { #endif @@ -50,7 +53,7 @@ struct arg arg_init(char **argv); int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); char *ignore_front_spaces(const char *str); void ignore_end_spaces(char *str); -int arg_cfg(int *argc, char ***argv, const char *file); +int parse_cfg(const char *file, cfg_options_t *config); const char *arg_next(struct arg *arg); void arg_show_usage(FILE *fp, const struct arg_def *const *defs); char **argv_dup(int argc, const char **argv); diff --git a/media/libaom/src/common/ivfdec.h b/media/libaom/src/common/ivfdec.h index ea294faa18..dbc77331f0 100644 --- a/media/libaom/src/common/ivfdec.h +++ b/media/libaom/src/common/ivfdec.h @@ -11,6 +11,7 @@ #ifndef AOM_COMMON_IVFDEC_H_ #define AOM_COMMON_IVFDEC_H_ +#include "aom/aom_codec.h" #include "common/tools_common.h" #ifdef __cplusplus @@ -18,8 +19,6 @@ extern "C" { #endif int file_is_ivf(struct AvxInputContext *input); - -typedef int64_t aom_codec_pts_t; int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read, size_t *buffer_size, aom_codec_pts_t *pts); diff --git a/media/libaom/src/common/obudec.c b/media/libaom/src/common/obudec.c index 1ce218d688..650f9973bd 100644 --- a/media/libaom/src/common/obudec.c +++ b/media/libaom/src/common/obudec.c @@ -467,10 +467,11 @@ int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx, memcpy(*buffer, &tuheader[0], length_of_temporal_unit_size); offset = length_of_temporal_unit_size; } else { - memcpy(*buffer, obu_ctx->buffer, obu_ctx->bytes_buffered); - offset = obu_ctx->bytes_buffered; - data_size = tu_size - obu_ctx->bytes_buffered; - obu_ctx->bytes_buffered = 0; + const size_t copy_size = AOMMIN(obu_ctx->bytes_buffered, tu_size); + memcpy(*buffer, obu_ctx->buffer, copy_size); + offset = copy_size; + data_size = tu_size - copy_size; + obu_ctx->bytes_buffered -= copy_size; } if (fread(*buffer + offset, 1, data_size, f) != data_size) { diff --git a/media/libaom/src/common/tools_common.h b/media/libaom/src/common/tools_common.h index d9a68f01bf..1ed004521a 100644 --- a/media/libaom/src/common/tools_common.h +++ b/media/libaom/src/common/tools_common.h @@ -144,20 +144,103 @@ void usage_exit(void) AOM_NO_RETURN; int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame); +/////////////////////////////////////////////////////////////////////////////// +// A description of the interfaces used to access the AOM codecs +/////////////////////////////////////////////////////////////////////////////// +// +// There are three levels of interfaces used to access the AOM codec: the +// AVXInterface, the aom_codec_iface, and the aom_codec_ctx. Each of these +// is described in detail here. +// +// +// 1. AVXInterface +// (Related files: common/tools_common.c, common/tools_common.h) +// +// The high-level interface to the AVx encoders / decoders. Each AvxInterface +// contains the name of the codec (e.g., "av1"), the four character code +// associated with it, and a function pointer to the actual interface (see the +// documentation on aom_codec_iface_t for more info). This API +// is meant for lookup / iteration over all known codecs. +// +// For the encoder, call get_aom_encoder_by_name(...) if you know the name +// (e.g., "av1"); to iterate over all known encoders, use +// get_aom_encoder_count() and get_aom_encoder_by_index(i). To get the +// encoder specifically for large scale tile encoding, use +// get_aom_lst_encoder(). +// +// For the decoder, similar functions are available. There is also a +// get_aom_decoder_by_fourcc(fourcc) to get the decoder based on the four +// character codes. +// +// The main purpose of the AVXInterface is to get a reference to the +// aom_codec_interface_t, pointed to by its codec_interface variable. +// +// +// 2. aom_codec_iface_t +// (Related files: aom/aom_codec.h, aom/src/aom_codec.c, +// aom/internal/aom_codec_internal.h, av1/av1_cx_iface.c, +// av1/av1_dx_iface.c) +// +// Used to initialize the codec context, which contains the configuration for +// for modifying the encoder/decoder during run-time. See the documentation of +// aom/aom_codec.h for more details. For the most part, users will call the +// helper functions listed there, such as aom_codec_iface_name, +// aom_codec_get_caps, etc., to interact with it. +// +// The main purpose of the aom_codec_iface_t is to provide a way to generate +// a default codec config, find out what capabilities the implementation has, +// and create an aom_codec_ctx_t (which is actually used to interact with the +// codec). +// +// Note that the implementations of the aom_codec_iface_t are located in +// av1/av1_cx_iface.c and av1/av1_dx_iface.c +// +// +// 3. aom_codec_ctx_t +// (Related files: aom/aom_codec.h, av1/av1_cx_iface.c, av1/av1_dx_iface.c, +// aom/aomcx.h, aom/aomdx.h, aom/src/aom_encoder.c, aom/src/aom_decoder.c) +// +// The actual interface between user code and the codec. It stores the name +// of the codec, a pointer back to the aom_codec_iface_t that initialized it, +// initialization flags, a config for either encoder or the decoder, and a +// pointer to internal data. +// +// The codec is configured / queried through calls to aom_codec_control, +// which takes a control code (listed in aomcx.h and aomdx.h) and a parameter. +// In the case of "getter" control codes, the parameter is modified to have +// the requested value; in the case of "setter" control codes, the codec's +// configuration is changed based on the parameter. Note that a aom_codec_err_t +// is returned, which indicates if the operation was successful or not. +// +// Note that for the encoder, the aom_codec_alg_priv_t points to the +// the aom_codec_alg_priv structure in av1/av1_cx_iface.c, and for the decoder, +// the struct in av1/av1_dx_iface.c. Variables such as AV1_COMP cpi are stored +// here and also used in the core algorithm. +// +// At the end, aom_codec_destroy should be called for each initialized +// aom_codec_ctx_t. + typedef struct AvxInterface { const char *const name; const uint32_t fourcc; + // Pointer to a function of zero arguments that returns an aom_codec_iface_t + // pointer. E.g.: + // aom_codec_iface_t *codec = interface->codec_interface(); aom_codec_iface_t *(*const codec_interface)(); } AvxInterface; int get_aom_encoder_count(void); +// Lookup the interface by index -- it must be the case that +// i < get_aom_encoder_count() const AvxInterface *get_aom_encoder_by_index(int i); +// Lookup the interface by name -- returns NULL if no match. const AvxInterface *get_aom_encoder_by_name(const char *name); const AvxInterface *get_aom_lst_encoder(void); int get_aom_decoder_count(void); const AvxInterface *get_aom_decoder_by_index(int i); const AvxInterface *get_aom_decoder_by_name(const char *name); +// Lookup the interface by the fourcc -- returns NULL if no match. const AvxInterface *get_aom_decoder_by_fourcc(uint32_t fourcc); void aom_img_write(const aom_image_t *img, FILE *file); diff --git a/media/libaom/src/common/video_writer.c b/media/libaom/src/common/video_writer.c index 2b42e365cc..1d4328ae1e 100644 --- a/media/libaom/src/common/video_writer.c +++ b/media/libaom/src/common/video_writer.c @@ -41,8 +41,10 @@ AvxVideoWriter *aom_video_writer_open(const char *filename, if (!file) return NULL; writer = malloc(sizeof(*writer)); - if (!writer) return NULL; - + if (!writer) { + fclose(file); + return NULL; + } writer->frame_count = 0; writer->info = *info; writer->file = file; diff --git a/media/libaom/src/common/webmdec.cc b/media/libaom/src/common/webmdec.cc index 17ac53c930..33bda59021 100644 --- a/media/libaom/src/common/webmdec.cc +++ b/media/libaom/src/common/webmdec.cc @@ -197,6 +197,17 @@ int webm_read_frame(struct WebmInputContext *webm_ctx, uint8_t **buffer, return frame.Read(reader, *buffer) ? -1 : 0; } +// Calculate the greatest common divisor between two numbers. +static int gcd(int a, int b) { + int remainder; + while (b > 0) { + remainder = a % b; + a = b; + b = remainder; + } + return a; +} + int webm_guess_framerate(struct WebmInputContext *webm_ctx, struct AvxInputContext *aom_ctx) { uint32_t i = 0; @@ -213,6 +224,14 @@ int webm_guess_framerate(struct WebmInputContext *webm_ctx, aom_ctx->framerate.numerator = (i - 1) * 1000000; aom_ctx->framerate.denominator = static_cast(webm_ctx->timestamp_ns / 1000); + // Fraction might be represented in large numbers, like 49000000/980000 + // for 50fps. Simplify as much as possible. + int g = gcd(aom_ctx->framerate.numerator, aom_ctx->framerate.denominator); + if (g != 0) { + aom_ctx->framerate.numerator /= g; + aom_ctx->framerate.denominator /= g; + } + delete[] buffer; webm_ctx->buffer = NULL; diff --git a/media/libaom/src/examples/analyzer.cc b/media/libaom/src/examples/analyzer.cc index 261d085697..35988211e7 100644 --- a/media/libaom/src/examples/analyzer.cc +++ b/media/libaom/src/examples/analyzer.cc @@ -15,7 +15,7 @@ #include "aom/aom_decoder.h" #include "aom/aomdx.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #include "av1/decoder/accounting.h" #include "av1/decoder/inspection.h" #include "common/tools_common.h" @@ -528,8 +528,8 @@ AnalyzerFrame::AnalyzerFrame(const bool bit_accounting) wxMenuBar *mb = new wxMenuBar(); fileMenu = new wxMenu(); - fileMenu->Append(wxID_OPEN, _("&Open...\tCtrl-O"), _("Open daala file")); - fileMenu->Append(wxID_CLOSE, _("&Close\tCtrl-W"), _("Close daala file")); + fileMenu->Append(wxID_OPEN, _("&Open...\tCtrl-O"), _("Open AV1 file")); + fileMenu->Append(wxID_CLOSE, _("&Close\tCtrl-W"), _("Close AV1 file")); fileMenu->Enable(wxID_CLOSE, false); fileMenu->Append(wxID_EXIT, _("E&xit\tCtrl-Q"), _("Quit this program")); mb->Append(fileMenu, _("&File")); diff --git a/media/libaom/src/examples/inspect.c b/media/libaom/src/examples/inspect.c index f7422ac9ce..526bdc16c1 100644 --- a/media/libaom/src/examples/inspect.c +++ b/media/libaom/src/examples/inspect.c @@ -29,7 +29,7 @@ #include "aom/aom_decoder.h" #include "aom/aomdx.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" #if CONFIG_ACCOUNTING #include "av1/decoder/accounting.h" diff --git a/media/libaom/src/examples/lightfield_bitstream_parsing.c b/media/libaom/src/examples/lightfield_bitstream_parsing.c index afacf44043..ffcbcb9cb9 100644 --- a/media/libaom/src/examples/lightfield_bitstream_parsing.c +++ b/media/libaom/src/examples/lightfield_bitstream_parsing.c @@ -148,14 +148,14 @@ void process_tile_list(const TILE_LIST_INFO *tiles, int num_tiles, size_t frame_size = frame_sizes[image_idx]; const unsigned char *frame = frames[image_idx]; - aom_codec_control_(codec, AV1_SET_DECODE_TILE_ROW, tr); - aom_codec_control_(codec, AV1_SET_DECODE_TILE_COL, tc); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_DECODE_TILE_ROW, tr); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_DECODE_TILE_COL, tc); aom_codec_err_t aom_status = aom_codec_decode(codec, frame, frame_size, NULL); if (aom_status) die_codec(codec, "Failed to decode tile."); - aom_codec_control_(codec, AV1D_GET_TILE_DATA, &tile_data); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_DATA, &tile_data); // Copy over tile info. // uint8_t anchor_frame_idx; @@ -228,7 +228,7 @@ int main(int argc, char **argv) { die_codec(&codec, "Failed to initialize decoder."); // Decode anchor frames. - aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 0); printf("Reading %d reference images.\n", num_references); for (i = 0; i < num_references; ++i) { @@ -248,8 +248,8 @@ int main(int argc, char **argv) { } // Decode camera frames. - aom_codec_control_(&codec, AV1_SET_TILE_MODE, 1); - aom_codec_control_(&codec, AV1D_EXT_TILE_DEBUG, 1); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 1); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_EXT_TILE_DEBUG, 1); FILE *infile = aom_video_reader_get_file(reader); // Record the offset of the first camera image. @@ -291,14 +291,15 @@ int main(int argc, char **argv) { // Need to decode frame header to get camera frame header info. So, here // decoding 1 tile is enough. - aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, 0); - aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, 0); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_DECODE_TILE_ROW, 0); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_DECODE_TILE_COL, 0); aom_codec_err_t aom_status = aom_codec_decode(&codec, frame, frame_size, NULL); if (aom_status) die_codec(&codec, "Failed to decode tile."); - aom_codec_control_(&codec, AV1D_GET_FRAME_HEADER_INFO, &frame_header_info); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_FRAME_HEADER_INFO, + &frame_header_info); size_t obu_size_offset = (uint8_t *)frame_header_info.coded_tile_data - frame; @@ -330,13 +331,13 @@ int main(int argc, char **argv) { // Read out the image format. aom_img_fmt_t ref_fmt = 0; - if (aom_codec_control(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) die_codec(&codec, "Failed to get the image format"); const int bps = get_image_bps(ref_fmt); if (!bps) die_codec(&codec, "Invalid image format."); // read out the tile size. unsigned int tile_size = 0; - if (aom_codec_control(&codec, AV1D_GET_TILE_SIZE, &tile_size)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_TILE_SIZE, &tile_size)) die_codec(&codec, "Failed to get the tile size"); const unsigned int tile_width = tile_size >> 16; const unsigned int tile_height = tile_size & 65535; diff --git a/media/libaom/src/examples/lightfield_decoder.c b/media/libaom/src/examples/lightfield_decoder.c index 48c4db2a60..a292e9c75e 100644 --- a/media/libaom/src/examples/lightfield_decoder.c +++ b/media/libaom/src/examples/lightfield_decoder.c @@ -95,16 +95,16 @@ void decode_tile(aom_codec_ctx_t *codec, const unsigned char *frame, aom_image_t *reference_images, aom_image_t *output, int *tile_idx, unsigned int *output_bit_depth, aom_image_t **img_ptr, int output_format) { - aom_codec_control_(codec, AV1_SET_TILE_MODE, 1); - aom_codec_control_(codec, AV1D_EXT_TILE_DEBUG, 1); - aom_codec_control_(codec, AV1_SET_DECODE_TILE_ROW, tr); - aom_codec_control_(codec, AV1_SET_DECODE_TILE_COL, tc); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_TILE_MODE, 1); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_EXT_TILE_DEBUG, 1); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_DECODE_TILE_ROW, tr); + AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_DECODE_TILE_COL, tc); av1_ref_frame_t ref; ref.idx = 0; ref.use_external_ref = 1; ref.img = reference_images[ref_idx]; - if (aom_codec_control(codec, AV1_SET_REFERENCE, &ref)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1_SET_REFERENCE, &ref)) { die_codec(codec, "Failed to set reference frame."); } @@ -126,7 +126,7 @@ void decode_tile(aom_codec_ctx_t *codec, const unsigned char *frame, if (output_format != YUV1D) { // read out the tile size. unsigned int tile_size = 0; - if (aom_codec_control(codec, AV1D_GET_TILE_SIZE, &tile_size)) + if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_SIZE, &tile_size)) die_codec(codec, "Failed to get the tile size"); const unsigned int tile_width = tile_size >> 16; const unsigned int tile_height = tile_size & 65535; @@ -198,12 +198,13 @@ int main(int argc, char **argv) { if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) die_codec(&codec, "Failed to initialize decoder."); - if (aom_codec_control(&codec, AV1D_SET_IS_ANNEXB, info->is_annexb)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_IS_ANNEXB, + info->is_annexb)) { die("Failed to set annex b status"); } // Decode anchor frames. - aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 0); for (i = 0; i < num_references; ++i) { aom_video_reader_read_frame(reader); frame = aom_video_reader_get_frame(reader, &frame_size); @@ -211,11 +212,11 @@ int main(int argc, char **argv) { die_codec(&codec, "Failed to decode frame."); if (i == 0) { - if (aom_codec_control(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) die_codec(&codec, "Failed to get the image format"); int frame_res[2]; - if (aom_codec_control(&codec, AV1D_GET_FRAME_SIZE, frame_res)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_FRAME_SIZE, frame_res)) die_codec(&codec, "Failed to get the image frame size"); // Allocate memory to store decoded references. Allocate memory with the @@ -230,8 +231,8 @@ int main(int argc, char **argv) { } } - if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE, - &reference_images[i])) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_COPY_NEW_FRAME_IMAGE, + &reference_images[i])) die_codec(&codec, "Failed to copy decoded reference frame"); aom_codec_iter_t iter = NULL; @@ -286,6 +287,7 @@ int main(int argc, char **argv) { printf("Decoding tile list from file.\n"); char line[1024]; FILE *tile_list_fptr = fopen(tile_list_file, "r"); + if (!tile_list_fptr) die_codec(&codec, "Failed to open tile list file."); int tile_list_cnt = 0; int tile_list_writes = 0; int tile_idx = 0; diff --git a/media/libaom/src/examples/lightfield_encoder.c b/media/libaom/src/examples/lightfield_encoder.c index 40c8030777..e80fe24f6b 100644 --- a/media/libaom/src/examples/lightfield_encoder.c +++ b/media/libaom/src/examples/lightfield_encoder.c @@ -259,6 +259,11 @@ static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name, die_codec(&codec, "Failed to turn off auto altref"); if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 0)) die_codec(&codec, "Failed to set frame parallel decoding"); + if (aom_codec_control(&codec, AV1E_ENABLE_EXT_TILE_DEBUG, 1)) + die_codec(&codec, "Failed to enable encoder ext_tile debug"); + if (aom_codec_control(&codec, AOME_SET_CPUUSED, 1)) + die_codec(&codec, "Failed to set cpu-used"); + // Note: The superblock is a sequence parameter and has to be the same for 1 // sequence. In lightfield application, must choose the superblock size(either // 64x64 or 128x128) before the encoding starts. Otherwise, the default is diff --git a/media/libaom/src/examples/lightfield_tile_list_decoder.c b/media/libaom/src/examples/lightfield_tile_list_decoder.c index a5b8f73110..3b928df2c3 100644 --- a/media/libaom/src/examples/lightfield_tile_list_decoder.c +++ b/media/libaom/src/examples/lightfield_tile_list_decoder.c @@ -51,14 +51,14 @@ static void write_tile_yuv1d(aom_codec_ctx_t *codec, const aom_image_t *img, FILE *file) { // read out the tile size. unsigned int tile_size = 0; - if (aom_codec_control(codec, AV1D_GET_TILE_SIZE, &tile_size)) + if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_SIZE, &tile_size)) die_codec(codec, "Failed to get the tile size"); const unsigned int tile_width = tile_size >> 16; const unsigned int tile_height = tile_size & 65535; const uint32_t output_frame_width_in_tiles = img->d_w / tile_width; unsigned int tile_count = 0; - if (aom_codec_control(codec, AV1D_GET_TILE_COUNT, &tile_count)) + if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_COUNT, &tile_count)) die_codec(codec, "Failed to get the tile size"); // Write tile to file. @@ -136,12 +136,13 @@ int main(int argc, char **argv) { if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) die_codec(&codec, "Failed to initialize decoder."); - if (aom_codec_control(&codec, AV1D_SET_IS_ANNEXB, info->is_annexb)) { + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_IS_ANNEXB, + info->is_annexb)) { die("Failed to set annex b status"); } // Decode anchor frames. - aom_codec_control_(&codec, AV1_SET_TILE_MODE, 0); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 0); for (i = 0; i < num_references; ++i) { aom_video_reader_read_frame(reader); frame = aom_video_reader_get_frame(reader, &frame_size); @@ -150,11 +151,11 @@ int main(int argc, char **argv) { if (i == 0) { aom_img_fmt_t ref_fmt = 0; - if (aom_codec_control(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) die_codec(&codec, "Failed to get the image format"); int frame_res[2]; - if (aom_codec_control(&codec, AV1D_GET_FRAME_SIZE, frame_res)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_FRAME_SIZE, frame_res)) die_codec(&codec, "Failed to get the image frame size"); // Allocate memory to store decoded references. Allocate memory with the @@ -169,8 +170,8 @@ int main(int argc, char **argv) { } } - if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE, - &reference_images[i])) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_COPY_NEW_FRAME_IMAGE, + &reference_images[i])) die_codec(&codec, "Failed to copy decoded reference frame"); aom_codec_iter_t iter = NULL; @@ -186,11 +187,11 @@ int main(int argc, char **argv) { } // Decode the lightfield. - aom_codec_control_(&codec, AV1_SET_TILE_MODE, 1); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 1); // Set external references. av1_ext_ref_frame_t set_ext_ref = { &reference_images[0], num_references }; - aom_codec_control_(&codec, AV1D_SET_EXT_REF_PTR, &set_ext_ref); + AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_EXT_REF_PTR, &set_ext_ref); // Must decode the camera frame header first. aom_video_reader_read_frame(reader); frame = aom_video_reader_get_frame(reader, &frame_size); diff --git a/media/libaom/src/examples/lossless_encoder.c b/media/libaom/src/examples/lossless_encoder.c index 438ff21c61..e0253d2b34 100644 --- a/media/libaom/src/examples/lossless_encoder.c +++ b/media/libaom/src/examples/lossless_encoder.c @@ -113,7 +113,7 @@ int main(int argc, char **argv) { if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) die_codec(&codec, "Failed to initialize encoder"); - if (aom_codec_control_(&codec, AV1E_SET_LOSSLESS, 1)) + if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1E_SET_LOSSLESS, 1)) die_codec(&codec, "Failed to use lossless mode"); // Encode frames. diff --git a/media/libaom/src/examples/resize_util.c b/media/libaom/src/examples/resize_util.c index 6a84d57401..5692c2062c 100644 --- a/media/libaom/src/examples/resize_util.c +++ b/media/libaom/src/examples/resize_util.c @@ -83,6 +83,7 @@ int main(int argc, char *argv[]) { } fpout = fopen(fout, "wb"); if (fpout == NULL) { + fclose(fpin); printf("Can't open file %s to write\n", fout); usage(); return 1; diff --git a/media/libaom/src/examples/svc_encoder_rtc.c b/media/libaom/src/examples/svc_encoder_rtc.c index 835308d506..1316c6c1eb 100644 --- a/media/libaom/src/examples/svc_encoder_rtc.c +++ b/media/libaom/src/examples/svc_encoder_rtc.c @@ -258,8 +258,10 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3), // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->ref_idx[i] = i; + for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->reference[i] = 0; for (i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0; - // Note only use LAST and GF for prediction in non-rd mode (speed 8). + // Note for this layered patterns only use LAST and GF for prediction in + // non-rd mode (speed >= 7). int layer_flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2; @@ -347,7 +349,7 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, } break; case 4: - // 2-temporla layer with the old update flags, not with the new + // 2-temporal layer with the old update flags, not with the new // SVC control. *use_svc_control = 0; // 1 3 5 @@ -420,6 +422,10 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, // 3 spatial and 3 temporal layer. // No overlap in buffer updates between TL2 and TL1. // TL2 updates slot 3 and 4, TL1 updates 5, 6, 7. + // Set the references via the svc_ref_frame_config control. + layer_flags = 0; + // Always reference LAST. + ref_frame_config->reference[0] = 1; if (superframe_cnt % 4 == 0) { // Base temporal layer. layer_id->temporal_layer_id = 0; @@ -429,7 +435,6 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->ref_idx[i] = 0; ref_frame_config->refresh[0] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 0. @@ -458,7 +463,6 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, ref_frame_config->ref_idx[i] = 0; ref_frame_config->ref_idx[3] = 3; ref_frame_config->refresh[3] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 3. @@ -487,7 +491,6 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, ref_frame_config->ref_idx[i] = 0; ref_frame_config->ref_idx[3] = 5 - shift; ref_frame_config->refresh[5 - shift] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 5. @@ -519,7 +522,6 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, ref_frame_config->ref_idx[0] = 5 - shift; ref_frame_config->ref_idx[3] = 3; ref_frame_config->refresh[3] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6, // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4. @@ -538,6 +540,8 @@ static int set_layer_pattern(int layering_mode, int superframe_cnt, ref_frame_config->ref_idx[3] = 4; } } + if (layer_id->spatial_layer_id > 0) + ref_frame_config->reference[3] = 1; // Reference GOLDEN. break; default: assert(0); die("Error: Unsupported temporal layering mode!\n"); } @@ -580,6 +584,10 @@ int main(int argc, char **argv) { memset(&input_ctx, 0, sizeof(input_ctx)); memset(&svc_params, 0, sizeof(svc_params)); + // Flag to test dynamic scaling of source frames for single + // spatial stream, using the scaling_mode control. + const int test_dynamic_scaling_single_layer = 0; + /* Setup default input stream settings */ input_ctx.framerate.numerator = 30; input_ctx.framerate.denominator = 1; @@ -794,6 +802,18 @@ int main(int argc, char **argv) { layer = slx * ts_number_layers + layer_id.temporal_layer_id; if (frame_avail && slx == 0) ++rc.layer_input_frames[layer]; + if (test_dynamic_scaling_single_layer) { + if (frame_cnt >= 200 && frame_cnt <= 400) { + // Scale source down by 2x2. + struct aom_scaling_mode mode = { AOME_ONETWO, AOME_ONETWO }; + aom_codec_control(&codec, AOME_SET_SCALEMODE, &mode); + } else { + // Source back up to original resolution (no scaling). + struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL }; + aom_codec_control(&codec, AOME_SET_SCALEMODE, &mode); + } + } + // Do the layer encode. aom_usec_timer_start(&timer); if (aom_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags)) diff --git a/media/libaom/src/test/arf_freq_test.cc b/media/libaom/src/test/arf_freq_test.cc index 50b478ba65..0780cd712d 100644 --- a/media/libaom/src/test/arf_freq_test.cc +++ b/media/libaom/src/test/arf_freq_test.cc @@ -214,7 +214,7 @@ TEST_P(ArfFreqTestLarge, MinArfFreqTest) { // BWDREF_FRAME is also a non-show frame, and the minimum run between two // consecutive BWDREF_FRAME's may vary between 1 and any arbitrary positive // number as long as it does not exceed the gf_group interval. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DISABLED_AV1, ArfFreqTestLarge, ::testing::Combine( ::testing::Values( diff --git a/media/libaom/src/test/onyxc_int_test.cc b/media/libaom/src/test/av1_common_int_test.cc similarity index 91% rename from media/libaom/src/test/onyxc_int_test.cc rename to media/libaom/src/test/av1_common_int_test.cc index 3889595187..dde2542e3d 100644 --- a/media/libaom/src/test/onyxc_int_test.cc +++ b/media/libaom/src/test/av1_common_int_test.cc @@ -11,9 +11,9 @@ #include "third_party/googletest/src/googletest/include/gtest/gtest.h" -#include "av1/common/onyxc_int.h" +#include "av1/common/av1_common_int.h" -TEST(OnyxcInt, TestGetTxSize) { +TEST(AV1CommonInt, TestGetTxSize) { for (int t = TX_4X4; t < TX_SIZES_ALL; t++) { TX_SIZE t2 = get_tx_size(tx_size_wide[t], tx_size_high[t]); GTEST_ASSERT_EQ(tx_size_wide[t], tx_size_wide[t2]); diff --git a/media/libaom/src/test/av1_convolve_2d_test.cc b/media/libaom/src/test/av1_convolve_2d_test.cc index 5218d957ff..50a58f06de 100644 --- a/media/libaom/src/test/av1_convolve_2d_test.cc +++ b/media/libaom/src/test/av1_convolve_2d_test.cc @@ -9,6 +9,8 @@ * 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/av1_convolve_2d_test_util.h" @@ -19,8 +21,8 @@ using libaom_test::AV1Convolve2D::AV1JntConvolve2DTest; using libaom_test::AV1HighbdConvolve2D::AV1HighbdConvolve2DSrTest; using libaom_test::AV1HighbdConvolve2D::AV1HighbdJntConvolve2DTest; #endif -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace { @@ -28,136 +30,136 @@ TEST_P(AV1Convolve2DSrTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); } TEST_P(AV1Convolve2DSrTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C_COPY, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_copy_sr_c, 0, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C_X, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_c, 1, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C_Y, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_c, 0, 1)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_c, 1, 1)); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1Convolve2DSrTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_convolve_2d_copy_sr_sse2, 0, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P(SSE2_COPY, AV1Convolve2DSrTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_convolve_2d_copy_sr_sse2, 0, 0)); +INSTANTIATE_TEST_SUITE_P( SSE2_X, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_sse2, 1, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2_Y, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_sse2, 0, 1)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_sse2, 1, 1)); #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1Convolve2DSrTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_convolve_2d_copy_sr_avx2, 0, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P(AVX2_COPY, AV1Convolve2DSrTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_convolve_2d_copy_sr_avx2, 0, 0)); +INSTANTIATE_TEST_SUITE_P( AVX2_X, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_avx2, 1, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2_Y, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_avx2, 0, 1)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_avx2, 1, 1)); #endif // HAVE_AVX2 #endif // HAVE_SSE2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON_X, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_neon, 1, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON_Y, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_neon, 0, 1)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AV1Convolve2DSrTest, libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_neon, 1, 1)); -INSTANTIATE_TEST_CASE_P(NEON_COPY, AV1Convolve2DSrTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_convolve_2d_copy_sr_neon, 0, 0)); +INSTANTIATE_TEST_SUITE_P(NEON_COPY, AV1Convolve2DSrTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_convolve_2d_copy_sr_neon, 0, 0)); #endif // HAVE_NEON TEST_P(AV1JntConvolve2DTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); } TEST_P(AV1JntConvolve2DTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); } -INSTANTIATE_TEST_CASE_P(C_COPY, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_copy_c, 0, 0)); +INSTANTIATE_TEST_SUITE_P(C_COPY, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_copy_c, 0, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C_X, AV1JntConvolve2DTest, libaom_test::AV1Convolve2D::BuildParams(av1_dist_wtd_convolve_x_c, 1, 0)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C_Y, AV1JntConvolve2DTest, libaom_test::AV1Convolve2D::BuildParams(av1_dist_wtd_convolve_y_c, 0, 1)); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_copy_sse2, 0, 0)); -INSTANTIATE_TEST_CASE_P(SSE2, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_sse2, 1, 1)); +INSTANTIATE_TEST_SUITE_P(SSE2_COPY, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_copy_sse2, 0, 0)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_sse2, 1, 1)); -INSTANTIATE_TEST_CASE_P(SSE2_X, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_x_sse2, 1, 0)); +INSTANTIATE_TEST_SUITE_P(SSE2_X, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_x_sse2, 1, 0)); -INSTANTIATE_TEST_CASE_P(SSE2_Y, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_y_sse2, 0, 1)); +INSTANTIATE_TEST_SUITE_P(SSE2_Y, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_y_sse2, 0, 1)); #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P(SSSE3, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_ssse3, 1, 1)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_ssse3, 1, 1)); #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_copy_avx2, 0, 0)); -INSTANTIATE_TEST_CASE_P(AVX2_X, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_x_avx2, 1, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2_COPY, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_copy_avx2, 0, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2_X, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_x_avx2, 1, 0)); -INSTANTIATE_TEST_CASE_P(AVX2_Y, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_y_avx2, 0, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2_Y, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_y_avx2, 0, 1)); -INSTANTIATE_TEST_CASE_P(AVX2, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_avx2, 1, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_avx2, 1, 1)); #endif // HAVE_AVX2 #endif // HAVE_SSSE3 #endif // HAVE_SSE2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON_COPY, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_copy_neon, 0, 0)); +INSTANTIATE_TEST_SUITE_P(NEON_COPY, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_copy_neon, 0, 0)); -INSTANTIATE_TEST_CASE_P(NEON, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_2d_neon, 1, 1)); -INSTANTIATE_TEST_CASE_P(NEON_X, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_x_neon, 1, 0)); +INSTANTIATE_TEST_SUITE_P(NEON, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_2d_neon, 1, 1)); +INSTANTIATE_TEST_SUITE_P(NEON_X, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_x_neon, 1, 0)); -INSTANTIATE_TEST_CASE_P(NEON_Y, AV1JntConvolve2DTest, - libaom_test::AV1Convolve2D::BuildParams( - av1_dist_wtd_convolve_y_neon, 0, 1)); +INSTANTIATE_TEST_SUITE_P(NEON_Y, AV1JntConvolve2DTest, + libaom_test::AV1Convolve2D::BuildParams( + av1_dist_wtd_convolve_y_neon, 0, 1)); #endif // HAVE_NEON #if CONFIG_AV1_HIGHBITDEPTH @@ -166,44 +168,44 @@ TEST_P(AV1HighbdConvolve2DSrTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(1)); } -INSTANTIATE_TEST_CASE_P(C_X, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_x_sr_c, 1, 0)); +INSTANTIATE_TEST_SUITE_P(C_X, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_x_sr_c, 1, 0)); -INSTANTIATE_TEST_CASE_P(C_Y, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_y_sr_c, 0, 1)); +INSTANTIATE_TEST_SUITE_P(C_Y, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_y_sr_c, 0, 1)); -INSTANTIATE_TEST_CASE_P(C_COPY, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_2d_copy_sr_c, 0, 0)); +INSTANTIATE_TEST_SUITE_P(C_COPY, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_2d_copy_sr_c, 0, 0)); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_2d_copy_sr_sse2, 0, 0)); +INSTANTIATE_TEST_SUITE_P(SSE2_COPY, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_2d_copy_sr_sse2, 0, 0)); #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P(SSSE3, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_2d_sr_ssse3, 1, 1)); -INSTANTIATE_TEST_CASE_P(SSSE3_X, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_x_sr_ssse3, 1, 0)); -INSTANTIATE_TEST_CASE_P(SSSE3_Y, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_y_sr_ssse3, 0, 1)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_2d_sr_ssse3, 1, 1)); +INSTANTIATE_TEST_SUITE_P(SSSE3_X, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_x_sr_ssse3, 1, 0)); +INSTANTIATE_TEST_SUITE_P(SSSE3_Y, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_y_sr_ssse3, 0, 1)); #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_2d_sr_avx2, 1, 1)); -INSTANTIATE_TEST_CASE_P(AVX2_X, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_x_sr_avx2, 1, 0)); -INSTANTIATE_TEST_CASE_P(AVX2_Y, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_y_sr_avx2, 0, 1)); -INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1HighbdConvolve2DSrTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_convolve_2d_copy_sr_avx2, 0, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_2d_sr_avx2, 1, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2_X, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_x_sr_avx2, 1, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2_Y, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_y_sr_avx2, 0, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2_COPY, AV1HighbdConvolve2DSrTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_convolve_2d_copy_sr_avx2, 0, 0)); #endif // HAVE_AVX2 #endif // HAVE_SSSE3 #endif // HAVE_SSE2 @@ -215,43 +217,44 @@ TEST_P(AV1HighbdJntConvolve2DTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(1)); } -INSTANTIATE_TEST_CASE_P(C_X, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_x_c, 1, 0)); +INSTANTIATE_TEST_SUITE_P(C_X, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_x_c, 1, 0)); -INSTANTIATE_TEST_CASE_P(C_Y, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_y_c, 0, 1)); +INSTANTIATE_TEST_SUITE_P(C_Y, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_y_c, 0, 1)); -INSTANTIATE_TEST_CASE_P(C_COPY, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_2d_copy_c, 0, 0)); +INSTANTIATE_TEST_SUITE_P(C_COPY, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_2d_copy_c, 0, 0)); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1_COPY, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_2d_copy_sse4_1, 0, 0)); -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_2d_sse4_1, 1, 1)); -INSTANTIATE_TEST_CASE_P(SSE4_1_X, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_x_sse4_1, 1, 0)); -INSTANTIATE_TEST_CASE_P(SSE4_1_Y, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_y_sse4_1, 0, 1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1_COPY, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_2d_copy_sse4_1, 0, + 0)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_2d_sse4_1, 1, 1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1_X, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_x_sse4_1, 1, 0)); +INSTANTIATE_TEST_SUITE_P(SSE4_1_Y, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_y_sse4_1, 0, 1)); #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_2d_copy_avx2, 0, 0)); -INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_2d_avx2, 1, 1)); -INSTANTIATE_TEST_CASE_P(AVX2_X, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_x_avx2, 1, 0)); -INSTANTIATE_TEST_CASE_P(AVX2_Y, AV1HighbdJntConvolve2DTest, - libaom_test::AV1HighbdConvolve2D::BuildParams( - av1_highbd_dist_wtd_convolve_y_avx2, 0, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2_COPY, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_2d_copy_avx2, 0, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_2d_avx2, 1, 1)); +INSTANTIATE_TEST_SUITE_P(AVX2_X, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_x_avx2, 1, 0)); +INSTANTIATE_TEST_SUITE_P(AVX2_Y, AV1HighbdJntConvolve2DTest, + libaom_test::AV1HighbdConvolve2D::BuildParams( + av1_highbd_dist_wtd_convolve_y_avx2, 0, 1)); #endif // HAVE_AVX2 #endif // HAVE_SSE4_1 #endif // CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/test/av1_convolve_2d_test_util.cc b/media/libaom/src/test/av1_convolve_2d_test_util.cc index c37b3fe97f..6f103d3f65 100644 --- a/media/libaom/src/test/av1_convolve_2d_test_util.cc +++ b/media/libaom/src/test/av1_convolve_2d_test_util.cc @@ -15,8 +15,8 @@ #include "av1/common/common_data.h" #include "av1/common/convolve.h" -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace libaom_test { diff --git a/media/libaom/src/test/av1_convolve_2d_test_util.h b/media/libaom/src/test/av1_convolve_2d_test_util.h index 22116c964d..3c19cfed32 100644 --- a/media/libaom/src/test/av1_convolve_2d_test_util.h +++ b/media/libaom/src/test/av1_convolve_2d_test_util.h @@ -12,6 +12,8 @@ #ifndef AOM_TEST_AV1_CONVOLVE_2D_TEST_UTIL_H_ #define AOM_TEST_AV1_CONVOLVE_2D_TEST_UTIL_H_ +#include + #include "config/av1_rtcd.h" #include "config/aom_dsp_rtcd.h" @@ -33,8 +35,7 @@ typedef void (*convolve_2d_func)(const uint8_t *src, int src_stride, const int subpel_x_qn, const int subpel_y_qn, ConvolveParams *conv_params); -typedef ::testing::tuple - Convolve2DParam; +typedef std::tuple Convolve2DParam; ::testing::internal::ParamGenerator BuildParams( convolve_2d_func filter, int subx_exist, int suby_exist); @@ -76,7 +77,7 @@ typedef void (*highbd_convolve_2d_func)( const InterpFilterParams *filter_params_y, const int subpel_x_qn, const int subpel_y_qn, ConvolveParams *conv_params, int bd); -typedef ::testing::tuple +typedef std::tuple HighbdConvolve2DParam; ::testing::internal::ParamGenerator BuildParams( diff --git a/media/libaom/src/test/av1_convolve_scale_test.cc b/media/libaom/src/test/av1_convolve_scale_test.cc index 2a1d1761af..ffd0bab333 100644 --- a/media/libaom/src/test/av1_convolve_scale_test.cc +++ b/media/libaom/src/test/av1_convolve_scale_test.cc @@ -9,6 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include #include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -33,8 +34,8 @@ const int kXStepQn = 16; const int kYStepQn = 20; using libaom_test::ACMRandom; -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; enum NTaps { EIGHT_TAP, TEN_TAP, TWELVE_TAP }; int NTapsToInt(NTaps ntaps) { return 8 + static_cast(ntaps) * 2; } @@ -269,8 +270,8 @@ class ConvolveScaleTestBase : public ::testing::Test { protected: void SetParams(const BaseParams ¶ms, int bd) { - width_ = ::testing::get<0>(params.dims); - height_ = ::testing::get<1>(params.dims); + width_ = std::get<0>(params.dims); + height_ = std::get<1>(params.dims); ntaps_x_ = params.ntaps_x; ntaps_y_ = params.ntaps_y; bd_ = bd; @@ -454,7 +455,7 @@ const NTaps kNTaps[] = { EIGHT_TAP }; TEST_P(LowBDConvolveScaleTest, Check) { Run(); } TEST_P(LowBDConvolveScaleTest, DISABLED_Speed) { SpeedTest(); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, LowBDConvolveScaleTest, ::testing::Combine(::testing::Values(av1_convolve_2d_scale_sse4_1), ::testing::ValuesIn(kBlockDim), @@ -521,7 +522,7 @@ const int kBDs[] = { 8, 10, 12 }; TEST_P(HighBDConvolveScaleTest, Check) { Run(); } TEST_P(HighBDConvolveScaleTest, DISABLED_Speed) { SpeedTest(); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, HighBDConvolveScaleTest, ::testing::Combine(::testing::Values(av1_highbd_convolve_2d_scale_sse4_1), ::testing::ValuesIn(kBlockDim), diff --git a/media/libaom/src/test/av1_fwd_txfm1d_test.cc b/media/libaom/src/test/av1_fwd_txfm1d_test.cc index 863cb396ae..abc46ed5a8 100644 --- a/media/libaom/src/test/av1_fwd_txfm1d_test.cc +++ b/media/libaom/src/test/av1_fwd_txfm1d_test.cc @@ -30,11 +30,11 @@ const int txfm_size_num = 5; const int txfm_size_ls[] = { 4, 8, 16, 32, 64 }; const TxfmFunc fwd_txfm_func_ls[][txfm_type_num] = { - { av1_fdct4_new, av1_fadst4_new, av1_fidentity4_c }, - { av1_fdct8_new, av1_fadst8_new, av1_fidentity8_c }, - { av1_fdct16_new, av1_fadst16_new, av1_fidentity16_c }, - { av1_fdct32_new, NULL, av1_fidentity32_c }, - { av1_fdct64_new, NULL, NULL }, + { av1_fdct4, av1_fadst4, av1_fidentity4_c }, + { av1_fdct8, av1_fadst8, av1_fidentity8_c }, + { av1_fdct16, av1_fadst16, av1_fidentity16_c }, + { av1_fdct32, NULL, av1_fidentity32_c }, + { av1_fdct64, NULL, NULL }, }; // the maximum stage number of fwd/inv 1d dct/adst txfm is 12 diff --git a/media/libaom/src/test/av1_fwd_txfm2d_test.cc b/media/libaom/src/test/av1_fwd_txfm2d_test.cc index eb09cb15f3..dd60665769 100644 --- a/media/libaom/src/test/av1_fwd_txfm2d_test.cc +++ b/media/libaom/src/test/av1_fwd_txfm2d_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "config/av1_rtcd.h" @@ -32,7 +33,7 @@ using std::vector; namespace { // tx_type_, tx_size_, max_error_, max_avg_error_ -typedef ::testing::tuple AV1FwdTxfm2dParam; +typedef std::tuple AV1FwdTxfm2dParam; class AV1FwdTxfm2d : public ::testing::TestWithParam { public: @@ -196,8 +197,8 @@ vector GetTxfm2dParamList() { return param_list; } -INSTANTIATE_TEST_CASE_P(C, AV1FwdTxfm2d, - ::testing::ValuesIn(GetTxfm2dParamList())); +INSTANTIATE_TEST_SUITE_P(C, AV1FwdTxfm2d, + ::testing::ValuesIn(GetTxfm2dParamList())); TEST_P(AV1FwdTxfm2d, RunFwdAccuracyCheck) { RunFwdAccuracyCheck(); } @@ -350,7 +351,7 @@ void AV1FwdTxfm2dSpeedTest(TX_SIZE tx_size, lowbd_fwd_txfm_func target_func) { } } -typedef ::testing::tuple LbdFwdTxfm2dParam; +typedef std::tuple LbdFwdTxfm2dParam; class AV1FwdTxfm2dTest : public ::testing::TestWithParam {}; @@ -387,9 +388,9 @@ static TX_SIZE fwd_txfm_for_sse2[] = { TX_64X16, }; -INSTANTIATE_TEST_CASE_P(SSE2, AV1FwdTxfm2dTest, - Combine(ValuesIn(fwd_txfm_for_sse2), - Values(av1_lowbd_fwd_txfm_sse2))); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1FwdTxfm2dTest, + Combine(ValuesIn(fwd_txfm_for_sse2), + Values(av1_lowbd_fwd_txfm_sse2))); #endif // HAVE_SSE2 #if HAVE_SSE4_1 @@ -400,9 +401,9 @@ static TX_SIZE fwd_txfm_for_sse41[] = { TX_64X32, }; -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1FwdTxfm2dTest, - Combine(ValuesIn(fwd_txfm_for_sse41), - Values(av1_lowbd_fwd_txfm_sse4_1))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1FwdTxfm2dTest, + Combine(ValuesIn(fwd_txfm_for_sse41), + Values(av1_lowbd_fwd_txfm_sse4_1))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -412,9 +413,9 @@ static TX_SIZE fwd_txfm_for_avx2[] = { TX_16X4, TX_8X32, TX_32X8, TX_16X64, TX_64X16, }; -INSTANTIATE_TEST_CASE_P(AVX2, AV1FwdTxfm2dTest, - Combine(ValuesIn(fwd_txfm_for_avx2), - Values(av1_lowbd_fwd_txfm_avx2))); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1FwdTxfm2dTest, + Combine(ValuesIn(fwd_txfm_for_avx2), + Values(av1_lowbd_fwd_txfm_avx2))); #endif // HAVE_AVX2 typedef void (*Highbd_fwd_txfm_func)(const int16_t *src_diff, tran_low_t *coeff, @@ -543,7 +544,7 @@ void AV1HighbdFwdTxfm2dSpeedTest(TX_SIZE tx_size, } } -typedef ::testing::tuple HighbdFwdTxfm2dParam; +typedef std::tuple HighbdFwdTxfm2dParam; class AV1HighbdFwdTxfm2dTest : public ::testing::TestWithParam {}; @@ -567,16 +568,16 @@ static TX_SIZE Highbd_fwd_txfm_for_sse4_1[] = { TX_16X4, TX_8X32, TX_32X8, TX_16X64, TX_64X16, }; -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdFwdTxfm2dTest, - Combine(ValuesIn(Highbd_fwd_txfm_for_sse4_1), - Values(av1_highbd_fwd_txfm))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1HighbdFwdTxfm2dTest, + Combine(ValuesIn(Highbd_fwd_txfm_for_sse4_1), + Values(av1_highbd_fwd_txfm))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 static TX_SIZE Highbd_fwd_txfm_for_avx2[] = { TX_8X8, TX_16X16, TX_32X32, TX_64X64, TX_8X16, TX_16X8 }; -INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdFwdTxfm2dTest, - Combine(ValuesIn(Highbd_fwd_txfm_for_avx2), - Values(av1_highbd_fwd_txfm))); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HighbdFwdTxfm2dTest, + Combine(ValuesIn(Highbd_fwd_txfm_for_avx2), + Values(av1_highbd_fwd_txfm))); #endif // HAVE_AVX2 } // namespace diff --git a/media/libaom/src/test/av1_highbd_iht_test.cc b/media/libaom/src/test/av1_highbd_iht_test.cc index 4aadf19482..8fea500db9 100644 --- a/media/libaom/src/test/av1_highbd_iht_test.cc +++ b/media/libaom/src/test/av1_highbd_iht_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/av1_rtcd.h" @@ -26,7 +28,7 @@ namespace { using libaom_test::ACMRandom; -using ::testing::tuple; +using std::tuple; typedef void (*HbdHtFunc)(const int16_t *input, int32_t *output, int stride, TX_TYPE tx_type, int bd); @@ -155,7 +157,7 @@ void AV1HighbdInvHTNxN::RunBitexactCheck() { TEST_P(AV1HighbdInvHTNxN, InvTransResultCheck) { RunBitexactCheck(); } -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_SSE4_1 #define PARAM_LIST_4X4 \ @@ -184,14 +186,14 @@ const IHbdHtParam kArrayIhtParam[] = { make_tuple(PARAM_LIST_4X4, FLIPADST_ADST, 12), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdInvHTNxN, - ::testing::ValuesIn(kArrayIhtParam)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1HighbdInvHTNxN, + ::testing::ValuesIn(kArrayIhtParam)); #endif // HAVE_SSE4_1 typedef void (*HighbdInvTxfm2dFunc)(const int32_t *input, uint8_t *output, int stride, const TxfmParam *txfm_param); -typedef ::testing::tuple AV1HighbdInvTxfm2dParam; +typedef std::tuple AV1HighbdInvTxfm2dParam; class AV1HighbdInvTxfm2d : public ::testing::TestWithParam { public: @@ -349,12 +351,12 @@ TEST_P(AV1HighbdInvTxfm2d, DISABLED_Speed) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdInvTxfm2d, - ::testing::Values(av1_highbd_inv_txfm_add_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1HighbdInvTxfm2d, + ::testing::Values(av1_highbd_inv_txfm_add_sse4_1)); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdInvTxfm2d, - ::testing::Values(av1_highbd_inv_txfm_add_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HighbdInvTxfm2d, + ::testing::Values(av1_highbd_inv_txfm_add_avx2)); #endif } // namespace diff --git a/media/libaom/src/test/av1_horz_only_frame_superres_test.cc b/media/libaom/src/test/av1_horz_only_frame_superres_test.cc index c26b70e17b..115fc84c0f 100644 --- a/media/libaom/src/test/av1_horz_only_frame_superres_test.cc +++ b/media/libaom/src/test/av1_horz_only_frame_superres_test.cc @@ -9,6 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include #include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -31,8 +32,8 @@ const int kVPad = 32; const int kHPad = 32; using libaom_test::ACMRandom; -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; template class TestImage { @@ -297,8 +298,8 @@ class LowBDConvolveHorizRSTest TEST_P(LowBDConvolveHorizRSTest, Correctness) { CorrectnessTest(); } TEST_P(LowBDConvolveHorizRSTest, DISABLED_Speed) { SpeedTest(); } -INSTANTIATE_TEST_CASE_P(SSE4_1, LowBDConvolveHorizRSTest, - ::testing::Values(av1_convolve_horiz_rs_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, LowBDConvolveHorizRSTest, + ::testing::Values(av1_convolve_horiz_rs_sse4_1)); #if CONFIG_AV1_HIGHBITDEPTH typedef void (*HighBDConvolveHorizRsFunc)(const uint16_t *src, int src_stride, @@ -355,7 +356,7 @@ const int kBDs[] = { 8, 10, 12 }; TEST_P(HighBDConvolveHorizRSTest, Correctness) { CorrectnessTest(); } TEST_P(HighBDConvolveHorizRSTest, DISABLED_Speed) { SpeedTest(); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, HighBDConvolveHorizRSTest, ::testing::Combine(::testing::Values(av1_highbd_convolve_horiz_rs_sse4_1), ::testing::ValuesIn(kBDs))); diff --git a/media/libaom/src/test/av1_inv_txfm1d_test.cc b/media/libaom/src/test/av1_inv_txfm1d_test.cc index 0fc2b03131..01d4a4d7f0 100644 --- a/media/libaom/src/test/av1_inv_txfm1d_test.cc +++ b/media/libaom/src/test/av1_inv_txfm1d_test.cc @@ -26,19 +26,15 @@ const int txfm_type_num = 2; const int txfm_size_ls[] = { 4, 8, 16, 32, 64 }; const TxfmFunc fwd_txfm_func_ls[][txfm_type_num] = { - { av1_fdct4_new, av1_fadst4_new }, - { av1_fdct8_new, av1_fadst8_new }, - { av1_fdct16_new, av1_fadst16_new }, - { av1_fdct32_new, NULL }, - { av1_fdct64_new, NULL }, + { av1_fdct4, av1_fadst4 }, { av1_fdct8, av1_fadst8 }, + { av1_fdct16, av1_fadst16 }, { av1_fdct32, NULL }, + { av1_fdct64, NULL }, }; const TxfmFunc inv_txfm_func_ls[][txfm_type_num] = { - { av1_idct4_new, av1_iadst4_new }, - { av1_idct8_new, av1_iadst8_new }, - { av1_idct16_new, av1_iadst16_new }, - { av1_idct32_new, NULL }, - { av1_idct64_new, NULL }, + { av1_idct4, av1_iadst4 }, { av1_idct8, av1_iadst8 }, + { av1_idct16, av1_iadst16 }, { av1_idct32, NULL }, + { av1_idct64, NULL }, }; // the maximum stage number of fwd/inv 1d dct/adst txfm is 12 diff --git a/media/libaom/src/test/av1_inv_txfm2d_test.cc b/media/libaom/src/test/av1_inv_txfm2d_test.cc index d8f3eca596..eacdf85d43 100644 --- a/media/libaom/src/test/av1_inv_txfm2d_test.cc +++ b/media/libaom/src/test/av1_inv_txfm2d_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "config/av1_rtcd.h" @@ -62,7 +63,7 @@ static const char *tx_type_name[] = { // AV1InvTxfm2dParam argument list: // tx_type_, tx_size_, max_error_, max_avg_error_ -typedef ::testing::tuple AV1InvTxfm2dParam; +typedef std::tuple AV1InvTxfm2dParam; class AV1InvTxfm2d : public ::testing::TestWithParam { public: @@ -226,8 +227,8 @@ vector GetInvTxfm2dParamList() { return param_list; } -INSTANTIATE_TEST_CASE_P(C, AV1InvTxfm2d, - ::testing::ValuesIn(GetInvTxfm2dParamList())); +INSTANTIATE_TEST_SUITE_P(C, AV1InvTxfm2d, + ::testing::ValuesIn(GetInvTxfm2dParamList())); TEST_P(AV1InvTxfm2d, RunRoundtripCheck) { RunRoundtripCheck(); } @@ -261,7 +262,7 @@ TEST(AV1InvTxfm2d, CfgTest) { } } -typedef ::testing::tuple AV1LbdInvTxfm2dParam; +typedef std::tuple AV1LbdInvTxfm2dParam; class AV1LbdInvTxfm2d : public ::testing::TestWithParam { public: virtual void SetUp() { target_func_ = GET_PARAM(0); } @@ -391,8 +392,8 @@ TEST_P(AV1LbdInvTxfm2d, DISABLED_Speed) { #if HAVE_SSSE3 #if defined(_MSC_VER) || defined(__SSSE3__) #include "av1/common/x86/av1_inv_txfm_ssse3.h" -INSTANTIATE_TEST_CASE_P(SSSE3, AV1LbdInvTxfm2d, - ::testing::Values(av1_lowbd_inv_txfm2d_add_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1LbdInvTxfm2d, + ::testing::Values(av1_lowbd_inv_txfm2d_add_ssse3)); #endif // _MSC_VER || __SSSE3__ #endif // HAVE_SSSE3 @@ -402,8 +403,8 @@ extern "C" void av1_lowbd_inv_txfm2d_add_avx2(const int32_t *input, TxType tx_type, TxSize tx_size, int eob); -INSTANTIATE_TEST_CASE_P(AVX2, AV1LbdInvTxfm2d, - ::testing::Values(av1_lowbd_inv_txfm2d_add_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1LbdInvTxfm2d, + ::testing::Values(av1_lowbd_inv_txfm2d_add_avx2)); #endif // HAVE_AVX2 // TODO(yunqing): Re-enable this unit test for NEON version after the functions @@ -414,8 +415,8 @@ extern "C" void av1_lowbd_inv_txfm2d_add_neon(const int32_t *input, TX_TYPE tx_type, TX_SIZE tx_size, int eob); -INSTANTIATE_TEST_CASE_P(NEON, AV1LbdInvTxfm2d, - ::testing::Values(av1_lowbd_inv_txfm2d_add_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, AV1LbdInvTxfm2d, + ::testing::Values(av1_lowbd_inv_txfm2d_add_neon)); #endif // HAVE_NEON } // namespace diff --git a/media/libaom/src/test/av1_nn_predict_test.cc b/media/libaom/src/test/av1_nn_predict_test.cc index f6c06b91cd..c03cba8c52 100644 --- a/media/libaom/src/test/av1_nn_predict_test.cc +++ b/media/libaom/src/test/av1_nn_predict_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "aom/aom_integer.h" @@ -27,7 +29,7 @@ typedef void (*NnPredict_Func)(const float *const input_nodes, const NN_CONFIG *const nn_config, int reduce_prec, float *const output); -typedef ::testing::tuple NnPredictTestParam; +typedef std::tuple NnPredictTestParam; const float epsilon = 1e-3f; // Error threshold for functional equivalence @@ -208,8 +210,8 @@ TEST_P(NnPredictTest, DISABLED_Speed) { } #if HAVE_SSE3 -INSTANTIATE_TEST_CASE_P(SSE3, NnPredictTest, - ::testing::Values(av1_nn_predict_sse3)); +INSTANTIATE_TEST_SUITE_P(SSE3, NnPredictTest, + ::testing::Values(av1_nn_predict_sse3)); #endif } // namespace diff --git a/media/libaom/src/test/av1_quantize_test.cc b/media/libaom/src/test/av1_quantize_test.cc index 54326aa56a..39a3c33d81 100644 --- a/media/libaom/src/test/av1_quantize_test.cc +++ b/media/libaom/src/test/av1_quantize_test.cc @@ -218,7 +218,7 @@ const QuantizeFuncParams qfps[4] = { 1024), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1QuantizeTest, ::testing::ValuesIn(qfps)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1QuantizeTest, ::testing::ValuesIn(qfps)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -233,7 +233,7 @@ const QuantizeFuncParams qfps_avx2[4] = { 1024), }; -INSTANTIATE_TEST_CASE_P(AVX2, AV1QuantizeTest, ::testing::ValuesIn(qfps_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1QuantizeTest, ::testing::ValuesIn(qfps_avx2)); #endif // HAVE_AVX2 } // namespace diff --git a/media/libaom/src/test/av1_round_shift_array_test.cc b/media/libaom/src/test/av1_round_shift_array_test.cc index 61dbed51f4..993fa9f19a 100644 --- a/media/libaom/src/test/av1_round_shift_array_test.cc +++ b/media/libaom/src/test/av1_round_shift_array_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "config/av1_rtcd.h" @@ -33,7 +34,7 @@ const int kValidBitCheck[] = { }; #endif // HAVE_SSE4_1 || HAVE_NEON -typedef ::testing::tuple +typedef std::tuple CompRoundShiftParam; class AV1CompRoundShiftTest @@ -111,7 +112,7 @@ TEST_P(AV1CompRoundShiftTest, DISABLED_Speed) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1CompRoundShiftTest, ::testing::Combine(::testing::Values(&av1_round_shift_array_sse4_1), ::testing::ValuesIn(txsize_to_bsize), @@ -119,7 +120,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AV1CompRoundShiftTest, ::testing::Combine(::testing::Values(&av1_round_shift_array_neon), ::testing::ValuesIn(txsize_to_bsize), diff --git a/media/libaom/src/test/av1_txfm_test.cc b/media/libaom/src/test/av1_txfm_test.cc index abbc475918..aedd45d133 100644 --- a/media/libaom/src/test/av1_txfm_test.cc +++ b/media/libaom/src/test/av1_txfm_test.cc @@ -119,7 +119,7 @@ void reference_idct_1d(const double *in, double *out, int size) { } } -// TODO(any): Copied from the old 'fadst4' (same as the new 'av1_fadst4_new' +// TODO(any): Copied from the old 'fadst4' (same as the new 'av1_fadst4' // function). Should be replaced by a proper reference function that takes // 'double' input & output. static void fadst4_new(const tran_low_t *input, tran_low_t *output) { diff --git a/media/libaom/src/test/av1_wedge_utils_test.cc b/media/libaom/src/test/av1_wedge_utils_test.cc index 6943329f10..f9dc838ff4 100644 --- a/media/libaom/src/test/av1_wedge_utils_test.cc +++ b/media/libaom/src/test/av1_wedge_utils_test.cc @@ -355,34 +355,34 @@ TEST_P(WedgeUtilsDeltaSquaresOptTest, RandomValues) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, WedgeUtilsSSEOptTest, ::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_c, av1_wedge_sse_from_residuals_sse2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, WedgeUtilsSignOptTest, ::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_c, av1_wedge_sign_from_residuals_sse2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, WedgeUtilsDeltaSquaresOptTest, ::testing::Values(TestFuncsFDS(av1_wedge_compute_delta_squares_c, av1_wedge_compute_delta_squares_sse2))); #endif // HAVE_SSE2 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, WedgeUtilsSSEOptTest, ::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_sse2, av1_wedge_sse_from_residuals_avx2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, WedgeUtilsSignOptTest, ::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_sse2, av1_wedge_sign_from_residuals_avx2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, WedgeUtilsDeltaSquaresOptTest, ::testing::Values(TestFuncsFDS(av1_wedge_compute_delta_squares_sse2, av1_wedge_compute_delta_squares_avx2))); diff --git a/media/libaom/src/test/avg_test.cc b/media/libaom/src/test/avg_test.cc index cbd3461d26..1742aec5fc 100644 --- a/media/libaom/src/test/avg_test.cc +++ b/media/libaom/src/test/avg_test.cc @@ -9,6 +9,7 @@ */ #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -244,13 +245,13 @@ TEST_P(IntProColTest, Random) { using std::make_tuple; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AverageTest, ::testing::Values(make_tuple(16, 16, 1, 8, &aom_avg_8x8_c), make_tuple(16, 16, 1, 4, &aom_avg_4x4_c))); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AverageTest, ::testing::Values(make_tuple(16, 16, 0, 8, &aom_avg_8x8_sse2), make_tuple(16, 16, 5, 8, &aom_avg_8x8_sse2), @@ -259,7 +260,7 @@ INSTANTIATE_TEST_CASE_P( make_tuple(16, 16, 5, 4, &aom_avg_4x4_sse2), make_tuple(32, 32, 15, 4, &aom_avg_4x4_sse2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, IntProRowTest, ::testing::Values(make_tuple(16, &aom_int_pro_row_sse2, &aom_int_pro_row_c), make_tuple(32, &aom_int_pro_row_sse2, &aom_int_pro_row_c), @@ -267,7 +268,7 @@ INSTANTIATE_TEST_CASE_P( make_tuple(128, &aom_int_pro_row_sse2, &aom_int_pro_row_c))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, IntProColTest, ::testing::Values(make_tuple(16, &aom_int_pro_col_sse2, &aom_int_pro_col_c), make_tuple(32, &aom_int_pro_col_sse2, &aom_int_pro_col_c), @@ -277,7 +278,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AverageTest, ::testing::Values(make_tuple(16, 16, 0, 8, &aom_avg_8x8_neon), make_tuple(16, 16, 5, 8, &aom_avg_8x8_neon), diff --git a/media/libaom/src/test/blend_a64_mask_1d_test.cc b/media/libaom/src/test/blend_a64_mask_1d_test.cc index 3a3e1b95ce..1b6350c793 100644 --- a/media/libaom/src/test/blend_a64_mask_1d_test.cc +++ b/media/libaom/src/test/blend_a64_mask_1d_test.cc @@ -194,13 +194,13 @@ static void blend_a64_vmask_ref(uint8_t *dst, uint32_t dst_stride, 0, 0); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, BlendA64Mask1DTest8B, ::testing::Values(TestFuncs(blend_a64_hmask_ref, aom_blend_a64_hmask_c), TestFuncs(blend_a64_vmask_ref, aom_blend_a64_vmask_c))); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64Mask1DTest8B, ::testing::Values( TestFuncs(blend_a64_hmask_ref, aom_blend_a64_hmask_sse4_1), @@ -208,11 +208,11 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE4_1 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, BlendA64Mask1DTest8B, - ::testing::Values(TestFuncs(blend_a64_hmask_ref, - aom_blend_a64_hmask_neon), - TestFuncs(blend_a64_vmask_ref, - aom_blend_a64_vmask_neon))); +INSTANTIATE_TEST_SUITE_P( + NEON, BlendA64Mask1DTest8B, + ::testing::Values(TestFuncs(blend_a64_hmask_ref, aom_blend_a64_hmask_neon), + TestFuncs(blend_a64_vmask_ref, + aom_blend_a64_vmask_neon))); #endif // HAVE_NEON ////////////////////////////////////////////////////////////////////////////// @@ -321,7 +321,7 @@ static void highbd_blend_a64_vmask_ref( BlendA64Mask1DTestHBD::kMaxMaskSize, w, h, 0, 0, bd); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, BlendA64Mask1DTestHBD, ::testing::Values(TestFuncsHBD(highbd_blend_a64_hmask_ref, aom_highbd_blend_a64_hmask_c), @@ -329,7 +329,7 @@ INSTANTIATE_TEST_CASE_P( aom_highbd_blend_a64_vmask_c))); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64Mask1DTestHBD, ::testing::Values(TestFuncsHBD(highbd_blend_a64_hmask_ref, aom_highbd_blend_a64_hmask_sse4_1), diff --git a/media/libaom/src/test/blend_a64_mask_test.cc b/media/libaom/src/test/blend_a64_mask_test.cc index 4d9ed36d0f..5c2c291fde 100644 --- a/media/libaom/src/test/blend_a64_mask_test.cc +++ b/media/libaom/src/test/blend_a64_mask_test.cc @@ -246,15 +246,15 @@ TEST_P(BlendA64MaskTest8B, DISABLED_Speed) { } } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, BlendA64MaskTest8B, - ::testing::Values(TestFuncs( - aom_blend_a64_mask_c, aom_blend_a64_mask_sse4_1))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, BlendA64MaskTest8B, + ::testing::Values(TestFuncs( + aom_blend_a64_mask_c, aom_blend_a64_mask_sse4_1))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, BlendA64MaskTest8B, - ::testing::Values(TestFuncs(aom_blend_a64_mask_sse4_1, - aom_blend_a64_mask_avx2))); +INSTANTIATE_TEST_SUITE_P(AVX2, BlendA64MaskTest8B, + ::testing::Values(TestFuncs(aom_blend_a64_mask_sse4_1, + aom_blend_a64_mask_avx2))); #endif // HAVE_AVX2 ////////////////////////////////////////////////////////////////////////////// @@ -342,21 +342,21 @@ TEST_P(BlendA64MaskTest8B_d16, ExtremeValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64MaskTest8B_d16, ::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c, aom_lowbd_blend_a64_d16_mask_sse4_1))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, BlendA64MaskTest8B_d16, ::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c, aom_lowbd_blend_a64_d16_mask_avx2))); #endif // HAVE_AVX2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, BlendA64MaskTest8B_d16, ::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c, aom_lowbd_blend_a64_d16_mask_neon))); @@ -457,7 +457,7 @@ TEST_P(BlendA64MaskTestHBD, ExtremeValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64MaskTestHBD, ::testing::Values(TestFuncsHBD(aom_highbd_blend_a64_mask_c, aom_highbd_blend_a64_mask_sse4_1))); @@ -589,19 +589,19 @@ TEST_P(BlendA64MaskTestHBD_d16, DISABLED_Speed) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, BlendA64MaskTestHBD_d16, ::testing::Values(TestFuncsHBD_d16(aom_highbd_blend_a64_d16_mask_c, NULL))); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64MaskTestHBD_d16, ::testing::Values(TestFuncsHBD_d16(aom_highbd_blend_a64_d16_mask_c, aom_highbd_blend_a64_d16_mask_sse4_1))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, BlendA64MaskTestHBD_d16, ::testing::Values(TestFuncsHBD_d16(aom_highbd_blend_a64_d16_mask_c, aom_highbd_blend_a64_d16_mask_avx2))); @@ -610,7 +610,7 @@ INSTANTIATE_TEST_CASE_P( // TODO(slavarnway): Enable the following in the avx2 commit. (56501) #if 0 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BlendA64MaskTestHBD, ::testing::Values(TestFuncsHBD(aom_highbd_blend_a64_mask_c, aom_highbd_blend_a64_mask_avx2))); diff --git a/media/libaom/src/test/blockd_test.cc b/media/libaom/src/test/blockd_test.cc index ab624007ce..17e6968630 100644 --- a/media/libaom/src/test/blockd_test.cc +++ b/media/libaom/src/test/blockd_test.cc @@ -56,7 +56,7 @@ TEST(BlockdTest, GetPartitionSubsize) { BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID }, { BLOCK_INVALID, - BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32, @@ -65,7 +65,7 @@ TEST(BlockdTest, GetPartitionSubsize) { BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID }, { BLOCK_INVALID, - BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32, @@ -74,7 +74,7 @@ TEST(BlockdTest, GetPartitionSubsize) { BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID }, { BLOCK_INVALID, - BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64, @@ -83,7 +83,7 @@ TEST(BlockdTest, GetPartitionSubsize) { BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID }, { BLOCK_INVALID, - BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8, + BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64, diff --git a/media/libaom/src/test/cdef_test.cc b/media/libaom/src/test/cdef_test.cc index 8201818795..a2ec1e31e7 100644 --- a/media/libaom/src/test/cdef_test.cc +++ b/media/libaom/src/test/cdef_test.cc @@ -11,6 +11,7 @@ #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -28,8 +29,8 @@ using libaom_test::ACMRandom; namespace { -typedef ::testing::tuple +typedef std::tuple cdef_dir_param_t; class CDEFBlockTest : public ::testing::TestWithParam { @@ -185,7 +186,7 @@ void test_cdef_speed(int bsize, int iterations, cdef_filter_block_func cdef, typedef int (*find_dir_t)(const uint16_t *img, int stride, int32_t *var, int coeff_shift); -typedef ::testing::tuple find_dir_param_t; +typedef std::tuple find_dir_param_t; class CDEFFindDirTest : public ::testing::TestWithParam { public: @@ -285,140 +286,140 @@ TEST_P(CDEFFindDirSpeedTest, DISABLED_TestSpeed) { test_finddir_speed(finddir, ref_finddir); } -using ::testing::make_tuple; +using std::make_tuple; // VS compiling for 32 bit targets does not support vector types in // structs as arguments, which makes the v256 type of the intrinsics // hard to support, so optimizations for this target are disabled. #if defined(_WIN64) || !defined(_MSC_VER) || defined(__clang__) #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, CDEFBlockTest, ::testing::Combine(::testing::Values(&cdef_filter_block_sse2), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSE2, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse2, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirTest, + ::testing::Values(make_tuple(&cdef_find_dir_sse2, + &cdef_find_dir_c))); #endif #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, CDEFBlockTest, ::testing::Combine(::testing::Values(&cdef_filter_block_ssse3), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSSE3, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_ssse3, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSSE3, CDEFFindDirTest, + ::testing::Values(make_tuple(&cdef_find_dir_ssse3, + &cdef_find_dir_c))); #endif #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, CDEFBlockTest, ::testing::Combine(::testing::Values(&cdef_filter_block_sse4_1), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSE4_1, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse4_1, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, CDEFFindDirTest, + ::testing::Values(make_tuple(&cdef_find_dir_sse4_1, + &cdef_find_dir_c))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, CDEFBlockTest, ::testing::Combine(::testing::Values(&cdef_filter_block_avx2), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(AVX2, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_avx2, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(AVX2, CDEFFindDirTest, + ::testing::Values(make_tuple(&cdef_find_dir_avx2, + &cdef_find_dir_c))); #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, CDEFBlockTest, ::testing::Combine(::testing::Values(&cdef_filter_block_neon), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(NEON, CDEFFindDirTest, - ::testing::Values(make_tuple(&cdef_find_dir_neon, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(NEON, CDEFFindDirTest, + ::testing::Values(make_tuple(&cdef_find_dir_neon, + &cdef_find_dir_c))); #endif // Test speed for all supported architectures #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, CDEFSpeedTest, ::testing::Combine(::testing::Values(&cdef_filter_block_sse2), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSE2, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse2, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSE2, CDEFFindDirSpeedTest, + ::testing::Values(make_tuple(&cdef_find_dir_sse2, + &cdef_find_dir_c))); #endif #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, CDEFSpeedTest, ::testing::Combine(::testing::Values(&cdef_filter_block_ssse3), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSSE3, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_ssse3, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSSE3, CDEFFindDirSpeedTest, + ::testing::Values(make_tuple(&cdef_find_dir_ssse3, + &cdef_find_dir_c))); #endif #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, CDEFSpeedTest, ::testing::Combine(::testing::Values(&cdef_filter_block_sse4_1), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(SSE4_1, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_sse4_1, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, CDEFFindDirSpeedTest, + ::testing::Values(make_tuple(&cdef_find_dir_sse4_1, + &cdef_find_dir_c))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, CDEFSpeedTest, ::testing::Combine(::testing::Values(&cdef_filter_block_avx2), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(AVX2, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_avx2, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(AVX2, CDEFFindDirSpeedTest, + ::testing::Values(make_tuple(&cdef_find_dir_avx2, + &cdef_find_dir_c))); #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, CDEFSpeedTest, ::testing::Combine(::testing::Values(&cdef_filter_block_neon), ::testing::Values(&cdef_filter_block_c), ::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4, BLOCK_8X8), ::testing::Range(0, 16), ::testing::Range(8, 13, 2))); -INSTANTIATE_TEST_CASE_P(NEON, CDEFFindDirSpeedTest, - ::testing::Values(make_tuple(&cdef_find_dir_neon, - &cdef_find_dir_c))); +INSTANTIATE_TEST_SUITE_P(NEON, CDEFFindDirSpeedTest, + ::testing::Values(make_tuple(&cdef_find_dir_neon, + &cdef_find_dir_c))); #endif #endif // defined(_WIN64) || !defined(_MSC_VER) diff --git a/media/libaom/src/test/cfl_test.cc b/media/libaom/src/test/cfl_test.cc index b2d613799e..d2973159c8 100644 --- a/media/libaom/src/test/cfl_test.cc +++ b/media/libaom/src/test/cfl_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/av1_rtcd.h" @@ -17,7 +19,7 @@ #include "test/util.h" #include "test/acm_random.h" -using ::testing::make_tuple; +using std::make_tuple; using libaom_test::ACMRandom; @@ -166,13 +168,13 @@ class CFLTestWithAlignedData : public CFLTest { }; typedef cfl_subtract_average_fn (*sub_avg_fn)(TX_SIZE tx_size); -typedef ::testing::tuple sub_avg_param; +typedef std::tuple sub_avg_param; class CFLSubAvgTest : public ::testing::TestWithParam, public CFLTestWithData { public: virtual void SetUp() { - CFLTest::init(::testing::get<0>(this->GetParam())); - sub_avg = ::testing::get<1>(this->GetParam())(tx_size); + CFLTest::init(std::get<0>(this->GetParam())); + sub_avg = std::get<1>(this->GetParam())(tx_size); sub_avg_ref = cfl_get_subtract_average_fn_c(tx_size); } virtual ~CFLSubAvgTest() {} @@ -216,10 +218,10 @@ class CFLSubsampleTest : public ::testing::TestWithParam, public CFLTestWithData { public: virtual void SetUp() { - CFLTest::init(::testing::get<0>(this->GetParam())); - fun_420 = ::testing::get<1>(this->GetParam())(this->tx_size); - fun_422 = ::testing::get<2>(this->GetParam())(this->tx_size); - fun_444 = ::testing::get<3>(this->GetParam())(this->tx_size); + CFLTest::init(std::get<0>(this->GetParam())); + fun_420 = std::get<1>(this->GetParam())(this->tx_size); + fun_422 = std::get<2>(this->GetParam())(this->tx_size); + fun_444 = std::get<3>(this->GetParam())(this->tx_size); } protected: @@ -269,8 +271,8 @@ class CFLSubsampleTest : public ::testing::TestWithParam, }; typedef cfl_subsample_lbd_fn (*get_subsample_lbd_fn)(TX_SIZE tx_size); -typedef ::testing::tuple +typedef std::tuple subsample_lbd_param; class CFLSubsampleLBDTest : public CFLSubsampleTest +typedef std::tuple subsample_hbd_param; class CFLSubsampleHBDTest : public CFLSubsampleTest predict_param; +typedef std::tuple predict_param; class CFLPredictTest : public ::testing::TestWithParam, public CFLTestWithAlignedData { public: virtual void SetUp() { - CFLTest::init(::testing::get<0>(this->GetParam())); - predict = ::testing::get<1>(this->GetParam())(tx_size); + CFLTest::init(std::get<0>(this->GetParam())); + predict = std::get<1>(this->GetParam())(tx_size); predict_ref = cfl_get_predict_lbd_fn_c(tx_size); } virtual ~CFLPredictTest() {} @@ -402,13 +404,13 @@ TEST_P(CFLPredictTest, DISABLED_PredictSpeedTest) { #if CONFIG_AV1_HIGHBITDEPTH typedef cfl_predict_hbd_fn (*get_predict_fn_hbd)(TX_SIZE tx_size); -typedef ::testing::tuple predict_param_hbd; +typedef std::tuple predict_param_hbd; class CFLPredictHBDTest : public ::testing::TestWithParam, public CFLTestWithAlignedData { public: virtual void SetUp() { - CFLTest::init(::testing::get<0>(this->GetParam())); - predict = ::testing::get<1>(this->GetParam())(tx_size); + CFLTest::init(std::get<0>(this->GetParam())); + predict = std::get<1>(this->GetParam())(tx_size); predict_ref = cfl_get_predict_hbd_fn_c(tx_size); } virtual ~CFLPredictHBDTest() {} @@ -454,8 +456,8 @@ TEST_P(CFLPredictHBDTest, DISABLED_PredictHBDSpeedTest) { const sub_avg_param sub_avg_sizes_sse2[] = { ALL_CFL_TX_SIZES( cfl_get_subtract_average_fn_sse2) }; -INSTANTIATE_TEST_CASE_P(SSE2, CFLSubAvgTest, - ::testing::ValuesIn(sub_avg_sizes_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, CFLSubAvgTest, + ::testing::ValuesIn(sub_avg_sizes_sse2)); #endif @@ -469,11 +471,11 @@ const subsample_lbd_param subsample_lbd_sizes_ssse3[] = { const predict_param predict_sizes_ssse3[] = { ALL_CFL_TX_SIZES( cfl_get_predict_lbd_fn_ssse3) }; -INSTANTIATE_TEST_CASE_P(SSSE3, CFLSubsampleLBDTest, - ::testing::ValuesIn(subsample_lbd_sizes_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, CFLSubsampleLBDTest, + ::testing::ValuesIn(subsample_lbd_sizes_ssse3)); -INSTANTIATE_TEST_CASE_P(SSSE3, CFLPredictTest, - ::testing::ValuesIn(predict_sizes_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, CFLPredictTest, + ::testing::ValuesIn(predict_sizes_ssse3)); #if CONFIG_AV1_HIGHBITDEPTH const subsample_hbd_param subsample_hbd_sizes_ssse3[] = { @@ -485,11 +487,11 @@ const subsample_hbd_param subsample_hbd_sizes_ssse3[] = { const predict_param_hbd predict_sizes_hbd_ssse3[] = { ALL_CFL_TX_SIZES( cfl_get_predict_hbd_fn_ssse3) }; -INSTANTIATE_TEST_CASE_P(SSSE3, CFLSubsampleHBDTest, - ::testing::ValuesIn(subsample_hbd_sizes_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, CFLSubsampleHBDTest, + ::testing::ValuesIn(subsample_hbd_sizes_ssse3)); -INSTANTIATE_TEST_CASE_P(SSSE3, CFLPredictHBDTest, - ::testing::ValuesIn(predict_sizes_hbd_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, CFLPredictHBDTest, + ::testing::ValuesIn(predict_sizes_hbd_ssse3)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_SSSE3 @@ -506,14 +508,14 @@ const subsample_lbd_param subsample_lbd_sizes_avx2[] = { const predict_param predict_sizes_avx2[] = { ALL_CFL_TX_SIZES( cfl_get_predict_lbd_fn_avx2) }; -INSTANTIATE_TEST_CASE_P(AVX2, CFLSubAvgTest, - ::testing::ValuesIn(sub_avg_sizes_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, CFLSubAvgTest, + ::testing::ValuesIn(sub_avg_sizes_avx2)); -INSTANTIATE_TEST_CASE_P(AVX2, CFLSubsampleLBDTest, - ::testing::ValuesIn(subsample_lbd_sizes_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, CFLSubsampleLBDTest, + ::testing::ValuesIn(subsample_lbd_sizes_avx2)); -INSTANTIATE_TEST_CASE_P(AVX2, CFLPredictTest, - ::testing::ValuesIn(predict_sizes_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, CFLPredictTest, + ::testing::ValuesIn(predict_sizes_avx2)); #if CONFIG_AV1_HIGHBITDEPTH const subsample_hbd_param subsample_hbd_sizes_avx2[] = { @@ -525,11 +527,11 @@ const subsample_hbd_param subsample_hbd_sizes_avx2[] = { const predict_param_hbd predict_sizes_hbd_avx2[] = { ALL_CFL_TX_SIZES( cfl_get_predict_hbd_fn_avx2) }; -INSTANTIATE_TEST_CASE_P(AVX2, CFLSubsampleHBDTest, - ::testing::ValuesIn(subsample_hbd_sizes_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, CFLSubsampleHBDTest, + ::testing::ValuesIn(subsample_hbd_sizes_avx2)); -INSTANTIATE_TEST_CASE_P(AVX2, CFLPredictHBDTest, - ::testing::ValuesIn(predict_sizes_hbd_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, CFLPredictHBDTest, + ::testing::ValuesIn(predict_sizes_hbd_avx2)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_AVX2 @@ -546,14 +548,14 @@ const subsample_lbd_param subsample_lbd_sizes_neon[] = { cfl_get_luma_subsampling_444_lbd_neon) }; -INSTANTIATE_TEST_CASE_P(NEON, CFLSubAvgTest, - ::testing::ValuesIn(sub_avg_sizes_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, CFLSubAvgTest, + ::testing::ValuesIn(sub_avg_sizes_neon)); -INSTANTIATE_TEST_CASE_P(NEON, CFLSubsampleLBDTest, - ::testing::ValuesIn(subsample_lbd_sizes_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, CFLSubsampleLBDTest, + ::testing::ValuesIn(subsample_lbd_sizes_neon)); -INSTANTIATE_TEST_CASE_P(NEON, CFLPredictTest, - ::testing::ValuesIn(predict_sizes_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, CFLPredictTest, + ::testing::ValuesIn(predict_sizes_neon)); #if CONFIG_AV1_HIGHBITDEPTH const subsample_hbd_param subsample_hbd_sizes_neon[] = { @@ -565,11 +567,11 @@ const subsample_hbd_param subsample_hbd_sizes_neon[] = { const predict_param_hbd predict_sizes_hbd_neon[] = { ALL_CFL_TX_SIZES( cfl_get_predict_hbd_fn_neon) }; -INSTANTIATE_TEST_CASE_P(NEON, CFLSubsampleHBDTest, - ::testing::ValuesIn(subsample_hbd_sizes_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, CFLSubsampleHBDTest, + ::testing::ValuesIn(subsample_hbd_sizes_neon)); -INSTANTIATE_TEST_CASE_P(NEON, CFLPredictHBDTest, - ::testing::ValuesIn(predict_sizes_hbd_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, CFLPredictHBDTest, + ::testing::ValuesIn(predict_sizes_hbd_neon)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_NEON @@ -577,7 +579,7 @@ INSTANTIATE_TEST_CASE_P(NEON, CFLPredictHBDTest, const sub_avg_param sub_avg_sizes_vsx[] = { ALL_CFL_TX_SIZES( cfl_get_subtract_average_fn_vsx) }; -INSTANTIATE_TEST_CASE_P(VSX, CFLSubAvgTest, - ::testing::ValuesIn(sub_avg_sizes_vsx)); +INSTANTIATE_TEST_SUITE_P(VSX, CFLSubAvgTest, + ::testing::ValuesIn(sub_avg_sizes_vsx)); #endif } // namespace diff --git a/media/libaom/src/test/codec_factory.h b/media/libaom/src/test/codec_factory.h index b2647f7beb..801b8948fe 100644 --- a/media/libaom/src/test/codec_factory.h +++ b/media/libaom/src/test/codec_factory.h @@ -11,6 +11,8 @@ #ifndef AOM_TEST_CODEC_FACTORY_H_ #define AOM_TEST_CODEC_FACTORY_H_ +#include + #include "config/aom_config.h" #include "aom/aom_decoder.h" @@ -44,7 +46,7 @@ class CodecFactory { TwopassStatsStore *stats) const = 0; virtual aom_codec_err_t DefaultEncoderConfig(aom_codec_enc_cfg_t *cfg, - int usage) const = 0; + unsigned int usage) const = 0; }; /* Provide CodecTestWithParams classes for a variable number of parameters @@ -54,27 +56,28 @@ class CodecFactory { template class CodecTestWithParam : public ::testing::TestWithParam< - ::testing::tuple > {}; + std::tuple > {}; template class CodecTestWith2Params : public ::testing::TestWithParam< - ::testing::tuple > {}; + std::tuple > {}; template class CodecTestWith3Params : public ::testing::TestWithParam< - ::testing::tuple > {}; + std::tuple > {}; template class CodecTestWith4Params - : public ::testing::TestWithParam< ::testing::tuple< - const libaom_test::CodecFactory *, T1, T2, T3, T4> > {}; + : public ::testing::TestWithParam< + std::tuple > {}; template class CodecTestWith5Params - : public ::testing::TestWithParam< ::testing::tuple< - const libaom_test::CodecFactory *, T1, T2, T3, T4, T5> > {}; + : public ::testing::TestWithParam< + std::tuple > { +}; /* * AV1 Codec Definitions @@ -145,7 +148,7 @@ class AV1CodecFactory : public CodecFactory { } virtual aom_codec_err_t DefaultEncoderConfig(aom_codec_enc_cfg_t *cfg, - int usage) const { + unsigned int usage) const { #if CONFIG_AV1_ENCODER return aom_codec_enc_config_default(aom_codec_av1_cx(), cfg, usage); #else @@ -159,7 +162,7 @@ class AV1CodecFactory : public CodecFactory { const libaom_test::AV1CodecFactory kAV1; #define AV1_INSTANTIATE_TEST_CASE(test, ...) \ - INSTANTIATE_TEST_CASE_P( \ + INSTANTIATE_TEST_SUITE_P( \ AV1, test, \ ::testing::Combine( \ ::testing::Values(static_cast( \ diff --git a/media/libaom/src/test/coding_path_sync.cc b/media/libaom/src/test/coding_path_sync.cc index 6735236ccd..4c613dc03b 100644 --- a/media/libaom/src/test/coding_path_sync.cc +++ b/media/libaom/src/test/coding_path_sync.cc @@ -15,12 +15,13 @@ #include "config/aom_config.h" -#include "aom_ports/mem.h" // ROUND_POWER_OF_TWO #include "aom/aomcx.h" #include "aom/aomdx.h" #include "aom/aom_encoder.h" #include "aom/aom_decoder.h" +#define NELEMENTS(x) static_cast(sizeof(x) / sizeof(x[0])) + using libaom_test::ACMRandom; namespace { diff --git a/media/libaom/src/test/comp_avg_pred_test.cc b/media/libaom/src/test/comp_avg_pred_test.cc index 21bfb573d9..ac625a79d3 100644 --- a/media/libaom/src/test/comp_avg_pred_test.cc +++ b/media/libaom/src/test/comp_avg_pred_test.cc @@ -18,8 +18,8 @@ using libaom_test::AV1DISTWTDCOMPAVG::AV1DISTWTDCOMPAVGUPSAMPLEDTest; using libaom_test::AV1DISTWTDCOMPAVG::AV1HighBDDISTWTDCOMPAVGTest; using libaom_test::AV1DISTWTDCOMPAVG::AV1HighBDDISTWTDCOMPAVGUPSAMPLEDTest; #endif -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace { @@ -28,9 +28,9 @@ TEST_P(AV1DISTWTDCOMPAVGTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); } TEST_P(AV1DISTWTDCOMPAVGTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); } #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P(SSSE3, AV1DISTWTDCOMPAVGTest, - libaom_test::AV1DISTWTDCOMPAVG::BuildParams( - aom_dist_wtd_comp_avg_pred_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1DISTWTDCOMPAVGTest, + libaom_test::AV1DISTWTDCOMPAVG::BuildParams( + aom_dist_wtd_comp_avg_pred_ssse3)); #endif TEST_P(AV1DISTWTDCOMPAVGUPSAMPLEDTest, DISABLED_Speed) { @@ -42,9 +42,9 @@ TEST_P(AV1DISTWTDCOMPAVGUPSAMPLEDTest, CheckOutput) { } #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P(SSSE3, AV1DISTWTDCOMPAVGUPSAMPLEDTest, - libaom_test::AV1DISTWTDCOMPAVG::BuildParams( - aom_dist_wtd_comp_avg_upsampled_pred_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1DISTWTDCOMPAVGUPSAMPLEDTest, + libaom_test::AV1DISTWTDCOMPAVG::BuildParams( + aom_dist_wtd_comp_avg_upsampled_pred_ssse3)); #endif #if CONFIG_AV1_HIGHBITDEPTH @@ -57,9 +57,9 @@ TEST_P(AV1HighBDDISTWTDCOMPAVGTest, CheckOutput) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, AV1HighBDDISTWTDCOMPAVGTest, - libaom_test::AV1DISTWTDCOMPAVG::BuildParams( - aom_highbd_dist_wtd_comp_avg_pred_sse2, 1)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1HighBDDISTWTDCOMPAVGTest, + libaom_test::AV1DISTWTDCOMPAVG::BuildParams( + aom_highbd_dist_wtd_comp_avg_pred_sse2, 1)); #endif TEST_P(AV1HighBDDISTWTDCOMPAVGUPSAMPLEDTest, DISABLED_Speed) { @@ -71,9 +71,9 @@ TEST_P(AV1HighBDDISTWTDCOMPAVGUPSAMPLEDTest, CheckOutput) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, AV1HighBDDISTWTDCOMPAVGUPSAMPLEDTest, - libaom_test::AV1DISTWTDCOMPAVG::BuildParams( - aom_highbd_dist_wtd_comp_avg_upsampled_pred_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1HighBDDISTWTDCOMPAVGUPSAMPLEDTest, + libaom_test::AV1DISTWTDCOMPAVG::BuildParams( + aom_highbd_dist_wtd_comp_avg_upsampled_pred_sse2)); #endif #endif // CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/test/comp_avg_pred_test.h b/media/libaom/src/test/comp_avg_pred_test.h index 27a29d38a4..7f73312c4e 100644 --- a/media/libaom/src/test/comp_avg_pred_test.h +++ b/media/libaom/src/test/comp_avg_pred_test.h @@ -12,6 +12,8 @@ #ifndef AOM_TEST_COMP_AVG_PRED_TEST_H_ #define AOM_TEST_COMP_AVG_PRED_TEST_H_ +#include + #include "config/aom_dsp_rtcd.h" #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -38,9 +40,9 @@ typedef void (*distwtdcompavgupsampled_func)( int height, int subpel_x_q3, int subpel_y_q3, const uint8_t *ref, int ref_stride, const DIST_WTD_COMP_PARAMS *jcp_param, int subpel_search); -typedef ::testing::tuple DISTWTDCOMPAVGParam; +typedef std::tuple DISTWTDCOMPAVGParam; -typedef ::testing::tuple +typedef std::tuple DISTWTDCOMPAVGUPSAMPLEDParam; #if CONFIG_AV1_HIGHBITDEPTH @@ -51,10 +53,10 @@ typedef void (*highbddistwtdcompavgupsampled_func)( int ref_stride, int bd, const DIST_WTD_COMP_PARAMS *jcp_param, int subpel_search); -typedef ::testing::tuple +typedef std::tuple HighbdDISTWTDCOMPAVGUPSAMPLEDParam; -typedef ::testing::tuple +typedef std::tuple HighbdDISTWTDCOMPAVGParam; ::testing::internal::ParamGenerator BuildParams( diff --git a/media/libaom/src/test/comp_mask_variance_test.cc b/media/libaom/src/test/comp_mask_variance_test.cc index f01c93c220..b666306a30 100644 --- a/media/libaom/src/test/comp_mask_variance_test.cc +++ b/media/libaom/src/test/comp_mask_variance_test.cc @@ -11,6 +11,7 @@ #include #include +#include #include "config/aom_config.h" #include "config/aom_dsp_rtcd.h" @@ -40,7 +41,7 @@ const BLOCK_SIZE kValidBlockSize[] = { BLOCK_16X32, BLOCK_32X8, BLOCK_32X16, BLOCK_32X32, }; #endif -typedef ::testing::tuple CompMaskPredParam; +typedef std::tuple CompMaskPredParam; class AV1CompMaskVarianceTest : public ::testing::TestWithParam { @@ -105,8 +106,7 @@ void AV1CompMaskVarianceTest::RunCheckOutput(comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv) { const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); for (int wedge_index = 0; wedge_index < wedge_types; ++wedge_index) { const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize); @@ -123,8 +123,7 @@ void AV1CompMaskVarianceTest::RunSpeedTest(comp_mask_pred_func test_impl, BLOCK_SIZE bsize) { const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); int wedge_index = wedge_types / 2; const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize); const int num_loops = 1000000000 / (w + h); @@ -158,14 +157,14 @@ TEST_P(AV1CompMaskVarianceTest, DISABLED_Speed) { } #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, AV1CompMaskVarianceTest, ::testing::Combine(::testing::Values(&aom_comp_mask_pred_ssse3), ::testing::ValuesIn(kValidBlockSize))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1CompMaskVarianceTest, ::testing::Combine(::testing::Values(&aom_comp_mask_pred_avx2), ::testing::ValuesIn(kValidBlockSize))); @@ -189,7 +188,7 @@ void AV1CompMaskUpVarianceTest::RunCheckOutput(comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv) { const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); int subpel_search; for (subpel_search = USE_4_TAPS; subpel_search <= USE_8_TAPS; ++subpel_search) { @@ -224,8 +223,7 @@ void AV1CompMaskUpVarianceTest::RunSpeedTest(comp_mask_pred_func test_impl, const int h = block_size_high[bsize]; const int subx = havSub ? 3 : 0; const int suby = havSub ? 4 : 0; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); int wedge_index = wedge_types / 2; const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize); @@ -262,14 +260,14 @@ TEST_P(AV1CompMaskUpVarianceTest, DISABLED_Speed) { } #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, AV1CompMaskUpVarianceTest, ::testing::Combine(::testing::Values(&aom_comp_mask_pred_ssse3), ::testing::ValuesIn(kValidBlockSize))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1CompMaskUpVarianceTest, ::testing::Combine(::testing::Values(&aom_comp_mask_pred_avx2), ::testing::ValuesIn(kValidBlockSize))); @@ -284,7 +282,7 @@ typedef void (*highbd_comp_mask_pred_func)(uint8_t *comp_pred8, int ref_stride, const uint8_t *mask, int mask_stride, int invert_mask); -typedef ::testing::tuple +typedef std::tuple HighbdCompMaskPredParam; class AV1HighbdCompMaskVarianceTest @@ -348,11 +346,9 @@ void AV1HighbdCompMaskVarianceTest::TearDown() { void AV1HighbdCompMaskVarianceTest::RunCheckOutput( highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv) { int bd_ = GET_PARAM(2); - const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); for (int i = 0; i < MAX_SB_SQUARE; ++i) { pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1); @@ -382,8 +378,7 @@ void AV1HighbdCompMaskVarianceTest::RunSpeedTest( const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); int wedge_index = wedge_types / 2; for (int i = 0; i < MAX_SB_SQUARE; ++i) { @@ -427,7 +422,7 @@ TEST_P(AV1HighbdCompMaskVarianceTest, DISABLED_Speed) { } #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1HighbdCompMaskVarianceTest, ::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_avx2), ::testing::ValuesIn(kValidBlockSize), @@ -435,7 +430,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AV1HighbdCompMaskVarianceTest, ::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_sse2), ::testing::ValuesIn(kValidBlockSize), @@ -464,7 +459,7 @@ void AV1HighbdCompMaskUpVarianceTest::RunCheckOutput( int bd_ = GET_PARAM(2); const int w = block_size_wide[bsize]; const int h = block_size_high[bsize]; - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); for (int i = 0; i < MAX_SB_SQUARE; ++i) { pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1); @@ -516,8 +511,7 @@ void AV1HighbdCompMaskUpVarianceTest::RunSpeedTest( const int h = block_size_high[bsize]; const int subx = havSub ? 3 : 0; const int suby = havSub ? 4 : 0; - - int wedge_types = (1 << get_wedge_bits_lookup(bsize)); + const int wedge_types = get_wedge_types_lookup(bsize); int wedge_index = wedge_types / 2; const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize); @@ -563,7 +557,7 @@ TEST_P(AV1HighbdCompMaskUpVarianceTest, DISABLED_Speed) { } #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1HighbdCompMaskUpVarianceTest, ::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_avx2), ::testing::ValuesIn(kValidBlockSize), @@ -571,7 +565,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AV1HighbdCompMaskUpVarianceTest, ::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_sse2), ::testing::ValuesIn(kValidBlockSize), diff --git a/media/libaom/src/test/convolve_round_test.cc b/media/libaom/src/test/convolve_round_test.cc index 2f801e7d46..4f17b54728 100644 --- a/media/libaom/src/test/convolve_round_test.cc +++ b/media/libaom/src/test/convolve_round_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include "config/av1_rtcd.h" @@ -52,7 +53,7 @@ void highbd_convolve_rounding_12(CONVOLVE_ROUNDING_PARAM) { typedef enum { LOWBITDEPTH_TEST, HIGHBITDEPTH_TEST } DataPathType; -using ::testing::tuple; +using std::tuple; typedef tuple ConvolveRoundParam; @@ -162,7 +163,7 @@ class ConvolveRoundTest : public ::testing::TestWithParam { TEST_P(ConvolveRoundTest, BitExactCheck) { ConvolveRoundingRun(); } -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_AVX2 const ConvolveRoundParam kConvRndParamArray[] = { make_tuple(&av1_convolve_rounding_c, &av1_convolve_rounding_avx2, @@ -177,7 +178,7 @@ const ConvolveRoundParam kConvRndParamArray[] = { &highbd_convolve_rounding_12, HIGHBITDEPTH_TEST) }; -INSTANTIATE_TEST_CASE_P(AVX2, ConvolveRoundTest, - ::testing::ValuesIn(kConvRndParamArray)); +INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveRoundTest, + ::testing::ValuesIn(kConvRndParamArray)); #endif // HAVE_AVX2 } // namespace diff --git a/media/libaom/src/test/convolve_test.cc b/media/libaom/src/test/convolve_test.cc index 2960735a18..0b1eea16a5 100644 --- a/media/libaom/src/test/convolve_test.cc +++ b/media/libaom/src/test/convolve_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -47,7 +48,7 @@ struct ConvolveFunctions { int use_highbd_; // 0 if high bitdepth not used, else the actual bit depth. }; -typedef ::testing::tuple ConvolveParam; +typedef std::tuple ConvolveParam; #define ALL_SIZES_64(convolve_fn) \ make_tuple(4, 4, &convolve_fn), make_tuple(8, 4, &convolve_fn), \ @@ -748,7 +749,7 @@ TEST_P(ConvolveTest, DISABLED_Speed) { UUT_->use_highbd_, elapsed_time); } -using ::testing::make_tuple; +using std::make_tuple; // WRAP macro is only used for high bitdepth build. #if CONFIG_AV1_HIGHBITDEPTH @@ -818,7 +819,8 @@ const ConvolveFunctions convolve8_c(aom_convolve_copy_c, aom_convolve8_horiz_c, const ConvolveParam kArrayConvolve_c[] = { ALL_SIZES(convolve8_c) }; #endif -INSTANTIATE_TEST_CASE_P(C, ConvolveTest, ::testing::ValuesIn(kArrayConvolve_c)); +INSTANTIATE_TEST_SUITE_P(C, ConvolveTest, + ::testing::ValuesIn(kArrayConvolve_c)); #if HAVE_SSE2 && ARCH_X86_64 #if CONFIG_AV1_HIGHBITDEPTH @@ -840,8 +842,8 @@ const ConvolveFunctions convolve8_sse2(aom_convolve_copy_c, aom_convolve8_vert_sse2, 0); const ConvolveParam kArrayConvolve_sse2[] = { ALL_SIZES(convolve8_sse2) }; #endif -INSTANTIATE_TEST_CASE_P(SSE2, ConvolveTest, - ::testing::ValuesIn(kArrayConvolve_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, ConvolveTest, + ::testing::ValuesIn(kArrayConvolve_sse2)); #endif #if HAVE_SSSE3 @@ -850,8 +852,8 @@ const ConvolveFunctions convolve8_ssse3(aom_convolve_copy_c, aom_convolve8_vert_ssse3, 0); const ConvolveParam kArrayConvolve8_ssse3[] = { ALL_SIZES(convolve8_ssse3) }; -INSTANTIATE_TEST_CASE_P(SSSE3, ConvolveTest, - ::testing::ValuesIn(kArrayConvolve8_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, ConvolveTest, + ::testing::ValuesIn(kArrayConvolve8_ssse3)); #endif #if HAVE_AVX2 @@ -876,8 +878,8 @@ const ConvolveFunctions convolve8_avx2(aom_convolve_copy_c, const ConvolveParam kArray_Convolve8_avx2[] = { ALL_SIZES(convolve8_avx2) }; #endif -INSTANTIATE_TEST_CASE_P(AVX2, ConvolveTest, - ::testing::ValuesIn(kArray_Convolve8_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveTest, + ::testing::ValuesIn(kArray_Convolve8_avx2)); #endif // HAVE_AVX2 } // namespace diff --git a/media/libaom/src/test/corner_match_test.cc b/media/libaom/src/test/corner_match_test.cc index 584cea3305..c685dca80c 100644 --- a/media/libaom/src/test/corner_match_test.cc +++ b/media/libaom/src/test/corner_match_test.cc @@ -8,6 +8,8 @@ * 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/av1_rtcd.h" #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -28,8 +30,8 @@ typedef double (*ComputeCrossCorrFunc)(unsigned char *im1, int stride1, int x1, int y1, unsigned char *im2, int stride2, int x2, int y2); -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; typedef tuple CornerMatchParam; class AV1CornerMatchTest : public ::testing::TestWithParam { @@ -125,14 +127,14 @@ TEST_P(AV1CornerMatchTest, CheckOutput) { RunCheckOutput(1); } TEST_P(AV1CornerMatchTest, DISABLED_Speed) { RunCheckOutput(100000); } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1CornerMatchTest, ::testing::Values(make_tuple(0, &av1_compute_cross_correlation_sse4_1), make_tuple(1, &av1_compute_cross_correlation_sse4_1))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1CornerMatchTest, ::testing::Values(make_tuple(0, &av1_compute_cross_correlation_avx2), make_tuple(1, &av1_compute_cross_correlation_avx2))); diff --git a/media/libaom/src/test/datarate_test.cc b/media/libaom/src/test/datarate_test.cc index fc5f397be6..053c055716 100644 --- a/media/libaom/src/test/datarate_test.cc +++ b/media/libaom/src/test/datarate_test.cc @@ -84,6 +84,30 @@ class DatarateTestLarge << " The datarate for the file is greater than target by too much!"; } + virtual void BasicRateTargetingCBRPeriodicKeyFrameTest() { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_dropframe_thresh = 1; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 63; + cfg_.rc_end_usage = AOM_CBR; + cfg_.g_lag_in_frames = 0; + // Periodic keyframe + cfg_.kf_max_dist = 50; + + ::libaom_test::I420VideoSource video("pixel_capture_w320h240.yuv", 320, 240, + 30, 1, 0, 310); + const int bitrate_array[2] = { 150, 550 }; + cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)]; + ResetModel(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85) + << " The datarate for the file is lower than target by too much!"; + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15) + << " The datarate for the file is greater than target by too much!"; + } + virtual void BasicRateTargetingAQModeOnOffCBRTest() { if (GET_PARAM(4) > 0) return; cfg_.rc_buf_initial_sz = 500; @@ -137,6 +161,27 @@ class DatarateTestLarge << " The datarate for the file missed the target!" << cfg_.rc_target_bitrate << " " << effective_datarate_; } +}; + +// Params: test mode, speed, aq mode. +class DatarateTestFrameDropLarge + : public ::libaom_test::CodecTestWith3Params, + public DatarateTest { + public: + DatarateTestFrameDropLarge() : DatarateTest(GET_PARAM(0)) { + set_cpu_used_ = GET_PARAM(2); + aq_mode_ = GET_PARAM(3); + } + + protected: + virtual ~DatarateTestFrameDropLarge() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(GET_PARAM(1)); + ResetModel(); + } virtual void ChangingDropFrameThreshTest() { cfg_.rc_buf_initial_sz = 500; @@ -167,7 +212,7 @@ class DatarateTestLarge ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85) << " The datarate for the file is lower than target by too much!"; - ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.16) + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.17) << " The datarate for the file is greater than target by too much!"; if (last_drop > 0) { ASSERT_LE(first_drop_, last_drop) @@ -190,11 +235,16 @@ TEST_P(DatarateTestLarge, BasicRateTargetingVBR) { BasicRateTargetingVBRTest(); } -// Check basic rate targeting for CBR, +// Check basic rate targeting for CBR. TEST_P(DatarateTestLarge, BasicRateTargetingCBR) { BasicRateTargetingCBRTest(); } +// Check basic rate targeting for periodic key frame. +TEST_P(DatarateTestLarge, PeriodicKeyFrameCBR) { + BasicRateTargetingCBRPeriodicKeyFrameTest(); +} + // Check basic rate targeting for CBR. TEST_P(DatarateTestLarge, BasicRateTargeting444CBR) { BasicRateTargeting444CBRTest(); @@ -204,7 +254,7 @@ TEST_P(DatarateTestLarge, BasicRateTargeting444CBR) { // as the drop frame threshold is increased, and (2) that the total number of // frame drops does not decrease as we increase frame drop threshold. // Use a lower qp-max to force some frame drops. -TEST_P(DatarateTestLarge, ChangingDropFrameThresh) { +TEST_P(DatarateTestFrameDropLarge, ChangingDropFrameThresh) { ChangingDropFrameThreshTest(); } @@ -214,16 +264,72 @@ TEST_P(DatarateTestLarge, BasicRateTargetingAQModeOnOffCBR) { class DatarateTestRealtime : public DatarateTestLarge {}; +class DatarateTestFrameDropRealtime : public DatarateTestFrameDropLarge {}; + +// Params: aq mode. +class DatarateTestSpeedChangeRealtime + : public ::libaom_test::CodecTestWith2Params, + public DatarateTest { + public: + DatarateTestSpeedChangeRealtime() : DatarateTest(GET_PARAM(0)) { + aq_mode_ = GET_PARAM(1); + speed_change_test_ = true; + } + + protected: + virtual ~DatarateTestSpeedChangeRealtime() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(GET_PARAM(1)); + ResetModel(); + } + + virtual void ChangingSpeedTest() { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_undershoot_pct = 20; + cfg_.rc_undershoot_pct = 20; + cfg_.rc_dropframe_thresh = 10; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 50; + cfg_.rc_end_usage = AOM_CBR; + cfg_.rc_target_bitrate = 200; + cfg_.g_lag_in_frames = 0; + cfg_.g_error_resilient = 1; + // TODO(marpan): Investigate datarate target failures with a smaller + // keyframe interval (128). + cfg_.kf_max_dist = 9999; + cfg_.rc_dropframe_thresh = 0; + ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, + 288, 30, 1, 0, 100); + + ResetModel(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.83) + << " The datarate for the file is lower than target by too much!"; + ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.20) + << " The datarate for the file is greater than target by too much!"; + } +}; + // Check basic rate targeting for VBR mode. TEST_P(DatarateTestRealtime, BasicRateTargetingVBR) { BasicRateTargetingVBRTest(); } -// Check basic rate targeting for CBR, +// Check basic rate targeting for CBR. TEST_P(DatarateTestRealtime, BasicRateTargetingCBR) { BasicRateTargetingCBRTest(); } +// Check basic rate targeting for periodic key frame. +TEST_P(DatarateTestRealtime, PeriodicKeyFrameCBR) { + BasicRateTargetingCBRPeriodicKeyFrameTest(); +} + // Check basic rate targeting for CBR. TEST_P(DatarateTestRealtime, BasicRateTargeting444CBR) { BasicRateTargeting444CBRTest(); @@ -233,19 +339,35 @@ TEST_P(DatarateTestRealtime, BasicRateTargeting444CBR) { // as the drop frame threshold is increased, and (2) that the total number of // frame drops does not decrease as we increase frame drop threshold. // Use a lower qp-max to force some frame drops. -TEST_P(DatarateTestRealtime, ChangingDropFrameThresh) { +TEST_P(DatarateTestFrameDropRealtime, ChangingDropFrameThresh) { ChangingDropFrameThreshTest(); } +TEST_P(DatarateTestSpeedChangeRealtime, ChangingSpeedTest) { + ChangingSpeedTest(); +} + AV1_INSTANTIATE_TEST_CASE(DatarateTestLarge, ::testing::Values(::libaom_test::kRealTime), ::testing::Range(5, 7), ::testing::Values(0, 3), ::testing::Values(0, 1)); +AV1_INSTANTIATE_TEST_CASE(DatarateTestFrameDropLarge, + ::testing::Values(::libaom_test::kRealTime), + ::testing::Range(5, 7), ::testing::Values(0, 3)); + AV1_INSTANTIATE_TEST_CASE(DatarateTestRealtime, ::testing::Values(::libaom_test::kRealTime), ::testing::Range(7, 9), ::testing::Values(0, 3), ::testing::Values(0, 1)); +AV1_INSTANTIATE_TEST_CASE(DatarateTestFrameDropRealtime, + ::testing::Values(::libaom_test::kRealTime), + ::testing::Range(7, 9), ::testing::Values(0, 3)); + +AV1_INSTANTIATE_TEST_CASE(DatarateTestSpeedChangeRealtime, + ::testing::Values(::libaom_test::kRealTime), + ::testing::Values(0, 3)); + } // namespace } // namespace datarate_test diff --git a/media/libaom/src/test/datarate_test.h b/media/libaom/src/test/datarate_test.h index 388915fff5..3c15731195 100644 --- a/media/libaom/src/test/datarate_test.h +++ b/media/libaom/src/test/datarate_test.h @@ -24,7 +24,8 @@ namespace { class DatarateTest : public ::libaom_test::EncoderTest { public: explicit DatarateTest(const ::libaom_test::CodecFactory *codec) - : EncoderTest(codec) {} + : EncoderTest(codec), set_cpu_used_(0), aq_mode_(0), + speed_change_test_(false) {} protected: virtual ~DatarateTest() {} @@ -64,6 +65,21 @@ class DatarateTest : public ::libaom_test::EncoderTest { } } + if (speed_change_test_) { + if (video->frame() == 0) { + encoder->Control(AOME_SET_CPUUSED, 8); + } + if (video->frame() == 30) { + encoder->Control(AOME_SET_CPUUSED, 7); + } + if (video->frame() == 60) { + encoder->Control(AOME_SET_CPUUSED, 6); + } + if (video->frame() == 90) { + encoder->Control(AOME_SET_CPUUSED, 7); + } + } + if (denoiser_offon_test_) { ASSERT_GT(denoiser_offon_period_, 0) << "denoiser_offon_period_ is not positive."; @@ -134,6 +150,7 @@ class DatarateTest : public ::libaom_test::EncoderTest { int denoiser_offon_test_; int denoiser_offon_period_; unsigned int aq_mode_; + bool speed_change_test_; }; } // namespace diff --git a/media/libaom/src/test/decode_api_test.cc b/media/libaom/src/test/decode_api_test.cc index c1beacee17..910640df75 100644 --- a/media/libaom/src/test/decode_api_test.cc +++ b/media/libaom/src/test/decode_api_test.cc @@ -33,19 +33,19 @@ TEST(DecodeAPI, InvalidParams) { EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(NULL, NULL, 0, NULL)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(NULL, buf, 0, NULL)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_decode(NULL, buf, NELEMENTS(buf), NULL)); + aom_codec_decode(NULL, buf, sizeof(buf), NULL)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_decode(NULL, NULL, NELEMENTS(buf), NULL)); + aom_codec_decode(NULL, NULL, sizeof(buf), NULL)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_destroy(NULL)); EXPECT_TRUE(aom_codec_error(NULL) != NULL); - for (int i = 0; i < NELEMENTS(kCodecs); ++i) { + for (const aom_codec_iface_t *iface : kCodecs) { EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_dec_init(NULL, kCodecs[i], NULL, 0)); + aom_codec_dec_init(NULL, iface, NULL, 0)); - EXPECT_EQ(AOM_CODEC_OK, aom_codec_dec_init(&dec, kCodecs[i], NULL, 0)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_dec_init(&dec, iface, NULL, 0)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_decode(&dec, NULL, NELEMENTS(buf), NULL)); + aom_codec_decode(&dec, NULL, sizeof(buf), NULL)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(&dec, buf, 0, NULL)); EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&dec)); diff --git a/media/libaom/src/test/decode_perf_test.cc b/media/libaom/src/test/decode_perf_test.cc index 2f67342570..691337cd6f 100644 --- a/media/libaom/src/test/decode_perf_test.cc +++ b/media/libaom/src/test/decode_perf_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include "config/aom_version.h" @@ -24,7 +25,7 @@ #include "test/util.h" #include "test/webm_video_source.h" -using ::testing::make_tuple; +using std::make_tuple; namespace { @@ -37,7 +38,7 @@ const char kNewEncodeOutputFile[] = "new_encode.ivf"; /* DecodePerfTest takes a tuple of filename + number of threads to decode with */ -typedef ::testing::tuple DecodePerfParam; +typedef std::tuple DecodePerfParam; // TODO(jimbankoski): Add actual test vectors here when available. // const DecodePerfParam kAV1DecodePerfVectors[] = {}; @@ -91,7 +92,7 @@ TEST_P(DecodePerfTest, PerfTest) { } // TODO(jimbankoski): Enabled when we have actual AV1 Decode vectors. -// INSTANTIATE_TEST_CASE_P(AV1, DecodePerfTest, +// INSTANTIATE_TEST_SUITE_P(AV1, DecodePerfTest, // ::testing::ValuesIn(kAV1DecodePerfVectors)); class AV1NewEncodeDecodePerfTest diff --git a/media/libaom/src/test/decode_test_driver.h b/media/libaom/src/test/decode_test_driver.h index d13e13ea1f..64722f43a7 100644 --- a/media/libaom/src/test/decode_test_driver.h +++ b/media/libaom/src/test/decode_test_driver.h @@ -67,13 +67,13 @@ class Decoder { void Control(int ctrl_id, const void *arg) { InitOnce(); - const aom_codec_err_t res = aom_codec_control_(&decoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&decoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << DecodeError(); } void Control(int ctrl_id, int arg, aom_codec_err_t expected_value) { InitOnce(); - const aom_codec_err_t res = aom_codec_control_(&decoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&decoder_, ctrl_id, arg); ASSERT_EQ(expected_value, res) << DecodeError(); } diff --git a/media/libaom/src/test/divu_small_test.cc b/media/libaom/src/test/divu_small_test.cc index 064f8ee454..f4d0846cf4 100644 --- a/media/libaom/src/test/divu_small_test.cc +++ b/media/libaom/src/test/divu_small_test.cc @@ -18,7 +18,7 @@ using libaom_test::ACMRandom; -TEST(Daala, TestDIVUuptoMAX) { +TEST(DivuSmallTest, TestDIVUuptoMAX) { for (int d = 1; d <= OD_DIVU_DMAX; d++) { for (uint32_t x = 1; x <= 1000000; x++) { GTEST_ASSERT_EQ(x / d, OD_DIVU_SMALL(x, d)) @@ -28,7 +28,7 @@ TEST(Daala, TestDIVUuptoMAX) { } } -TEST(Daala, TestDIVUrandI31) { +TEST(DivuSmallTest, TestDIVUrandI31) { ACMRandom rnd(ACMRandom::DeterministicSeed()); for (int d = 1; d < OD_DIVU_DMAX; d++) { for (int i = 0; i < 1000000; i++) { diff --git a/media/libaom/src/test/dr_prediction_test.cc b/media/libaom/src/test/dr_prediction_test.cc index 59937e7179..e8865c02a3 100644 --- a/media/libaom/src/test/dr_prediction_test.cc +++ b/media/libaom/src/test/dr_prediction_test.cc @@ -8,6 +8,9 @@ * 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 "config/aom_config.h" @@ -314,9 +317,9 @@ TEST_P(LowbdDrPredTest, SaturatedValues) { } } -using ::testing::make_tuple; +using std::make_tuple; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, LowbdDrPredTest, ::testing::Values(DrPredFunc(&z1_wrapper, NULL, AOM_BITS_8, kZ1Start), @@ -338,7 +341,7 @@ TEST_P(HighbdDrPredTest, SaturatedValues) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, HighbdDrPredTest, ::testing::Values( DrPredFunc(&z1_wrapper_hbd, @@ -362,7 +365,7 @@ INSTANTIATE_TEST_CASE_P( #endif // CONFIG_AV1_HIGHBITDEPTH #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, LowbdDrPredTest, ::testing::Values(DrPredFunc(&z1_wrapper, &z1_wrapper, @@ -401,7 +404,7 @@ TEST_P(LowbdDrPredTest, OperationCheck) { } #if CONFIG_AV1_HIGHBITDEPTH -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, HighbdDrPredTest, ::testing::Values(DrPredFunc( &z1_wrapper_hbd, diff --git a/media/libaom/src/test/edge_detect_test.cc b/media/libaom/src/test/edge_detect_test.cc index b09ed7d95b..33fbbc0bb0 100644 --- a/media/libaom/src/test/edge_detect_test.cc +++ b/media/libaom/src/test/edge_detect_test.cc @@ -11,6 +11,7 @@ #include #include +#include #include "aom_mem/aom_mem.h" #include "av1/encoder/rdopt.h" #include "test/util.h" @@ -18,8 +19,8 @@ namespace { -using ::testing::get; -using ::testing::tuple; +using std::get; +using std::tuple; static int get_pix(uint8_t *buf, int i, bool high_bd) { if (high_bd) { @@ -217,35 +218,35 @@ TEST_P(EdgeDetectBrightnessTest, DetectUniformBrightness) { } #if CONFIG_AV1_HIGHBITDEPTH -INSTANTIATE_TEST_CASE_P(ImageBrightnessTests, EdgeDetectBrightnessTest, - ::testing::Combine( - // Brightness - ::testing::Values(0, 1, 2, 127, 128, 129, 254, 255, - 256, 511, 512, 1023, 1024, 2048, - 4095), - // Width - ::testing::Values(8, 16, 32), - // Height - ::testing::Values(4, 8, 12, 32), - // High bit depth representation - ::testing::Bool(), - // Bit depth - ::testing::Values(8, 10, 12))); +INSTANTIATE_TEST_SUITE_P(ImageBrightnessTests, EdgeDetectBrightnessTest, + ::testing::Combine( + // Brightness + ::testing::Values(0, 1, 2, 127, 128, 129, 254, 255, + 256, 511, 512, 1023, 1024, 2048, + 4095), + // Width + ::testing::Values(8, 16, 32), + // Height + ::testing::Values(4, 8, 12, 32), + // High bit depth representation + ::testing::Bool(), + // Bit depth + ::testing::Values(8, 10, 12))); #else -INSTANTIATE_TEST_CASE_P(ImageBrightnessTests, EdgeDetectBrightnessTest, - ::testing::Combine( - // Brightness - ::testing::Values(0, 1, 2, 127, 128, 129, 254, 255, - 256, 511, 512, 1023, 1024, 2048, - 4095), - // Width - ::testing::Values(8, 16, 32), - // Height - ::testing::Values(4, 8, 12, 32), - // High bit depth representation - ::testing::Values(false), - // Bit depth - ::testing::Values(8))); +INSTANTIATE_TEST_SUITE_P(ImageBrightnessTests, EdgeDetectBrightnessTest, + ::testing::Combine( + // Brightness + ::testing::Values(0, 1, 2, 127, 128, 129, 254, 255, + 256, 511, 512, 1023, 1024, 2048, + 4095), + // Width + ::testing::Values(8, 16, 32), + // Height + ::testing::Values(4, 8, 12, 32), + // High bit depth representation + ::testing::Values(false), + // Bit depth + ::testing::Values(8))); #endif class EdgeDetectImageTest : @@ -383,26 +384,26 @@ TEST(EdgeDetectImageTest, SobelTest) { } #if CONFIG_AV1_HIGHBITDEPTH -INSTANTIATE_TEST_CASE_P(EdgeDetectImages, EdgeDetectImageTest, - ::testing::Combine( - // Width - ::testing::Values(8, 16, 32), - // Height - ::testing::Values(4, 8, 12, 32), - // High bit depth representation - ::testing::Bool(), - // Bit depth - ::testing::Values(8, 10, 12))); +INSTANTIATE_TEST_SUITE_P(EdgeDetectImages, EdgeDetectImageTest, + ::testing::Combine( + // Width + ::testing::Values(8, 16, 32), + // Height + ::testing::Values(4, 8, 12, 32), + // High bit depth representation + ::testing::Bool(), + // Bit depth + ::testing::Values(8, 10, 12))); #else -INSTANTIATE_TEST_CASE_P(EdgeDetectImages, EdgeDetectImageTest, - ::testing::Combine( - // Width - ::testing::Values(8, 16, 32), - // Height - ::testing::Values(4, 8, 12, 32), - // High bit depth representation - ::testing::Values(false), - // Bit depth - ::testing::Values(8))); +INSTANTIATE_TEST_SUITE_P(EdgeDetectImages, EdgeDetectImageTest, + ::testing::Combine( + // Width + ::testing::Values(8, 16, 32), + // Height + ::testing::Values(4, 8, 12, 32), + // High bit depth representation + ::testing::Values(false), + // Bit depth + ::testing::Values(8))); #endif } // namespace diff --git a/media/libaom/src/test/encode_api_test.cc b/media/libaom/src/test/encode_api_test.cc index 235480a13c..25bdb5c3f3 100644 --- a/media/libaom/src/test/encode_api_test.cc +++ b/media/libaom/src/test/encode_api_test.cc @@ -43,17 +43,17 @@ TEST(EncodeAPI, InvalidParams) { aom_codec_enc_config_default(NULL, &cfg, 0)); EXPECT_TRUE(aom_codec_error(NULL) != NULL); - for (int i = 0; i < NELEMENTS(kCodecs); ++i) { - SCOPED_TRACE(aom_codec_iface_name(kCodecs[i])); + for (const aom_codec_iface_t *iface : kCodecs) { + SCOPED_TRACE(aom_codec_iface_name(iface)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_enc_init(NULL, kCodecs[i], NULL, 0)); + aom_codec_enc_init(NULL, iface, NULL, 0)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_enc_init(&enc, kCodecs[i], NULL, 0)); + aom_codec_enc_init(&enc, iface, NULL, 0)); EXPECT_EQ(AOM_CODEC_INVALID_PARAM, - aom_codec_enc_config_default(kCodecs[i], &cfg, 2)); + aom_codec_enc_config_default(iface, &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)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, 0)); + EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); EXPECT_EQ(NULL, aom_codec_get_global_headers(NULL)); diff --git a/media/libaom/src/test/encode_perf_test.cc b/media/libaom/src/test/encode_perf_test.cc index fe649b1539..390a6e0e62 100644 --- a/media/libaom/src/test/encode_perf_test.cc +++ b/media/libaom/src/test/encode_perf_test.cc @@ -123,32 +123,29 @@ class AV1EncodePerfTest }; TEST_P(AV1EncodePerfTest, PerfTest) { - for (size_t i = 0; i < NELEMENTS(kAV1EncodePerfTestVectors); ++i) { - for (size_t j = 0; j < NELEMENTS(kEncodePerfTestSpeeds); ++j) { - for (size_t k = 0; k < NELEMENTS(kEncodePerfTestThreads); ++k) { - if (kAV1EncodePerfTestVectors[i].width < 512 && - kEncodePerfTestThreads[k] > 1) + for (const EncodePerfTestVideo &test_video : kAV1EncodePerfTestVectors) { + for (int speed : kEncodePerfTestSpeeds) { + for (int threads : kEncodePerfTestThreads) { + if (test_video.width < 512 && threads > 1) continue; - else if (kAV1EncodePerfTestVectors[i].width < 1024 && - kEncodePerfTestThreads[k] > 2) + else if (test_video.width < 1024 && threads > 2) continue; - set_threads(kEncodePerfTestThreads[k]); + set_threads(threads); SetUp(); const aom_rational timebase = { 33333333, 1000000000 }; cfg_.g_timebase = timebase; - cfg_.rc_target_bitrate = kAV1EncodePerfTestVectors[i].bitrate; + cfg_.rc_target_bitrate = test_video.bitrate; init_flags_ = AOM_CODEC_USE_PSNR; - const unsigned frames = kAV1EncodePerfTestVectors[i].frames; - const char *video_name = kAV1EncodePerfTestVectors[i].name; - libaom_test::I420VideoSource video( - video_name, kAV1EncodePerfTestVectors[i].width, - kAV1EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0, - kAV1EncodePerfTestVectors[i].frames); - set_speed(kEncodePerfTestSpeeds[j]); + const unsigned frames = test_video.frames; + const char *video_name = test_video.name; + libaom_test::I420VideoSource video(video_name, test_video.width, + test_video.height, timebase.den, + timebase.num, 0, test_video.frames); + set_speed(speed); aom_usec_timer t; aom_usec_timer_start(&t); @@ -160,10 +157,9 @@ TEST_P(AV1EncodePerfTest, PerfTest) { const double fps = frames / elapsed_secs; const double minimum_psnr = min_psnr(); std::string display_name(video_name); - if (kEncodePerfTestThreads[k] > 1) { + if (threads > 1) { char thread_count[32]; - snprintf(thread_count, sizeof(thread_count), "_t-%d", - kEncodePerfTestThreads[k]); + snprintf(thread_count, sizeof(thread_count), "_t-%d", threads); display_name += thread_count; } @@ -175,8 +171,8 @@ TEST_P(AV1EncodePerfTest, PerfTest) { printf("\t\"totalFrames\" : %u,\n", frames); printf("\t\"framesPerSecond\" : %f,\n", fps); printf("\t\"minPsnr\" : %f,\n", minimum_psnr); - printf("\t\"speed\" : %d,\n", kEncodePerfTestSpeeds[j]); - printf("\t\"threads\" : %d\n", kEncodePerfTestThreads[k]); + printf("\t\"speed\" : %d,\n", speed); + printf("\t\"threads\" : %d\n", threads); printf("}\n"); } } diff --git a/media/libaom/src/test/encode_test_driver.h b/media/libaom/src/test/encode_test_driver.h index cce8653d00..6319a52202 100644 --- a/media/libaom/src/test/encode_test_driver.h +++ b/media/libaom/src/test/encode_test_driver.h @@ -105,38 +105,38 @@ class Encoder { void EncodeFrame(VideoSource *video) { EncodeFrame(video, 0); } void Control(int ctrl_id, int arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } void Control(int ctrl_id, int *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } void Control(int ctrl_id, struct aom_scaling_mode *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } void Control(int ctrl_id, struct aom_svc_layer_id *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } void Control(int ctrl_id, struct aom_svc_ref_frame_config *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } void Control(int ctrl_id, struct aom_svc_params *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } #if CONFIG_AV1_ENCODER void Control(int ctrl_id, aom_active_map_t *arg) { - const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg); + const aom_codec_err_t res = aom_codec_control(&encoder_, ctrl_id, arg); ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError(); } #endif diff --git a/media/libaom/src/test/encodetxb_test.cc b/media/libaom/src/test/encodetxb_test.cc index 3751251bdd..385d3f1a8b 100644 --- a/media/libaom/src/test/encodetxb_test.cc +++ b/media/libaom/src/test/encodetxb_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -20,8 +21,8 @@ #include "aom_ports/aom_timer.h" #include "aom_ports/mem.h" +#include "av1/common/av1_common_int.h" #include "av1/common/idct.h" -#include "av1/common/onyxc_int.h" #include "av1/common/scan.h" #include "av1/common/txb_common.h" #include "test/acm_random.h" @@ -177,15 +178,15 @@ TEST_P(EncodeTxbTest, DISABLED_SpeedTestGetNzMapContexts) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, EncodeTxbTest, - ::testing::Values(av1_get_nz_map_contexts_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, EncodeTxbTest, + ::testing::Values(av1_get_nz_map_contexts_sse2)); #endif typedef void (*av1_txb_init_levels_func)(const tran_low_t *const coeff, const int width, const int height, uint8_t *const levels); -typedef ::testing::tuple TxbInitLevelParam; +typedef std::tuple TxbInitLevelParam; class EncodeTxbInitLevelTest : public ::testing::TestWithParam { @@ -248,13 +249,13 @@ TEST_P(EncodeTxbInitLevelTest, DISABLED_Speed) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, EncodeTxbInitLevelTest, ::testing::Combine(::testing::Values(&av1_txb_init_levels_sse4_1), ::testing::Range(0, static_cast(TX_SIZES_ALL), 1))); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, EncodeTxbInitLevelTest, ::testing::Combine(::testing::Values(&av1_txb_init_levels_avx2), ::testing::Range(0, static_cast(TX_SIZES_ALL), 1))); diff --git a/media/libaom/src/test/end_to_end_test.cc b/media/libaom/src/test/end_to_end_test.cc index 13d349ff8f..162a7c7437 100644 --- a/media/libaom/src/test/end_to_end_test.cc +++ b/media/libaom/src/test/end_to_end_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -57,7 +58,7 @@ 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 << "}"; + << " profile:" << test_arg.profile << " }"; } const TestVideoParam kTestVectors[] = { diff --git a/media/libaom/src/test/error_block_test.cc b/media/libaom/src/test/error_block_test.cc index 7365907b97..462661e61a 100644 --- a/media/libaom/src/test/error_block_test.cc +++ b/media/libaom/src/test/error_block_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -39,7 +40,7 @@ typedef int64_t (*ErrorBlockFunc8Bits)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz); -typedef ::testing::tuple +typedef std::tuple ErrorBlockParam; template @@ -232,7 +233,7 @@ TEST_P(ErrorBlockTest, DISABLED_Speed) { } } -using ::testing::make_tuple; +using std::make_tuple; #if (HAVE_SSE2) const ErrorBlockParam kErrorBlockTestParamsSse2[] = { @@ -248,8 +249,8 @@ const ErrorBlockParam kErrorBlockTestParamsSse2[] = { &BlockError8BitWrapper, AOM_BITS_8) }; -INSTANTIATE_TEST_CASE_P(SSE2, ErrorBlockTest, - ::testing::ValuesIn(kErrorBlockTestParamsSse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, ErrorBlockTest, + ::testing::ValuesIn(kErrorBlockTestParamsSse2)); #endif // HAVE_SSE2 #if (HAVE_AVX2) @@ -266,12 +267,12 @@ const ErrorBlockParam kErrorBlockTestParamsAvx2[] = { &BlockError8BitWrapper, AOM_BITS_8) }; -INSTANTIATE_TEST_CASE_P(AVX2, ErrorBlockTest, - ::testing::ValuesIn(kErrorBlockTestParamsAvx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, ErrorBlockTest, + ::testing::ValuesIn(kErrorBlockTestParamsAvx2)); #endif // HAVE_AVX2 #if (HAVE_MSA) -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MSA, ErrorBlockTest, ::testing::Values(make_tuple(&BlockError8BitWrapper, &BlockError8BitWrapper, @@ -279,7 +280,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_MSA #if (HAVE_NEON) -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, ErrorBlockTest, ::testing::Values(make_tuple(&BlockError8BitWrapper, &BlockError8BitWrapper, diff --git a/media/libaom/src/test/fdct4x4_test.cc b/media/libaom/src/test/fdct4x4_test.cc new file mode 100644 index 0000000000..6600f2c466 --- /dev/null +++ b/media/libaom/src/test/fdct4x4_test.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020, 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 "aom_dsp/aom_dsp_common.h" +#include "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "config/av1_rtcd.h" +#include "config/aom_dsp_rtcd.h" +#include "test/acm_random.h" +#include "test/clear_system_state.h" +#include "test/register_state_check.h" +#include "test/transform_test_base.h" +#include "test/util.h" +#include "av1/common/entropy.h" +#include "aom/aom_codec.h" +#include "aom/aom_integer.h" +#include "aom_ports/mem.h" + +using libaom_test::ACMRandom; + +namespace { + +template +using FdctFunc = void (*)(const int16_t *in, OutputType *out, int stride); + +template +using FhtFunc = void (*)(const int16_t *in, OutputType *out, int stride, + TxfmParam *txfm_param); + +template +using Fdct4x4Param = + std::tuple, FhtFunc, aom_bit_depth_t, int>; + +#if HAVE_NEON || HAVE_SSE2 +void fdct4x4_ref(const int16_t *in, tran_low_t *out, int stride, + TxfmParam * /*txfm_param*/) { + aom_fdct4x4_c(in, out, stride); +} + +void fdct4x4_lp_ref(const int16_t *in, int16_t *out, int stride, + TxfmParam * /*txfm_param*/) { + aom_fdct4x4_lp_c(in, out, stride); +} +#endif + +template +class Trans4x4FDCT : public libaom_test::TransformTestBase, + public ::testing::TestWithParam> { + public: + virtual ~Trans4x4FDCT() {} + + using TxfmBaseOutType = libaom_test::TransformTestBase; + virtual void SetUp() { + fwd_txfm_ = std::get<0>(this->GetParam()); + TxfmBaseOutType::pitch_ = 4; + TxfmBaseOutType::height_ = 4; + TxfmBaseOutType::fwd_txfm_ref = std::get<1>(this->GetParam()); + TxfmBaseOutType::bit_depth_ = std::get<2>(this->GetParam()); + TxfmBaseOutType::mask_ = (1 << TxfmBaseOutType::bit_depth_) - 1; + TxfmBaseOutType::num_coeffs_ = std::get<3>(this->GetParam()); + } + virtual void TearDown() { libaom_test::ClearSystemState(); } + + protected: + void RunFwdTxfm(const int16_t *in, OutputType *out, int stride) { + fwd_txfm_(in, out, stride); + } + + void RunInvTxfm(const OutputType *out, uint8_t *dst, int stride) { + (void)out; + (void)dst; + (void)stride; + } + + FdctFunc fwd_txfm_; +}; + +using Trans4x4FDCTTranLow = Trans4x4FDCT; +TEST_P(Trans4x4FDCTTranLow, CoeffCheck) { RunCoeffCheck(); } +TEST_P(Trans4x4FDCTTranLow, MemCheck) { RunMemCheck(); } + +using Trans4x4FDCTInt16 = Trans4x4FDCT; +TEST_P(Trans4x4FDCTInt16, CoeffCheck) { RunCoeffCheck(); } +TEST_P(Trans4x4FDCTInt16, MemCheck) { RunMemCheck(); } + +using std::make_tuple; + +#if HAVE_NEON +INSTANTIATE_TEST_SUITE_P(NEON, Trans4x4FDCTTranLow, + ::testing::Values(make_tuple(&aom_fdct4x4_neon, + &fdct4x4_ref, AOM_BITS_8, + 16))); + +INSTANTIATE_TEST_SUITE_P(NEON, Trans4x4FDCTInt16, + ::testing::Values(make_tuple(&aom_fdct4x4_lp_neon, + &fdct4x4_lp_ref, + AOM_BITS_8, 16))); +#endif + +#if HAVE_SSE2 +INSTANTIATE_TEST_SUITE_P(SSE2, Trans4x4FDCTTranLow, + ::testing::Values(make_tuple(&aom_fdct4x4_sse2, + &fdct4x4_ref, AOM_BITS_8, + 16))); + +INSTANTIATE_TEST_SUITE_P(SSE2, Trans4x4FDCTInt16, + ::testing::Values(make_tuple(&aom_fdct4x4_lp_sse2, + &fdct4x4_lp_ref, + AOM_BITS_8, 16))); +#endif +} // namespace diff --git a/media/libaom/src/test/fft_test.cc b/media/libaom/src/test/fft_test.cc index e24e451a33..d23aa012c4 100644 --- a/media/libaom/src/test/fft_test.cc +++ b/media/libaom/src/test/fft_test.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include "aom_dsp/fft_common.h" @@ -133,16 +134,16 @@ TEST_P(FFT2DTest, Benchmark) { } } -INSTANTIATE_TEST_CASE_P(C, FFT2DTest, - ::testing::Values(FFTTestArg(2, aom_fft2x2_float_c), - FFTTestArg(4, aom_fft4x4_float_c), - FFTTestArg(8, aom_fft8x8_float_c), - FFTTestArg(16, aom_fft16x16_float_c), - FFTTestArg(32, - aom_fft32x32_float_c))); +INSTANTIATE_TEST_SUITE_P(C, FFT2DTest, + ::testing::Values(FFTTestArg(2, aom_fft2x2_float_c), + FFTTestArg(4, aom_fft4x4_float_c), + FFTTestArg(8, aom_fft8x8_float_c), + FFTTestArg(16, aom_fft16x16_float_c), + FFTTestArg(32, + aom_fft32x32_float_c))); #if ARCH_X86 || ARCH_X86_64 #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, FFT2DTest, ::testing::Values(FFTTestArg(4, aom_fft4x4_float_sse2), FFTTestArg(8, aom_fft8x8_float_sse2), @@ -150,7 +151,7 @@ INSTANTIATE_TEST_CASE_P( FFTTestArg(32, aom_fft32x32_float_sse2))); #endif // HAVE_SSE2 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, FFT2DTest, ::testing::Values(FFTTestArg(8, aom_fft8x8_float_avx2), FFTTestArg(16, aom_fft16x16_float_avx2), @@ -227,7 +228,7 @@ TEST_P(IFFT2DTest, Benchmark) { input_[i % (n * n)] = 0; } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, IFFT2DTest, ::testing::Values(IFFTTestArg(2, aom_ifft2x2_float_c), IFFTTestArg(4, aom_ifft4x4_float_c), @@ -236,7 +237,7 @@ INSTANTIATE_TEST_CASE_P( IFFTTestArg(32, aom_ifft32x32_float_c))); #if ARCH_X86 || ARCH_X86_64 #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, IFFT2DTest, ::testing::Values(IFFTTestArg(4, aom_ifft4x4_float_sse2), IFFTTestArg(8, aom_ifft8x8_float_sse2), @@ -245,7 +246,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE2 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, IFFT2DTest, ::testing::Values(IFFTTestArg(8, aom_ifft8x8_float_avx2), IFFTTestArg(16, aom_ifft16x16_float_avx2), diff --git a/media/libaom/src/test/filterintra_test.cc b/media/libaom/src/test/filterintra_test.cc index 93e26ae46b..284353c69c 100644 --- a/media/libaom/src/test/filterintra_test.cc +++ b/media/libaom/src/test/filterintra_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/av1_rtcd.h" @@ -22,7 +24,7 @@ namespace { using libaom_test::ACMRandom; -using ::testing::tuple; +using std::tuple; typedef void (*Predictor)(uint8_t *dst, ptrdiff_t stride, TX_SIZE tx_size, const uint8_t *above, const uint8_t *left, int mode); @@ -43,9 +45,9 @@ class AV1FilterIntraPredTest : public ::testing::TestWithParam { virtual ~AV1FilterIntraPredTest() {} virtual void SetUp() { PredFuncMode funcMode = GET_PARAM(0); - predFuncRef_ = ::testing::get<0>(funcMode); - predFunc_ = ::testing::get<1>(funcMode); - mode_ = ::testing::get<2>(funcMode); + predFuncRef_ = std::get<0>(funcMode); + predFunc_ = std::get<1>(funcMode); + mode_ = std::get<2>(funcMode); txSize_ = GET_PARAM(1); alloc_ = new uint8_t[2 * MaxTxSize + 1]; @@ -108,7 +110,7 @@ class AV1FilterIntraPredTest : public ::testing::TestWithParam { TEST_P(AV1FilterIntraPredTest, BitExactCheck) { RunTest(); } -using ::testing::make_tuple; +using std::make_tuple; const PredFuncMode kPredFuncMdArray[] = { make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1, @@ -127,7 +129,7 @@ const TX_SIZE kTxSize[] = { TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_4X8, TX_8X4, TX_8X16, TX_16X8, TX_16X32, TX_32X16, TX_4X16, TX_16X4, TX_8X32, TX_32X8 }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1FilterIntraPredTest, ::testing::Combine(::testing::ValuesIn(kPredFuncMdArray), ::testing::ValuesIn(kTxSize))); diff --git a/media/libaom/src/test/frame_error_test.cc b/media/libaom/src/test/frame_error_test.cc index 73b880a9c7..6d74a68f2a 100644 --- a/media/libaom/src/test/frame_error_test.cc +++ b/media/libaom/src/test/frame_error_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "config/av1_rtcd.h" @@ -35,7 +36,7 @@ const int kBlockHeight[] = { 480, 482, 360, 720, 1080, }; #endif -typedef ::testing::tuple FrameErrorParam; +typedef std::tuple FrameErrorParam; class AV1FrameErrorTest : public ::testing::TestWithParam { public: @@ -146,7 +147,7 @@ TEST_P(AV1FrameErrorTest, DISABLED_Speed) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AV1FrameErrorTest, ::testing::Combine(::testing::Values(&av1_calc_frame_error_sse2), ::testing::ValuesIn(kBlockWidth), @@ -154,7 +155,7 @@ INSTANTIATE_TEST_CASE_P( #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1FrameErrorTest, ::testing::Combine(::testing::Values(&av1_calc_frame_error_avx2), ::testing::ValuesIn(kBlockWidth), diff --git a/media/libaom/src/test/function_equivalence_test.h b/media/libaom/src/test/function_equivalence_test.h index f270689023..a299c48d43 100644 --- a/media/libaom/src/test/function_equivalence_test.h +++ b/media/libaom/src/test/function_equivalence_test.h @@ -12,6 +12,8 @@ #ifndef AOM_TEST_FUNCTION_EQUIVALENCE_TEST_H_ #define AOM_TEST_FUNCTION_EQUIVALENCE_TEST_H_ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/acm_random.h" #include "test/clear_system_state.h" diff --git a/media/libaom/src/test/fwd_kf_test.cc b/media/libaom/src/test/fwd_kf_test.cc index 9f6f7efe35..50c2f36d83 100644 --- a/media/libaom/src/test/fwd_kf_test.cc +++ b/media/libaom/src/test/fwd_kf_test.cc @@ -9,6 +9,8 @@ * 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" @@ -23,10 +25,15 @@ typedef struct { } FwdKfTestParam; const FwdKfTestParam kTestParams[] = { - { 4, 37.0 }, { 6, 35.9 }, { 8, 35.0 }, - { 12, 33.6 }, { 16, 33.5 }, { 18, 33.1 } + { 4, 33.4 }, { 6, 32.9 }, { 8, 32.6 }, + { 12, 32.4 }, { 16, 32.3 }, { 18, 32.1 } }; +std::ostream &operator<<(std::ostream &os, const FwdKfTestParam &test_arg) { + return os << "FwdKfTestParam { max_kf_dist:" << test_arg.max_kf_dist + << " psnr_thresh:" << test_arg.psnr_thresh << " }"; +} + class ForwardKeyTest : public ::libaom_test::CodecTestWith2Params, diff --git a/media/libaom/src/test/fwht4x4_test.cc b/media/libaom/src/test/fwht4x4_test.cc index c8d98c5198..d2f77b8d47 100644 --- a/media/libaom/src/test/fwht4x4_test.cc +++ b/media/libaom/src/test/fwht4x4_test.cc @@ -12,7 +12,9 @@ #include #include #include +#include +#include "aom_dsp/aom_dsp_common.h" #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/av1_rtcd.h" @@ -35,7 +37,7 @@ typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); using libaom_test::FhtFunc; -typedef ::testing::tuple +typedef std::tuple Dct4x4Param; void fwht4x4_ref(const int16_t *in, tran_low_t *out, int stride, @@ -51,7 +53,7 @@ void iwht4x4_12(const tran_low_t *in, uint8_t *out, int stride) { av1_highbd_iwht4x4_16_add_c(in, out, stride, 12); } -class Trans4x4WHT : public libaom_test::TransformTestBase, +class Trans4x4WHT : public libaom_test::TransformTestBase, public ::testing::TestWithParam { public: virtual ~Trans4x4WHT() {} @@ -87,9 +89,9 @@ TEST_P(Trans4x4WHT, CoeffCheck) { RunCoeffCheck(); } TEST_P(Trans4x4WHT, MemCheck) { RunMemCheck(); } TEST_P(Trans4x4WHT, InvAccuracyCheck) { RunInvAccuracyCheck(0); } -using ::testing::make_tuple; +using std::make_tuple; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, Trans4x4WHT, ::testing::Values(make_tuple(&av1_highbd_fwht4x4_c, &iwht4x4_10, DCT_DCT, AOM_BITS_10, 16), diff --git a/media/libaom/src/test/gf_max_pyr_height_test.cc b/media/libaom/src/test/gf_pyr_height_test.cc similarity index 61% rename from media/libaom/src/test/gf_max_pyr_height_test.cc rename to media/libaom/src/test/gf_pyr_height_test.cc index 56d3255aaa..b1ade67a6b 100644 --- a/media/libaom/src/test/gf_max_pyr_height_test.cc +++ b/media/libaom/src/test/gf_pyr_height_test.cc @@ -9,6 +9,8 @@ * 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" @@ -17,11 +19,38 @@ namespace { -static const struct GFMaxPyrHeightTestParam { +static const struct GFPyrHeightTestParam { + int gf_min_pyr_height; int gf_max_pyr_height; double psnr_thresh; } kTestParams[] = { - { 0, 34.2 }, { 1, 34.40 }, { 2, 34.9 }, { 3, 35.1 }, { 4, 35.2 }, + // gf_min_pyr_height = 0 + { 0, 0, 33.40 }, + { 0, 1, 34.00 }, + { 0, 2, 34.00 }, + { 0, 3, 34.20 }, + { 0, 4, 34.30 }, + { 0, 5, 34.40 }, + // gf_min_pyr_height = 1 + { 1, 1, 34.00 }, + { 1, 2, 34.00 }, + { 1, 3, 34.20 }, + { 1, 4, 34.30 }, + { 1, 5, 34.40 }, + // gf_min_pyr_height = 2 + { 2, 2, 34.00 }, + { 2, 3, 34.20 }, + { 2, 4, 34.30 }, + { 2, 5, 34.40 }, + // gf_min_pyr_height = 3 + { 3, 3, 34.20 }, + { 3, 4, 34.30 }, + { 3, 5, 34.40 }, + // gf_min_pyr_height = 4 + { 4, 4, 34.30 }, + { 4, 5, 34.40 }, + // gf_min_pyr_height = 5 + { 5, 5, 34.40 }, }; // Compiler may decide to add some padding to the struct above for alignment, @@ -29,25 +58,28 @@ static const struct GFMaxPyrHeightTestParam { // 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 { " +std::ostream &operator<<(std::ostream &os, const GFPyrHeightTestParam &p) { + os << "GFPyrHeightTestParam { " + << "gf_min_pyr_height = " << p.gf_min_pyr_height << ", " << "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, +// Params: encoding mode, rate control mode and GFPyrHeightTestParam object. +class GFPyrHeightTest + : public ::libaom_test::CodecTestWith3Params< + libaom_test::TestMode, aom_rc_mode, GFPyrHeightTestParam>, 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; + GFPyrHeightTest() + : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), + rc_mode_(GET_PARAM(2)) { + gf_min_pyr_height_ = GET_PARAM(3).gf_min_pyr_height; + gf_max_pyr_height_ = GET_PARAM(3).gf_max_pyr_height; + psnr_threshold_ = GET_PARAM(3).psnr_thresh; } - virtual ~GFMaxPyrHeightTest() {} + virtual ~GFPyrHeightTest() {} virtual void SetUp() { InitializeConfig(); @@ -55,8 +87,10 @@ class GFMaxPyrHeightTest 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_.rc_end_usage = rc_mode_; + if (rc_mode_ == AOM_VBR) { + cfg_.rc_target_bitrate = 200; + } cfg_.g_lag_in_frames = 19; cfg_.g_threads = 0; init_flags_ = AOM_CODEC_USE_PSNR; @@ -76,11 +110,15 @@ class GFMaxPyrHeightTest ::libaom_test::Encoder *encoder) { if (video->frame() == 0) { encoder->Control(AOME_SET_CPUUSED, cpu_used_); + if (rc_mode_ == AOM_Q) { + encoder->Control(AOME_SET_CQ_LEVEL, 32); + } 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_MIN_PYRAMID_HEIGHT, gf_min_pyr_height_); encoder->Control(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, gf_max_pyr_height_); } } @@ -93,23 +131,26 @@ class GFMaxPyrHeightTest double GetPsnrThreshold() { return psnr_threshold_; } ::libaom_test::TestMode encoding_mode_; + aom_rc_mode rc_mode_; double psnr_threshold_; + int gf_min_pyr_height_; int gf_max_pyr_height_; int cpu_used_; int nframes_; double psnr_; }; -TEST_P(GFMaxPyrHeightTest, EncodeAndVerifyPSNR) { +TEST_P(GFPyrHeightTest, 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 Min Pyramid Height = " << gf_min_pyr_height_ << ", " << "GF Max Pyramid Height = " << gf_max_pyr_height_; } -AV1_INSTANTIATE_TEST_CASE(GFMaxPyrHeightTest, - ::testing::Values(::libaom_test::kTwoPassGood), +AV1_INSTANTIATE_TEST_CASE(GFPyrHeightTest, NONREALTIME_TEST_MODES, + ::testing::Values(AOM_Q, AOM_VBR), ::testing::ValuesIn(kTestParams)); } // namespace diff --git a/media/libaom/src/test/hadamard_test.cc b/media/libaom/src/test/hadamard_test.cc index e331556cf3..7903259e7d 100644 --- a/media/libaom/src/test/hadamard_test.cc +++ b/media/libaom/src/test/hadamard_test.cc @@ -9,6 +9,7 @@ */ #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -229,14 +230,14 @@ TEST_P(HadamardLowbdTest, CompareReferenceRandom) { CompareReferenceRandom(); } TEST_P(HadamardLowbdTest, VaryStride) { VaryStride(); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, HadamardLowbdTest, ::testing::Values(HadamardFuncWithSize(&aom_hadamard_8x8_c, 8), HadamardFuncWithSize(&aom_hadamard_16x16_c, 16), HadamardFuncWithSize(&aom_hadamard_32x32_c, 32))); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, HadamardLowbdTest, ::testing::Values(HadamardFuncWithSize(&aom_hadamard_8x8_sse2, 8), HadamardFuncWithSize(&aom_hadamard_16x16_sse2, 16), @@ -244,14 +245,14 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE2 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, HadamardLowbdTest, ::testing::Values(HadamardFuncWithSize(&aom_hadamard_16x16_avx2, 16), HadamardFuncWithSize(&aom_hadamard_32x32_avx2, 32))); #endif // HAVE_AVX2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, HadamardLowbdTest, ::testing::Values(HadamardFuncWithSize(&aom_hadamard_8x8_neon, 8), HadamardFuncWithSize(&aom_hadamard_16x16_neon, 16))); diff --git a/media/libaom/src/test/hash_test.cc b/media/libaom/src/test/hash_test.cc index 1aed40946f..eb964ac5f6 100644 --- a/media/libaom/src/test/hash_test.cc +++ b/media/libaom/src/test/hash_test.cc @@ -11,6 +11,7 @@ #include #include +#include #include "config/aom_config.h" #include "config/av1_rtcd.h" @@ -26,7 +27,7 @@ namespace { typedef uint32_t (*get_crc32c_value_func)(void *calculator, uint8_t *p, size_t length); -typedef ::testing::tuple HashParam; +typedef std::tuple HashParam; class AV1Crc32cHashTest : public ::testing::TestWithParam { public: @@ -118,13 +119,13 @@ TEST_P(AV1Crc32cHashTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); } const int kValidBlockSize[] = { 64, 32, 8, 4 }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AV1Crc32cHashTest, ::testing::Combine(::testing::Values(&av1_get_crc32c_value_c), ::testing::ValuesIn(kValidBlockSize))); #if HAVE_SSE4_2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_2, AV1Crc32cHashTest, ::testing::Combine(::testing::Values(&av1_get_crc32c_value_sse4_2), ::testing::ValuesIn(kValidBlockSize))); diff --git a/media/libaom/src/test/hbd_metrics_test.cc b/media/libaom/src/test/hbd_metrics_test.cc index 09df9bde47..5b03beee7d 100644 --- a/media/libaom/src/test/hbd_metrics_test.cc +++ b/media/libaom/src/test/hbd_metrics_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/acm_random.h" @@ -173,7 +174,7 @@ class HBDMetricsTestBase { HBDMetricFunc hbd_metric_; }; -typedef ::testing::tuple +typedef std::tuple MetricTestTParam; class HBDMetricsTest : public HBDMetricsTestBase, public ::testing::TestWithParam { @@ -197,7 +198,7 @@ static const double kFSsim_thresh = 0.03; // Allow some extra variation due to rounding error accumulated in dct. static const double kPhvs_thresh = 0.3; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AOMSSIM, HBDMetricsTest, ::testing::Values(MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 8, 10, kSsim_thresh), @@ -207,7 +208,7 @@ INSTANTIATE_TEST_CASE_P( 8, 12, kSsim_thresh), MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim, 12, 12, kPhvs_thresh))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FASTSSIM, HBDMetricsTest, ::testing::Values(MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 8, 10, kFSsim_thresh), @@ -217,7 +218,7 @@ INSTANTIATE_TEST_CASE_P( 8, 12, kFSsim_thresh), MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 12, 12, kFSsim_thresh))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PSNRHVS, HBDMetricsTest, ::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 8, 10, kPhvs_thresh), @@ -227,7 +228,7 @@ INSTANTIATE_TEST_CASE_P( 8, 12, kPhvs_thresh), MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 12, 12, kPhvs_thresh))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PSNR, HBDMetricsTest, ::testing::Values( MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10, kPhvs_thresh), diff --git a/media/libaom/src/test/hiprec_convolve_test.cc b/media/libaom/src/test/hiprec_convolve_test.cc index 9301abfefb..59d28e8830 100644 --- a/media/libaom/src/test/hiprec_convolve_test.cc +++ b/media/libaom/src/test/hiprec_convolve_test.cc @@ -9,6 +9,8 @@ * 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/hiprec_convolve_test_util.h" @@ -17,8 +19,8 @@ using libaom_test::ACMRandom; using libaom_test::AV1HighbdHiprecConvolve::AV1HighbdHiprecConvolveTest; #endif using libaom_test::AV1HiprecConvolve::AV1HiprecConvolveTest; -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace { @@ -27,19 +29,19 @@ TEST_P(AV1HiprecConvolveTest, DISABLED_SpeedTest) { RunSpeedTest(GET_PARAM(3)); } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, AV1HiprecConvolveTest, - libaom_test::AV1HiprecConvolve::BuildParams( - av1_wiener_convolve_add_src_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1HiprecConvolveTest, + libaom_test::AV1HiprecConvolve::BuildParams( + av1_wiener_convolve_add_src_sse2)); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, AV1HiprecConvolveTest, - libaom_test::AV1HiprecConvolve::BuildParams( - av1_wiener_convolve_add_src_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HiprecConvolveTest, + libaom_test::AV1HiprecConvolve::BuildParams( + av1_wiener_convolve_add_src_avx2)); #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, AV1HiprecConvolveTest, - libaom_test::AV1HiprecConvolve::BuildParams( - av1_wiener_convolve_add_src_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, AV1HiprecConvolveTest, + libaom_test::AV1HiprecConvolve::BuildParams( + av1_wiener_convolve_add_src_neon)); #endif #if CONFIG_AV1_HIGHBITDEPTH @@ -51,14 +53,14 @@ TEST_P(AV1HighbdHiprecConvolveTest, DISABLED_SpeedTest) { RunSpeedTest(GET_PARAM(4)); } #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P(SSSE3, AV1HighbdHiprecConvolveTest, - libaom_test::AV1HighbdHiprecConvolve::BuildParams( - av1_highbd_wiener_convolve_add_src_ssse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, AV1HighbdHiprecConvolveTest, + libaom_test::AV1HighbdHiprecConvolve::BuildParams( + av1_highbd_wiener_convolve_add_src_ssse3)); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdHiprecConvolveTest, - libaom_test::AV1HighbdHiprecConvolve::BuildParams( - av1_highbd_wiener_convolve_add_src_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AV1HighbdHiprecConvolveTest, + libaom_test::AV1HighbdHiprecConvolve::BuildParams( + av1_highbd_wiener_convolve_add_src_avx2)); #endif #endif #endif // CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/test/hiprec_convolve_test_util.cc b/media/libaom/src/test/hiprec_convolve_test_util.cc index 5da8b8495e..956af7fc89 100644 --- a/media/libaom/src/test/hiprec_convolve_test_util.cc +++ b/media/libaom/src/test/hiprec_convolve_test_util.cc @@ -13,8 +13,8 @@ #include "av1/common/restoration.h" -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace libaom_test { diff --git a/media/libaom/src/test/hiprec_convolve_test_util.h b/media/libaom/src/test/hiprec_convolve_test_util.h index 847fb55469..6b6da4ee81 100644 --- a/media/libaom/src/test/hiprec_convolve_test_util.h +++ b/media/libaom/src/test/hiprec_convolve_test_util.h @@ -12,6 +12,8 @@ #ifndef AOM_TEST_HIPREC_CONVOLVE_TEST_UTIL_H_ #define AOM_TEST_HIPREC_CONVOLVE_TEST_UTIL_H_ +#include + #include "config/av1_rtcd.h" #include "test/acm_random.h" @@ -35,8 +37,7 @@ typedef void (*hiprec_convolve_func)(const uint8_t *src, ptrdiff_t src_stride, int w, int h, const ConvolveParams *conv_params); -typedef ::testing::tuple - HiprecConvolveParam; +typedef std::tuple HiprecConvolveParam; ::testing::internal::ParamGenerator BuildParams( hiprec_convolve_func filter); @@ -66,7 +67,7 @@ typedef void (*highbd_hiprec_convolve_func)( const int16_t *filter_y, int y_step_q4, int w, int h, const ConvolveParams *conv_params, int bps); -typedef ::testing::tuple +typedef std::tuple HighbdHiprecConvolveParam; ::testing::internal::ParamGenerator BuildParams( diff --git a/media/libaom/src/test/horver_correlation_test.cc b/media/libaom/src/test/horver_correlation_test.cc index 72fd46ac23..ccb8eddd0a 100644 --- a/media/libaom/src/test/horver_correlation_test.cc +++ b/media/libaom/src/test/horver_correlation_test.cc @@ -9,6 +9,8 @@ * 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/acm_random.h" @@ -27,7 +29,7 @@ namespace { typedef void (*HorverFunc)(const int16_t *diff, int stride, int w, int h, float *hcorr, float *vcorr); -typedef ::testing::tuple HorverTestParam; +typedef std::tuple HorverTestParam; class HorverTest : public ::testing::TestWithParam { public: @@ -133,13 +135,13 @@ TEST_P(HorverTest, ExtremeValues) { RunHorverTest_ExtremeValues(); } TEST_P(HorverTest, DISABLED_Speed) { RunHorverSpeedTest(100000); } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, HorverTest, ::testing::Values(av1_get_horver_correlation_full_sse4_1)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, HorverTest, ::testing::Values(av1_get_horver_correlation_full_avx2)); #endif // HAVE_AVX2 diff --git a/media/libaom/src/test/horz_superres_test.cc b/media/libaom/src/test/horz_superres_test.cc index 9a90ffbfd3..938b0b15aa 100644 --- a/media/libaom/src/test/horz_superres_test.cc +++ b/media/libaom/src/test/horz_superres_test.cc @@ -10,6 +10,8 @@ */ #include +#include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -23,8 +25,8 @@ namespace { -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; /* TESTING PARAMETERS */ @@ -40,8 +42,16 @@ typedef struct { double psnr_threshold; } TestVideoParam; +std::ostream &operator<<(std::ostream &os, const TestVideoParam &test_arg) { + return os << "TestVideoParam { filename:" << test_arg.filename + << " fmt:" << test_arg.fmt << " bit_depth:" << test_arg.bit_depth + << " profile:" << test_arg.profile << " limit:" << test_arg.limit + << " screen_content:" << test_arg.screen_content + << " psnr_threshold:" << test_arg.psnr_threshold << " }"; +} + const TestVideoParam kTestVideoVectors[] = { - { "park_joy_90p_8_420.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 5, 0, 26.0 }, + { "park_joy_90p_8_420.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 5, 0, 25.5 }, #if CONFIG_AV1_HIGHBITDEPTH { "park_joy_90p_10_444.y4m", AOM_IMG_FMT_I44416, AOM_BITS_10, 1, 5, 0, 28.0 }, #endif @@ -184,8 +194,8 @@ class 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); + superres_denom_ = std::get<0>(denoms); + superres_kf_denom_ = std::get<1>(denoms); } virtual ~HorzSuperresFixedEndToEndTest() {} @@ -295,8 +305,8 @@ class HorzSuperresQThreshEndToEndTest : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)), superres_mode_(SUPERRES_QTHRESH), psnr_(0.0), frame_count_(0) { SuperresQThresholdPair qthresholds = GET_PARAM(2); - superres_qthresh_ = ::testing::get<0>(qthresholds); - superres_kf_qthresh_ = ::testing::get<1>(qthresholds); + superres_qthresh_ = std::get<0>(qthresholds); + superres_kf_qthresh_ = std::get<1>(qthresholds); } virtual ~HorzSuperresQThreshEndToEndTest() {} diff --git a/media/libaom/src/test/intra_edge_test.cc b/media/libaom/src/test/intra_edge_test.cc index ce61402acb..f7702c952b 100644 --- a/media/libaom/src/test/intra_edge_test.cc +++ b/media/libaom/src/test/intra_edge_test.cc @@ -100,7 +100,7 @@ TEST_P(UpsampleTest8B, RandomValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, UpsampleTest8B, ::testing::Values(TestFuncs(av1_upsample_intra_edge_c, av1_upsample_intra_edge_sse4_1))); @@ -152,7 +152,7 @@ TEST_P(UpsampleTestHB, RandomValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, UpsampleTestHB, ::testing::Values(TestFuncsHBD(av1_upsample_intra_edge_high_c, av1_upsample_intra_edge_high_sse4_1))); @@ -223,7 +223,7 @@ TEST_P(FilterEdgeTest8B, RandomValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, FilterEdgeTest8B, ::testing::Values(FilterEdgeTestFuncs(av1_filter_intra_edge_c, av1_filter_intra_edge_sse4_1))); @@ -268,10 +268,10 @@ TEST_P(FilterEdgeTestHB, RandomValues) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, FilterEdgeTestHB, - ::testing::Values(FilterEdgeTestFuncsHBD( - av1_filter_intra_edge_high_c, - av1_filter_intra_edge_high_sse4_1))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, FilterEdgeTestHB, + ::testing::Values(FilterEdgeTestFuncsHBD( + av1_filter_intra_edge_high_c, + av1_filter_intra_edge_high_sse4_1))); #endif // HAVE_SSE4_1 // Speed tests diff --git a/media/libaom/src/test/intrabc_test.cc b/media/libaom/src/test/intrabc_test.cc index 6ef0a50574..b57eb6fab5 100644 --- a/media/libaom/src/test/intrabc_test.cc +++ b/media/libaom/src/test/intrabc_test.cc @@ -13,11 +13,11 @@ #include "config/aom_config.h" +#include "av1/common/av1_common_int.h" #include "av1/common/blockd.h" #include "av1/common/enums.h" #include "av1/common/mv.h" #include "av1/common/mvref_common.h" -#include "av1/common/onyxc_int.h" #include "av1/common/tile_common.h" namespace { @@ -157,10 +157,13 @@ TEST(IntrabcTest, DvValidation) { memset(&cm, 0, sizeof(cm)); for (const DvTestCase &dv_case : kDvCases) { + const int mi_row = xd.tile.mi_row_start + dv_case.mi_row_offset; + const int mi_col = xd.tile.mi_col_start + dv_case.mi_col_offset; + xd.is_chroma_ref = is_chroma_reference(mi_row, mi_col, dv_case.bsize, + xd.plane[1].subsampling_x, + xd.plane[1].subsampling_y); EXPECT_EQ(static_cast(dv_case.valid), - av1_is_dv_valid(dv_case.dv, &cm, &xd, - xd.tile.mi_row_start + dv_case.mi_row_offset, - xd.tile.mi_col_start + dv_case.mi_col_offset, + av1_is_dv_valid(dv_case.dv, &cm, &xd, mi_row, mi_col, dv_case.bsize, MAX_MIB_SIZE_LOG2)); } } diff --git a/media/libaom/src/test/intrapred_test.cc b/media/libaom/src/test/intrapred_test.cc index 2689c63343..779cf9a5de 100644 --- a/media/libaom/src/test/intrapred_test.cc +++ b/media/libaom/src/test/intrapred_test.cc @@ -224,8 +224,8 @@ const IntraPredFunc LowbdIntraPredTestVector[] = { lowbd_intrapred(v, sse2), lowbd_intrapred(h, sse2), }; -INSTANTIATE_TEST_CASE_P(SSE2, LowbdIntraPredTest, - ::testing::ValuesIn(LowbdIntraPredTestVector)); +INSTANTIATE_TEST_SUITE_P(SSE2, LowbdIntraPredTest, + ::testing::ValuesIn(LowbdIntraPredTestVector)); #endif // HAVE_SSE2 @@ -235,8 +235,8 @@ const IntraPredFunc LowbdIntraPredTestVectorSsse3[] = { lowbd_intrapred(smooth, ssse3), }; -INSTANTIATE_TEST_CASE_P(SSSE3, LowbdIntraPredTest, - ::testing::ValuesIn(LowbdIntraPredTestVectorSsse3)); +INSTANTIATE_TEST_SUITE_P(SSSE3, LowbdIntraPredTest, + ::testing::ValuesIn(LowbdIntraPredTestVectorSsse3)); #endif // HAVE_SSSE3 @@ -252,8 +252,8 @@ const IntraPredFunc LowbdIntraPredTestVectorAvx2[] = { lowbd_entry(paeth, 32, 16, avx2), lowbd_entry(paeth, 32, 32, avx2), }; -INSTANTIATE_TEST_CASE_P(AVX2, LowbdIntraPredTest, - ::testing::ValuesIn(LowbdIntraPredTestVectorAvx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, LowbdIntraPredTest, + ::testing::ValuesIn(LowbdIntraPredTestVectorAvx2)); #endif // HAVE_AVX2 @@ -265,8 +265,8 @@ const IntraPredFunc HighbdIntraPredTestVectorNeon[] = { highbd_entry(dc, 64, 64, neon, 8), }; -INSTANTIATE_TEST_CASE_P(NEON, HighbdIntraPredTest, - ::testing::ValuesIn(HighbdIntraPredTestVectorNeon)); +INSTANTIATE_TEST_SUITE_P(NEON, HighbdIntraPredTest, + ::testing::ValuesIn(HighbdIntraPredTestVectorNeon)); #endif // HAVE_NEON #endif // CONFIG_AV1_HIGHBITDEPTH diff --git a/media/libaom/src/test/invalid_file_test.cc b/media/libaom/src/test/invalid_file_test.cc index 5951d6ea37..dd0956d0c7 100644 --- a/media/libaom/src/test/invalid_file_test.cc +++ b/media/libaom/src/test/invalid_file_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" diff --git a/media/libaom/src/test/level_test.cc b/media/libaom/src/test/level_test.cc index 73e52e3353..a9613c5f76 100644 --- a/media/libaom/src/test/level_test.cc +++ b/media/libaom/src/test/level_test.cc @@ -93,12 +93,12 @@ TEST_P(LevelTest, TestTargetLevelApi) { level != 21 && level != 22 && level != 23) || level == 31 || operating_point > 31) { EXPECT_EQ(AOM_CODEC_OK, - aom_codec_control(&enc, AV1E_SET_TARGET_SEQ_LEVEL_IDX, - target_level)); + AOM_CODEC_CONTROL_TYPECHECKED( + &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)); + AOM_CODEC_CONTROL_TYPECHECKED( + &enc, AV1E_SET_TARGET_SEQ_LEVEL_IDX, target_level)); } } } diff --git a/media/libaom/src/test/lightfield_test.sh b/media/libaom/src/test/lightfield_test.sh index 19b6934a3b..3de88af877 100644 --- a/media/libaom/src/test/lightfield_test.sh +++ b/media/libaom/src/test/lightfield_test.sh @@ -46,6 +46,22 @@ lightfield_test() { [ -e "${lf_file}" ] || return 1 + # Check to ensure all camera frames have the identical frame header. If not identical, this test fails. + for i in ./fh*; do + diff ./fh004 $i > /dev/null + if [ $? -eq 1 ]; then + return 1 + fi + done + + # Check to ensure all camera frames use the identical frame context. If not identical, this test fails. + for i in ./fc*; do + diff ./fc004 $i > /dev/null + if [ $? -eq 1 ]; then + return 1 + fi + done + # Parse lightfield bitstream to construct and output a new bitstream that can # be decoded by an AV1 decoder. local bs_decoder="${LIBAOM_BIN_PATH}/lightfield_bitstream_parsing${AOM_TEST_EXE_SUFFIX}" diff --git a/media/libaom/src/test/lpf_test.cc b/media/libaom/src/test/lpf_test.cc index 2586e9ecc7..e8eeceb7c3 100644 --- a/media/libaom/src/test/lpf_test.cc +++ b/media/libaom/src/test/lpf_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -50,11 +51,11 @@ typedef void (*dual_loop_op_t)(uint8_t *s, DUAL_LOOP_PARAM); typedef void (*hbdloop_op_t)(uint16_t *s, LOOP_PARAM, int bd); typedef void (*hbddual_loop_op_t)(uint16_t *s, DUAL_LOOP_PARAM, int bd); -typedef ::testing::tuple hbdloop_param_t; -typedef ::testing::tuple +typedef std::tuple hbdloop_param_t; +typedef std::tuple hbddual_loop_param_t; -typedef ::testing::tuple loop_param_t; -typedef ::testing::tuple dual_loop_param_t; +typedef std::tuple loop_param_t; +typedef std::tuple dual_loop_param_t; template void InitInput(Pixel_t *s, Pixel_t *ref_s, ACMRandom *rnd, const uint8_t limit, @@ -129,9 +130,9 @@ class LoopTestParam : public ::testing::TestWithParam { public: virtual ~LoopTestParam() {} virtual void SetUp() { - loopfilter_op_ = ::testing::get<0>(this->GetParam()); - ref_loopfilter_op_ = ::testing::get<1>(this->GetParam()); - bit_depth_ = ::testing::get<2>(this->GetParam()); + loopfilter_op_ = std::get<0>(this->GetParam()); + ref_loopfilter_op_ = std::get<1>(this->GetParam()); + bit_depth_ = std::get<2>(this->GetParam()); mask_ = (1 << bit_depth_) - 1; } @@ -455,7 +456,7 @@ TEST_P(Loop8Test9Param_hbd, DISABLED_Speed) { SPEEDCHECKd(uint16_t, 16); } #endif TEST_P(Loop8Test9Param_lbd, DISABLED_Speed) { SPEEDCHECKd(uint8_t, 8); } -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_SSE2 #if CONFIG_AV1_HIGHBITDEPTH @@ -502,8 +503,8 @@ const hbdloop_param_t kHbdLoop8Test6[] = { make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 12) }; -INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param_hbd, - ::testing::ValuesIn(kHbdLoop8Test6)); +INSTANTIATE_TEST_SUITE_P(SSE2, Loop8Test6Param_hbd, + ::testing::ValuesIn(kHbdLoop8Test6)); #endif // CONFIG_AV1_HIGHBITDEPTH const loop_param_t kLoop8Test6[] = { @@ -517,8 +518,8 @@ const loop_param_t kLoop8Test6[] = { make_tuple(&aom_lpf_vertical_14_sse2, &aom_lpf_vertical_14_c, 8), }; -INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param_lbd, - ::testing::ValuesIn(kLoop8Test6)); +INSTANTIATE_TEST_SUITE_P(SSE2, Loop8Test6Param_lbd, + ::testing::ValuesIn(kLoop8Test6)); const dual_loop_param_t kLoop8Test9[] = { make_tuple(&aom_lpf_horizontal_4_dual_sse2, &aom_lpf_horizontal_4_dual_c, 8), @@ -532,8 +533,8 @@ const dual_loop_param_t kLoop8Test9[] = { make_tuple(&aom_lpf_vertical_14_dual_sse2, &aom_lpf_vertical_14_dual_c, 8) }; -INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param_lbd, - ::testing::ValuesIn(kLoop8Test9)); +INSTANTIATE_TEST_SUITE_P(SSE2, Loop8Test9Param_lbd, + ::testing::ValuesIn(kLoop8Test9)); #endif // HAVE_SSE2 @@ -589,8 +590,8 @@ const hbddual_loop_param_t kHbdLoop8Test9[] = { &aom_highbd_lpf_vertical_14_dual_c, 12), }; -INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param_hbd, - ::testing::ValuesIn(kHbdLoop8Test9)); +INSTANTIATE_TEST_SUITE_P(SSE2, Loop8Test9Param_hbd, + ::testing::ValuesIn(kHbdLoop8Test9)); #endif // HAVE_SSE2 && CONFIG_AV1_HIGHBITDEPTH @@ -606,8 +607,8 @@ const loop_param_t kLoop8Test6[] = { make_tuple(&aom_lpf_horizontal_4_neon, &aom_lpf_horizontal_4_c, 8) }; -INSTANTIATE_TEST_CASE_P(NEON, Loop8Test6Param_lbd, - ::testing::ValuesIn(kLoop8Test6)); +INSTANTIATE_TEST_SUITE_P(NEON, Loop8Test6Param_lbd, + ::testing::ValuesIn(kLoop8Test6)); #endif // HAVE_NEON #if HAVE_AVX2 && CONFIG_AV1_HIGHBITDEPTH @@ -638,7 +639,7 @@ const hbddual_loop_param_t kHbdLoop8Test9Avx2[] = { &aom_highbd_lpf_vertical_8_dual_c, 12), }; -INSTANTIATE_TEST_CASE_P(AVX2, Loop8Test9Param_hbd, - ::testing::ValuesIn(kHbdLoop8Test9Avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, Loop8Test9Param_hbd, + ::testing::ValuesIn(kHbdLoop8Test9Avx2)); #endif } // namespace diff --git a/media/libaom/src/test/masked_sad_test.cc b/media/libaom/src/test/masked_sad_test.cc index c8b5db1a23..aa4dd83410 100644 --- a/media/libaom/src/test/masked_sad_test.cc +++ b/media/libaom/src/test/masked_sad_test.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/acm_random.h" @@ -33,9 +34,37 @@ typedef unsigned int (*MaskedSADFunc)(const uint8_t *src, int src_stride, const uint8_t *second_pred, const uint8_t *msk, int msk_stride, int invert_mask); -typedef ::testing::tuple MaskedSADParam; +typedef std::tuple MaskedSADParam; -class MaskedSADTest : public ::testing::TestWithParam { +typedef void (*MaskedSADx4Func)(const uint8_t *src, int src_stride, + const uint8_t *ref[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int invert_mask, + unsigned sads[]); + +typedef std::tuple MaskedSADx4Param; + +class MaskedSADTestBase : public ::testing::Test { + public: + virtual ~MaskedSADTestBase() {} + virtual void SetUp() = 0; + virtual void runRef(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], + int times) = 0; + virtual void runTest(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], + int times) = 0; + + virtual void TearDown() { libaom_test::ClearSystemState(); } + void runMaskedSADTest(int run_times); +}; + +class MaskedSADTest : public MaskedSADTestBase, + public ::testing::WithParamInterface { public: virtual ~MaskedSADTest() {} virtual void SetUp() { @@ -43,20 +72,113 @@ class MaskedSADTest : public ::testing::TestWithParam { ref_maskedSAD_op_ = GET_PARAM(1); } - virtual void TearDown() { libaom_test::ClearSystemState(); } - void runMaskedSADTest(int run_times); + virtual void runRef(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], int times); + virtual void runTest(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], + int times); protected: MaskedSADFunc maskedSAD_op_; MaskedSADFunc ref_maskedSAD_op_; }; -void MaskedSADTest::runMaskedSADTest(int run_times) { - unsigned int ref_ret = 0, ret = 1; + +class MaskedSADx4Test : public MaskedSADTestBase, + public ::testing::WithParamInterface { + public: + virtual ~MaskedSADx4Test() {} + virtual void SetUp() { + maskedSAD_op_ = GET_PARAM(0); + ref_maskedSAD_op_ = GET_PARAM(1); + } + virtual void runRef(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], int times); + virtual void runTest(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int inv_mask, unsigned sads[], + int times); + + protected: + MaskedSADx4Func maskedSAD_op_; + MaskedSADx4Func ref_maskedSAD_op_; +}; + +void MaskedSADTest::runRef(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int invert_mask, unsigned sads[], + int times) { + for (int repeat = 0; repeat < times; ++repeat) { + sads[0] = ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr[0], ref_stride, + second_pred, msk, msk_stride, invert_mask); + } +} + +void MaskedSADTest::runTest(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int invert_mask, unsigned sads[], + int times) { + if (times == 1) { + sads[0] = maskedSAD_op_(src_ptr, src_stride, ref_ptr[0], ref_stride, + second_pred, msk, msk_stride, invert_mask); + } else { + for (int repeat = 0; repeat < times; ++repeat) { + ASM_REGISTER_STATE_CHECK( + sads[0] = maskedSAD_op_(src_ptr, src_stride, ref_ptr[0], ref_stride, + second_pred, msk, msk_stride, invert_mask)); + } + } +} + +void MaskedSADx4Test::runRef(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int invert_mask, unsigned sads[], + int times) { + for (int repeat = 0; repeat < times; ++repeat) { + ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, + msk, msk_stride, invert_mask, sads); + } +} + +void MaskedSADx4Test::runTest(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr[], int ref_stride, + const uint8_t *second_pred, const uint8_t *msk, + int msk_stride, int invert_mask, unsigned sads[], + int times) { + if (times == 1) { + ASM_REGISTER_STATE_CHECK(maskedSAD_op_(src_ptr, src_stride, ref_ptr, + ref_stride, second_pred, msk, + msk_stride, invert_mask, sads)); + } else { + for (int repeat = 0; repeat < times; ++repeat) { + maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride, second_pred, msk, + msk_stride, invert_mask, sads); + } + } +} + +void MaskedSADTestBase::runMaskedSADTest(int run_times) { ACMRandom rnd(ACMRandom::DeterministicSeed()); + const unsigned kBlockSize = MAX_SB_SIZE * MAX_SB_SIZE; DECLARE_ALIGNED(16, uint8_t, src_ptr[MAX_SB_SIZE * MAX_SB_SIZE]); - DECLARE_ALIGNED(16, uint8_t, ref_ptr[MAX_SB_SIZE * MAX_SB_SIZE]); + DECLARE_ALIGNED(16, uint8_t, ref_ptr[MAX_SB_SIZE * MAX_SB_SIZE * 4]); DECLARE_ALIGNED(16, uint8_t, second_pred_ptr[MAX_SB_SIZE * MAX_SB_SIZE]); DECLARE_ALIGNED(16, uint8_t, msk_ptr[MAX_SB_SIZE * MAX_SB_SIZE]); + + const uint8_t *refs[] = { ref_ptr, ref_ptr + kBlockSize, + ref_ptr + 2 * kBlockSize, + ref_ptr + 3 * kBlockSize }; + unsigned sads[] = { 0, 0, 0, 0 }; + unsigned sads_ref[] = { 0, 0, 0, 0 }; int err_count = 0; int first_failure = -1; int src_stride = MAX_SB_SIZE; @@ -67,6 +189,9 @@ void MaskedSADTest::runMaskedSADTest(int run_times) { for (int j = 0; j < MAX_SB_SIZE * MAX_SB_SIZE; j++) { src_ptr[j] = rnd.Rand8(); ref_ptr[j] = rnd.Rand8(); + (ref_ptr + kBlockSize)[j] = rnd.Rand8(); + (ref_ptr + 2 * kBlockSize)[j] = rnd.Rand8(); + (ref_ptr + 3 * kBlockSize)[j] = rnd.Rand8(); second_pred_ptr[j] = rnd.Rand8(); msk_ptr[j] = ((rnd.Rand8() & 0x7f) > 64) ? rnd.Rand8() & 0x3f : 64; assert(msk_ptr[j] <= 64); @@ -75,33 +200,23 @@ void MaskedSADTest::runMaskedSADTest(int run_times) { for (int invert_mask = 0; invert_mask < 2; ++invert_mask) { aom_usec_timer timer; aom_usec_timer_start(&timer); - for (int repeat = 0; repeat < run_times; ++repeat) { - ref_ret = ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride, - second_pred_ptr, msk_ptr, msk_stride, - invert_mask); - } + runRef(src_ptr, src_stride, refs, ref_stride, second_pred_ptr, msk_ptr, + msk_stride, invert_mask, sads_ref, run_times); aom_usec_timer_mark(&timer); const double time1 = static_cast(aom_usec_timer_elapsed(&timer)); + aom_usec_timer_start(&timer); - if (run_times == 1) { - ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src_ptr, src_stride, - ref_ptr, ref_stride, - second_pred_ptr, msk_ptr, - msk_stride, invert_mask)); - } else { - for (int repeat = 0; repeat < run_times; ++repeat) { - ret = - maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride, - second_pred_ptr, msk_ptr, msk_stride, invert_mask); - } - } + runTest(src_ptr, src_stride, refs, ref_stride, second_pred_ptr, msk_ptr, + msk_stride, invert_mask, sads, run_times); aom_usec_timer_mark(&timer); const double time2 = static_cast(aom_usec_timer_elapsed(&timer)); + if (run_times > 10) { printf("%7.2f/%7.2fns", time1, time2); printf("(%3.2f)\n", time1 / time2); } - if (ret != ref_ret) { + if (sads_ref[0] != sads[0] || sads_ref[1] != sads[1] || + sads_ref[2] != sads[2] || sads_ref[3] != sads[3]) { err_count++; if (first_failure == -1) first_failure = i; } @@ -115,13 +230,17 @@ TEST_P(MaskedSADTest, OperationCheck) { runMaskedSADTest(1); } TEST_P(MaskedSADTest, DISABLED_Speed) { runMaskedSADTest(2000000); } +TEST_P(MaskedSADx4Test, OperationCheck) { runMaskedSADTest(1); } + +TEST_P(MaskedSADx4Test, DISABLED_Speed) { runMaskedSADTest(2000000); } + #if CONFIG_AV1_HIGHBITDEPTH typedef unsigned int (*HighbdMaskedSADFunc)(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, const uint8_t *second_pred, const uint8_t *msk, int msk_stride, int invert_mask); -typedef ::testing::tuple +typedef std::tuple HighbdMaskedSADParam; class HighbdMaskedSADTest @@ -209,7 +328,7 @@ TEST_P(HighbdMaskedSADTest, OperationCheck) { runHighbdMaskedSADTest(1); } TEST_P(HighbdMaskedSADTest, DISABLED_Speed) { runHighbdMaskedSADTest(1000000); } #endif // CONFIG_AV1_HIGHBITDEPTH -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_SSSE3 const MaskedSADParam msad_test[] = { @@ -237,7 +356,35 @@ const MaskedSADParam msad_test[] = { make_tuple(&aom_masked_sad64x16_ssse3, &aom_masked_sad64x16_c), }; -INSTANTIATE_TEST_CASE_P(SSSE3, MaskedSADTest, ::testing::ValuesIn(msad_test)); +INSTANTIATE_TEST_SUITE_P(SSSE3, MaskedSADTest, ::testing::ValuesIn(msad_test)); + +const MaskedSADx4Param msadx4_test[] = { + make_tuple(&aom_masked_sad4x4x4d_ssse3, &aom_masked_sad4x4x4d_c), + make_tuple(&aom_masked_sad4x8x4d_ssse3, &aom_masked_sad4x8x4d_c), + make_tuple(&aom_masked_sad8x4x4d_ssse3, &aom_masked_sad8x4x4d_c), + make_tuple(&aom_masked_sad8x8x4d_ssse3, &aom_masked_sad8x8x4d_c), + make_tuple(&aom_masked_sad8x16x4d_ssse3, &aom_masked_sad8x16x4d_c), + make_tuple(&aom_masked_sad16x8x4d_ssse3, &aom_masked_sad16x8x4d_c), + make_tuple(&aom_masked_sad16x16x4d_ssse3, &aom_masked_sad16x16x4d_c), + make_tuple(&aom_masked_sad16x32x4d_ssse3, &aom_masked_sad16x32x4d_c), + make_tuple(&aom_masked_sad32x16x4d_ssse3, &aom_masked_sad32x16x4d_c), + make_tuple(&aom_masked_sad32x32x4d_ssse3, &aom_masked_sad32x32x4d_c), + make_tuple(&aom_masked_sad32x64x4d_ssse3, &aom_masked_sad32x64x4d_c), + make_tuple(&aom_masked_sad64x32x4d_ssse3, &aom_masked_sad64x32x4d_c), + make_tuple(&aom_masked_sad64x64x4d_ssse3, &aom_masked_sad64x64x4d_c), + make_tuple(&aom_masked_sad64x128x4d_ssse3, &aom_masked_sad64x128x4d_c), + make_tuple(&aom_masked_sad128x64x4d_ssse3, &aom_masked_sad128x64x4d_c), + make_tuple(&aom_masked_sad128x128x4d_ssse3, &aom_masked_sad128x128x4d_c), + make_tuple(&aom_masked_sad4x16x4d_ssse3, &aom_masked_sad4x16x4d_c), + make_tuple(&aom_masked_sad16x4x4d_ssse3, &aom_masked_sad16x4x4d_c), + make_tuple(&aom_masked_sad8x32x4d_ssse3, &aom_masked_sad8x32x4d_c), + make_tuple(&aom_masked_sad32x8x4d_ssse3, &aom_masked_sad32x8x4d_c), + make_tuple(&aom_masked_sad16x64x4d_ssse3, &aom_masked_sad16x64x4d_c), + make_tuple(&aom_masked_sad64x16x4d_ssse3, &aom_masked_sad64x16x4d_c), +}; + +INSTANTIATE_TEST_SUITE_P(SSSE3, MaskedSADx4Test, + ::testing::ValuesIn(msadx4_test)); #if CONFIG_AV1_HIGHBITDEPTH const HighbdMaskedSADParam hbd_msad_test[] = { @@ -268,8 +415,8 @@ const HighbdMaskedSADParam hbd_msad_test[] = { make_tuple(&aom_highbd_masked_sad64x16_ssse3, &aom_highbd_masked_sad64x16_c), }; -INSTANTIATE_TEST_CASE_P(SSSE3, HighbdMaskedSADTest, - ::testing::ValuesIn(hbd_msad_test)); +INSTANTIATE_TEST_SUITE_P(SSSE3, HighbdMaskedSADTest, + ::testing::ValuesIn(hbd_msad_test)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_SSSE3 @@ -299,8 +446,8 @@ const MaskedSADParam msad_avx2_test[] = { make_tuple(&aom_masked_sad64x16_avx2, &aom_masked_sad64x16_ssse3) }; -INSTANTIATE_TEST_CASE_P(AVX2, MaskedSADTest, - ::testing::ValuesIn(msad_avx2_test)); +INSTANTIATE_TEST_SUITE_P(AVX2, MaskedSADTest, + ::testing::ValuesIn(msad_avx2_test)); #if CONFIG_AV1_HIGHBITDEPTH const HighbdMaskedSADParam hbd_msad_avx2_test[] = { @@ -340,8 +487,8 @@ const HighbdMaskedSADParam hbd_msad_avx2_test[] = { &aom_highbd_masked_sad64x16_ssse3) }; -INSTANTIATE_TEST_CASE_P(AVX2, HighbdMaskedSADTest, - ::testing::ValuesIn(hbd_msad_avx2_test)); +INSTANTIATE_TEST_SUITE_P(AVX2, HighbdMaskedSADTest, + ::testing::ValuesIn(hbd_msad_avx2_test)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_AVX2 diff --git a/media/libaom/src/test/masked_variance_test.cc b/media/libaom/src/test/masked_variance_test.cc index d1b33755b2..bf814cea2b 100644 --- a/media/libaom/src/test/masked_variance_test.cc +++ b/media/libaom/src/test/masked_variance_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/acm_random.h" @@ -37,7 +38,7 @@ typedef unsigned int (*MaskedSubPixelVarianceFunc)( const uint8_t *ref, int ref_stride, const uint8_t *second_pred, const uint8_t *msk, int msk_stride, int invert_mask, unsigned int *sse); -typedef ::testing::tuple +typedef std::tuple MaskedSubPixelVarianceParam; class MaskedSubPixelVarianceTest @@ -171,8 +172,8 @@ TEST_P(MaskedSubPixelVarianceTest, ExtremeValues) { } #if CONFIG_AV1_HIGHBITDEPTH -typedef ::testing::tuple +typedef std::tuple HighbdMaskedSubPixelVarianceParam; class HighbdMaskedSubPixelVarianceTest @@ -314,7 +315,7 @@ TEST_P(HighbdMaskedSubPixelVarianceTest, ExtremeValues) { } #endif // CONFIG_AV1_HIGHBITDEPTH -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_SSSE3 @@ -366,8 +367,8 @@ const MaskedSubPixelVarianceParam sub_pel_var_test[] = { &aom_masked_sub_pixel_variance4x16_c), }; -INSTANTIATE_TEST_CASE_P(SSSE3_C_COMPARE, MaskedSubPixelVarianceTest, - ::testing::ValuesIn(sub_pel_var_test)); +INSTANTIATE_TEST_SUITE_P(SSSE3_C_COMPARE, MaskedSubPixelVarianceTest, + ::testing::ValuesIn(sub_pel_var_test)); #if CONFIG_AV1_HIGHBITDEPTH const HighbdMaskedSubPixelVarianceParam hbd_sub_pel_var_test[] = { @@ -506,8 +507,8 @@ const HighbdMaskedSubPixelVarianceParam hbd_sub_pel_var_test[] = { &aom_highbd_12_masked_sub_pixel_variance4x16_c, AOM_BITS_12), }; -INSTANTIATE_TEST_CASE_P(SSSE3_C_COMPARE, HighbdMaskedSubPixelVarianceTest, - ::testing::ValuesIn(hbd_sub_pel_var_test)); +INSTANTIATE_TEST_SUITE_P(SSSE3_C_COMPARE, HighbdMaskedSubPixelVarianceTest, + ::testing::ValuesIn(hbd_sub_pel_var_test)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_SSSE3 } // namespace diff --git a/media/libaom/src/test/metadata_memory_handling_test.cc b/media/libaom/src/test/metadata_memory_handling_test.cc deleted file mode 100644 index 59581c0c20..0000000000 --- a/media/libaom/src/test/metadata_memory_handling_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "third_party/googletest/src/googletest/include/gtest/gtest.h" - -#include "aom/aom_codec.h" -#include "aom/internal/aom_image_internal.h" -#include "aom_scale/yv12config.h" - -TEST(MetadataMemoryHandlingTest, MetadataAllocation) { - uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - aom_metadata_t *metadata = - aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10); - ASSERT_NE(metadata, nullptr); - EXPECT_EQ(aom_img_metadata_free(metadata), 0); -} - -TEST(MetadataMemoryHandlingTest, MetadataArrayAllocation) { - uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - aom_metadata_array_t *metadata_array = aom_img_metadata_array_alloc(2); - ASSERT_NE(metadata_array, nullptr); - - metadata_array->metadata_array[0] = - aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10); - metadata_array->metadata_array[1] = - aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10); - - EXPECT_EQ(aom_img_metadata_array_free(metadata_array), 2u); -} - -TEST(MetadataMemoryHandlingTest, AddMetadataToImage) { - aom_image_t image; - image.metadata = NULL; - - uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, data, 10), - 0); - EXPECT_EQ(aom_img_metadata_array_free(image.metadata), 1u); - EXPECT_EQ(aom_img_add_metadata(NULL, OBU_METADATA_TYPE_ITUT_T35, data, 10), - -1); -} - -TEST(MetadataMemoryHandlingTest, RemoveMetadataFromImage) { - aom_image_t image; - image.metadata = NULL; - - uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - - ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, data, 10), - 0); - EXPECT_EQ(aom_img_remove_metadata(&image), 1u); - EXPECT_EQ(aom_img_remove_metadata(NULL), 0u); -} - -TEST(MetadataMemoryHandlingTest, CopyMetadataToFrameBUffer) { - YV12_BUFFER_CONFIG yvBuf; - yvBuf.metadata = NULL; - uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - - aom_metadata_array_t *metadata_array = aom_img_metadata_array_alloc(1); - ASSERT_NE(metadata_array, nullptr); - - metadata_array->metadata_array[0] = - aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10); - - // Metadata_array - int status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array); - EXPECT_EQ(status, 0); - status = aom_copy_metadata_to_frame_buffer(NULL, metadata_array); - EXPECT_EQ(status, -1); - EXPECT_EQ(aom_img_metadata_array_free(metadata_array), 1u); - - // Metadata_array_2 - aom_metadata_array_t *metadata_array_2 = aom_img_metadata_array_alloc(0); - ASSERT_NE(metadata_array_2, nullptr); - status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array_2); - EXPECT_EQ(status, -1); - EXPECT_EQ(aom_img_metadata_array_free(metadata_array_2), 0u); - - // YV12_BUFFER_CONFIG - status = aom_copy_metadata_to_frame_buffer(&yvBuf, NULL); - EXPECT_EQ(status, -1); - EXPECT_EQ(aom_remove_metadata_from_frame_buffer(NULL), 0u); - EXPECT_EQ(aom_remove_metadata_from_frame_buffer(&yvBuf), 1u); -} diff --git a/media/libaom/src/test/metadata_test.cc b/media/libaom/src/test/metadata_test.cc new file mode 100644 index 0000000000..79e08a7a57 --- /dev/null +++ b/media/libaom/src/test/metadata_test.cc @@ -0,0 +1,337 @@ +/* + * 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 "aom/aom_codec.h" +#include "aom/aom_image.h" +#include "aom/internal/aom_image_internal.h" +#include "aom_scale/yv12config.h" +#include "av1/encoder/bitstream.h" +#include "test/codec_factory.h" +#include "test/encode_test_driver.h" +#include "test/i420_video_source.h" +#include "test/util.h" +#include "test/video_source.h" + +namespace { +const size_t kMetadataPayloadSizeT35 = 24; +// 0xB5 stands for the itut t35 metadata country code for the Unites States +const uint8_t kMetadataPayloadT35[kMetadataPayloadSizeT35] = { + 0xB5, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 +}; + +const size_t kMetadataPayloadSizeCll = 4; +const uint8_t kMetadataPayloadCll[kMetadataPayloadSizeCll] = { 0xB5, 0x01, 0x02, + 0x03 }; + +#if CONFIG_AV1_ENCODER + +const size_t kMetadataObuSizeT35 = 28; +const uint8_t kMetadataObuT35[kMetadataObuSizeT35] = { + 0x2A, 0x1A, 0x02, 0xB5, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x80 +}; +const size_t kMetadataObuSizeMdcv = 28; +const uint8_t kMetadataObuMdcv[kMetadataObuSizeMdcv] = { + 0x2A, 0x1A, 0x02, 0xB5, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x80 +}; +const size_t kMetadataObuSizeCll = 8; +const uint8_t kMetadataObuCll[kMetadataObuSizeCll] = { 0x2A, 0x06, 0x01, 0xB5, + 0x01, 0x02, 0x03, 0x80 }; + +class MetadataEncodeTest + : public ::libaom_test::CodecTestWithParam, + public ::libaom_test::EncoderTest { + protected: + MetadataEncodeTest() : EncoderTest(GET_PARAM(0)) {} + + virtual ~MetadataEncodeTest() {} + + virtual void SetUp() { + InitializeConfig(); + SetMode(GET_PARAM(1)); + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video) { + aom_image_t *current_frame = video->img(); + if (current_frame) { + if (current_frame->metadata) aom_img_remove_metadata(current_frame); + ASSERT_EQ(aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, 0, AOM_MIF_ANY_FRAME), + -1); + ASSERT_EQ( + aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35, NULL, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME), + -1); + ASSERT_EQ(aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35, + NULL, 0, AOM_MIF_ANY_FRAME), + -1); + ASSERT_EQ( + aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_ANY_FRAME), + 0); + + ASSERT_EQ( + aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_HDR_MDCV, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_KEY_FRAME), + 0); + + ASSERT_EQ( + aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_HDR_CLL, + kMetadataPayloadCll, kMetadataPayloadSizeCll, + AOM_MIF_KEY_FRAME), + 0); + } + } + + virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) { + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { + const size_t bitstream_size = pkt->data.frame.sz; + const uint8_t *bitstream = + static_cast(pkt->data.frame.buf); + // look for valid metadatas in bitstream + bool itut_t35_metadata_found = false; + if (bitstream_size >= kMetadataObuSizeT35) { + for (size_t i = 0; i <= bitstream_size - kMetadataObuSizeT35; ++i) { + if (memcmp(bitstream + i, kMetadataObuT35, kMetadataObuSizeT35) == + 0) { + itut_t35_metadata_found = true; + } + } + } + ASSERT_EQ(itut_t35_metadata_found, 1u); + + // Testing for HDR MDCV metadata + bool hdr_mdcv_metadata_found = false; + if (bitstream_size >= kMetadataObuSizeMdcv) { + for (size_t i = 0; i <= bitstream_size - kMetadataObuSizeMdcv; ++i) { + if (memcmp(bitstream + i, kMetadataObuMdcv, kMetadataObuSizeMdcv) == + 0) { + hdr_mdcv_metadata_found = true; + } + } + } + ASSERT_TRUE(hdr_mdcv_metadata_found); + + // Testing for HDR CLL metadata + bool hdr_cll_metadata_found = false; + if (bitstream_size >= kMetadataObuSizeCll) { + for (size_t i = 0; i <= bitstream_size - kMetadataObuSizeCll; ++i) { + if (memcmp(bitstream + i, kMetadataObuCll, kMetadataObuSizeCll) == + 0) { + hdr_cll_metadata_found = true; + } + } + } + ASSERT_TRUE(hdr_cll_metadata_found); + } + } + + virtual void DecompressedFrameHook(const aom_image_t &img, + aom_codec_pts_t /*pts*/) { + ASSERT_TRUE(img.metadata != nullptr); + + ASSERT_EQ(img.metadata->sz, 3u); + + for (size_t i = 0; i < img.metadata->sz - 1; ++i) { + ASSERT_EQ(kMetadataPayloadSizeT35, img.metadata->metadata_array[i]->sz); + EXPECT_EQ( + memcmp(kMetadataPayloadT35, img.metadata->metadata_array[i]->payload, + kMetadataPayloadSizeT35), + 0); + } + + ASSERT_EQ(kMetadataPayloadSizeCll, img.metadata->metadata_array[2]->sz); + EXPECT_EQ( + memcmp(kMetadataPayloadCll, img.metadata->metadata_array[2]->payload, + kMetadataPayloadSizeCll), + 0); + } +}; + +TEST_P(MetadataEncodeTest, TestMetadataEncoding) { + ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 5); + init_flags_ = AOM_CODEC_USE_PSNR; + + cfg_.g_w = 352; + cfg_.g_h = 288; + + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 600; + cfg_.rc_buf_sz = 1000; + cfg_.rc_min_quantizer = 2; + cfg_.rc_max_quantizer = 56; + cfg_.rc_undershoot_pct = 50; + cfg_.rc_overshoot_pct = 50; + cfg_.rc_end_usage = AOM_CBR; + cfg_.kf_mode = AOM_KF_AUTO; + cfg_.g_lag_in_frames = 1; + cfg_.kf_min_dist = cfg_.kf_max_dist = 3000; + // Enable dropped frames. + cfg_.rc_dropframe_thresh = 1; + // Disable error_resilience mode. + cfg_.g_error_resilient = 0; + // Run at low bitrate. + cfg_.rc_target_bitrate = 40; + + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + +AV1_INSTANTIATE_TEST_CASE(MetadataEncodeTest, + ::testing::Values(::libaom_test::kOnePassGood)); + +#endif // CONFIG_AV1_ENCODER +} // namespace + +TEST(MetadataTest, MetadataAllocation) { + aom_metadata_t *metadata = + aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME); + ASSERT_NE(metadata, nullptr); + aom_img_metadata_free(metadata); +} + +TEST(MetadataTest, MetadataArrayAllocation) { + aom_metadata_array_t *metadata_array = aom_img_metadata_array_alloc(2); + ASSERT_NE(metadata_array, nullptr); + + metadata_array->metadata_array[0] = + aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME); + metadata_array->metadata_array[1] = + aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME); + + aom_img_metadata_array_free(metadata_array); +} + +TEST(MetadataTest, AddMetadataToImage) { + aom_image_t image; + image.metadata = NULL; + + ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_ANY_FRAME), + 0); + aom_img_metadata_array_free(image.metadata); + EXPECT_EQ(aom_img_add_metadata(NULL, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_ANY_FRAME), + -1); +} + +TEST(MetadataTest, RemoveMetadataFromImage) { + aom_image_t image; + image.metadata = NULL; + + ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_ANY_FRAME), + 0); + aom_img_remove_metadata(&image); + aom_img_remove_metadata(NULL); +} + +TEST(MetadataTest, CopyMetadataToFrameBuffer) { + YV12_BUFFER_CONFIG yvBuf; + yvBuf.metadata = NULL; + + aom_metadata_array_t *metadata_array = aom_img_metadata_array_alloc(1); + ASSERT_NE(metadata_array, nullptr); + + metadata_array->metadata_array[0] = + aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME); + + // Metadata_array + int status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array); + EXPECT_EQ(status, 0); + status = aom_copy_metadata_to_frame_buffer(NULL, metadata_array); + EXPECT_EQ(status, -1); + aom_img_metadata_array_free(metadata_array); + + // Metadata_array_2 + aom_metadata_array_t *metadata_array_2 = aom_img_metadata_array_alloc(0); + ASSERT_NE(metadata_array_2, nullptr); + status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array_2); + EXPECT_EQ(status, -1); + aom_img_metadata_array_free(metadata_array_2); + + // YV12_BUFFER_CONFIG + status = aom_copy_metadata_to_frame_buffer(&yvBuf, NULL); + EXPECT_EQ(status, -1); + aom_remove_metadata_from_frame_buffer(&yvBuf); + aom_remove_metadata_from_frame_buffer(NULL); +} + +TEST(MetadataTest, GetMetadataFromImage) { + aom_image_t image; + image.metadata = NULL; + + ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, + kMetadataPayloadT35, kMetadataPayloadSizeT35, + AOM_MIF_ANY_FRAME), + 0); + + EXPECT_TRUE(aom_img_get_metadata(NULL, 0) == NULL); + EXPECT_TRUE(aom_img_get_metadata(&image, 1u) == NULL); + EXPECT_TRUE(aom_img_get_metadata(&image, 10u) == NULL); + + const aom_metadata_t *metadata = aom_img_get_metadata(&image, 0); + ASSERT_TRUE(metadata != NULL); + ASSERT_EQ(metadata->sz, kMetadataPayloadSizeT35); + EXPECT_EQ( + memcmp(kMetadataPayloadT35, metadata->payload, kMetadataPayloadSizeT35), + 0); + + aom_img_metadata_array_free(image.metadata); +} + +TEST(MetadataTest, ReadMetadatasFromImage) { + aom_image_t image; + image.metadata = NULL; + + uint32_t types[3]; + types[0] = OBU_METADATA_TYPE_ITUT_T35; + types[1] = OBU_METADATA_TYPE_HDR_CLL; + types[2] = OBU_METADATA_TYPE_HDR_MDCV; + + ASSERT_EQ(aom_img_add_metadata(&image, types[0], kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_ANY_FRAME), + 0); + ASSERT_EQ(aom_img_add_metadata(&image, types[1], kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_KEY_FRAME), + 0); + ASSERT_EQ(aom_img_add_metadata(&image, types[2], kMetadataPayloadT35, + kMetadataPayloadSizeT35, AOM_MIF_KEY_FRAME), + 0); + + size_t number_metadata = aom_img_num_metadata(&image); + ASSERT_EQ(number_metadata, 3u); + for (size_t i = 0; i < number_metadata; ++i) { + const aom_metadata_t *metadata = aom_img_get_metadata(&image, i); + ASSERT_TRUE(metadata != NULL); + ASSERT_EQ(metadata->type, types[i]); + ASSERT_EQ(metadata->sz, kMetadataPayloadSizeT35); + EXPECT_EQ( + memcmp(kMetadataPayloadT35, metadata->payload, kMetadataPayloadSizeT35), + 0); + } + aom_img_metadata_array_free(image.metadata); +} diff --git a/media/libaom/src/test/noise_model_test.cc b/media/libaom/src/test/noise_model_test.cc index b5b387e313..5b61236f0b 100644 --- a/media/libaom/src/test/noise_model_test.cc +++ b/media/libaom/src/test/noise_model_test.cc @@ -343,7 +343,7 @@ class FlatBlockEstimatorTest : public ::testing::Test, public T { libaom_test::ACMRandom random_; }; -TYPED_TEST_CASE_P(FlatBlockEstimatorTest); +TYPED_TEST_SUITE_P(FlatBlockEstimatorTest); TYPED_TEST_P(FlatBlockEstimatorTest, ExtractBlock) { const int kBlockSize = 16; @@ -494,16 +494,16 @@ TYPED_TEST_P(FlatBlockEstimatorTest, FindFlatBlocks) { aom_flat_block_finder_free(&flat_block_finder); } -REGISTER_TYPED_TEST_CASE_P(FlatBlockEstimatorTest, ExtractBlock, - FindFlatBlocks); +REGISTER_TYPED_TEST_SUITE_P(FlatBlockEstimatorTest, ExtractBlock, + FindFlatBlocks); typedef ::testing::Types, // lowbd BitDepthParams, // lowbd in 16-bit BitDepthParams, // highbd data BitDepthParams > AllBitDepthParams; -INSTANTIATE_TYPED_TEST_CASE_P(FlatBlockInstatiation, FlatBlockEstimatorTest, - AllBitDepthParams); +INSTANTIATE_TYPED_TEST_SUITE_P(FlatBlockInstatiation, FlatBlockEstimatorTest, + AllBitDepthParams); template class NoiseModelUpdateTest : public ::testing::Test, public T { @@ -570,7 +570,7 @@ class NoiseModelUpdateTest : public ::testing::Test, public T { uint8_t *denoised_ptr_raw_[3]; }; -TYPED_TEST_CASE_P(NoiseModelUpdateTest); +TYPED_TEST_SUITE_P(NoiseModelUpdateTest); TYPED_TEST_P(NoiseModelUpdateTest, UpdateFailsNoFlatBlocks) { EXPECT_EQ(AOM_NOISE_STATUS_INSUFFICIENT_FLAT_BLOCKS, @@ -929,17 +929,17 @@ TYPED_TEST_P(NoiseModelUpdateTest, NoiseCoeffsSignalsDifferentNoiseType) { } EXPECT_EQ(AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE, this->NoiseModelUpdate()); } -REGISTER_TYPED_TEST_CASE_P(NoiseModelUpdateTest, UpdateFailsNoFlatBlocks, - UpdateSuccessForZeroNoiseAllFlat, - UpdateFailsBlockSizeTooSmall, - UpdateSuccessForWhiteRandomNoise, - UpdateSuccessForScaledWhiteNoise, - UpdateSuccessForCorrelatedNoise, - NoiseStrengthChangeSignalsDifferentNoiseType, - NoiseCoeffsSignalsDifferentNoiseType); +REGISTER_TYPED_TEST_SUITE_P(NoiseModelUpdateTest, UpdateFailsNoFlatBlocks, + UpdateSuccessForZeroNoiseAllFlat, + UpdateFailsBlockSizeTooSmall, + UpdateSuccessForWhiteRandomNoise, + UpdateSuccessForScaledWhiteNoise, + UpdateSuccessForCorrelatedNoise, + NoiseStrengthChangeSignalsDifferentNoiseType, + NoiseCoeffsSignalsDifferentNoiseType); -INSTANTIATE_TYPED_TEST_CASE_P(NoiseModelUpdateTestInstatiation, - NoiseModelUpdateTest, AllBitDepthParams); +INSTANTIATE_TYPED_TEST_SUITE_P(NoiseModelUpdateTestInstatiation, + NoiseModelUpdateTest, AllBitDepthParams); TEST(NoiseModelGetGrainParameters, TestLagSize) { aom_film_grain_t film_grain; @@ -1229,7 +1229,7 @@ class WienerDenoiseTest : public ::testing::Test, public T { int stride_[3]; }; -TYPED_TEST_CASE_P(WienerDenoiseTest); +TYPED_TEST_SUITE_P(WienerDenoiseTest); TYPED_TEST_P(WienerDenoiseTest, InvalidBlockSize) { const uint8_t *const data_ptrs[3] = { @@ -1336,8 +1336,8 @@ TYPED_TEST_P(WienerDenoiseTest, GradientTest) { } } -REGISTER_TYPED_TEST_CASE_P(WienerDenoiseTest, InvalidBlockSize, - InvalidChromaSubsampling, GradientTest); +REGISTER_TYPED_TEST_SUITE_P(WienerDenoiseTest, InvalidBlockSize, + InvalidChromaSubsampling, GradientTest); -INSTANTIATE_TYPED_TEST_CASE_P(WienerDenoiseTestInstatiation, WienerDenoiseTest, - AllBitDepthParams); +INSTANTIATE_TYPED_TEST_SUITE_P(WienerDenoiseTestInstatiation, WienerDenoiseTest, + AllBitDepthParams); diff --git a/media/libaom/src/test/obmc_sad_test.cc b/media/libaom/src/test/obmc_sad_test.cc index 75d7cda5a7..6b4382cd7f 100644 --- a/media/libaom/src/test/obmc_sad_test.cc +++ b/media/libaom/src/test/obmc_sad_test.cc @@ -111,8 +111,8 @@ const ObmcSadTest::ParamType sse4_functions[] = { TestFuncs(aom_obmc_sad4x16_c, aom_obmc_sad4x16_sse4_1), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, ObmcSadTest, - ::testing::ValuesIn(sse4_functions)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, ObmcSadTest, + ::testing::ValuesIn(sse4_functions)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -142,7 +142,8 @@ const ObmcSadTest::ParamType avx2_functions[] = { TestFuncs(aom_obmc_sad4x16_c, aom_obmc_sad4x16_avx2), }; -INSTANTIATE_TEST_CASE_P(AVX2, ObmcSadTest, ::testing::ValuesIn(avx2_functions)); +INSTANTIATE_TEST_SUITE_P(AVX2, ObmcSadTest, + ::testing::ValuesIn(avx2_functions)); #endif // HAVE_AVX2 #if CONFIG_AV1_HIGHBITDEPTH @@ -229,8 +230,8 @@ ObmcSadHBDTest::ParamType sse4_functions_hbd[] = { TestFuncs(aom_highbd_obmc_sad4x16_c, aom_highbd_obmc_sad4x16_sse4_1), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, ObmcSadHBDTest, - ::testing::ValuesIn(sse4_functions_hbd)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, ObmcSadHBDTest, + ::testing::ValuesIn(sse4_functions_hbd)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -260,8 +261,8 @@ ObmcSadHBDTest::ParamType avx2_functions_hbd[] = { TestFuncs(aom_highbd_obmc_sad4x16_c, aom_highbd_obmc_sad4x16_avx2), }; -INSTANTIATE_TEST_CASE_P(AVX2, ObmcSadHBDTest, - ::testing::ValuesIn(avx2_functions_hbd)); +INSTANTIATE_TEST_SUITE_P(AVX2, ObmcSadHBDTest, + ::testing::ValuesIn(avx2_functions_hbd)); #endif // HAVE_AVX2 #endif // CONFIG_AV1_HIGHBITDEPTH } // namespace diff --git a/media/libaom/src/test/obmc_variance_test.cc b/media/libaom/src/test/obmc_variance_test.cc index da4bd9635d..fc281d70b9 100644 --- a/media/libaom/src/test/obmc_variance_test.cc +++ b/media/libaom/src/test/obmc_variance_test.cc @@ -157,8 +157,8 @@ const ObmcVarianceTest::ParamType sse4_functions[] = { TestFuncs(aom_obmc_variance4x16_c, aom_obmc_variance4x16_sse4_1), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, ObmcVarianceTest, - ::testing::ValuesIn(sse4_functions)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, ObmcVarianceTest, + ::testing::ValuesIn(sse4_functions)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -188,8 +188,8 @@ const ObmcVarianceTest::ParamType avx2_functions[] = { TestFuncs(aom_obmc_variance4x16_c, aom_obmc_variance4x16_avx2), }; -INSTANTIATE_TEST_CASE_P(AVX2, ObmcVarianceTest, - ::testing::ValuesIn(avx2_functions)); +INSTANTIATE_TEST_SUITE_P(AVX2, ObmcVarianceTest, + ::testing::ValuesIn(avx2_functions)); #endif // HAVE_AVX2 //////////////////////////////////////////////////////////////////////////////// @@ -390,8 +390,8 @@ ObmcVarianceHBDTest::ParamType sse4_functions_hbd[] = { aom_highbd_12_obmc_variance4x16_sse4_1, 12), }; -INSTANTIATE_TEST_CASE_P(SSE4_1, ObmcVarianceHBDTest, - ::testing::ValuesIn(sse4_functions_hbd)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, ObmcVarianceHBDTest, + ::testing::ValuesIn(sse4_functions_hbd)); #endif // HAVE_SSE4_1 #endif // CONFIG_AV1_HIGHBITDEPTH } // namespace diff --git a/media/libaom/src/test/pickrst_test.cc b/media/libaom/src/test/pickrst_test.cc index 09b4aa164d..9a2c5bcd40 100644 --- a/media/libaom/src/test/pickrst_test.cc +++ b/media/libaom/src/test/pickrst_test.cc @@ -9,6 +9,8 @@ * 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/register_state_check.h" @@ -36,8 +38,7 @@ typedef int64_t (*lowbd_pixel_proj_error_func)( // 8 bit //////////////////////////////////////////////////////////////////////////////// -typedef ::testing::tuple - PixelProjErrorTestParam; +typedef std::tuple PixelProjErrorTestParam; class PixelProjErrorTest : public ::testing::TestWithParam { @@ -177,14 +178,14 @@ TEST_P(PixelProjErrorTest, ExtremeValues) { TEST_P(PixelProjErrorTest, DISABLED_Speed) { RunPixelProjErrorTest(200000); } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, PixelProjErrorTest, - ::testing::Values(av1_lowbd_pixel_proj_error_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, PixelProjErrorTest, + ::testing::Values(av1_lowbd_pixel_proj_error_sse4_1)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, PixelProjErrorTest, - ::testing::Values(av1_lowbd_pixel_proj_error_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, PixelProjErrorTest, + ::testing::Values(av1_lowbd_pixel_proj_error_avx2)); #endif // HAVE_AVX2 } // namespace pickrst_test_lowbd @@ -202,8 +203,7 @@ typedef int64_t (*highbd_pixel_proj_error_func)( // High bit-depth //////////////////////////////////////////////////////////////////////////////// -typedef ::testing::tuple - PixelProjErrorTestParam; +typedef std::tuple PixelProjErrorTestParam; class PixelProjHighbdErrorTest : public ::testing::TestWithParam { @@ -345,14 +345,14 @@ TEST_P(PixelProjHighbdErrorTest, DISABLED_Speed) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, PixelProjHighbdErrorTest, - ::testing::Values(av1_highbd_pixel_proj_error_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, PixelProjHighbdErrorTest, + ::testing::Values(av1_highbd_pixel_proj_error_sse4_1)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, PixelProjHighbdErrorTest, - ::testing::Values(av1_highbd_pixel_proj_error_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, PixelProjHighbdErrorTest, + ::testing::Values(av1_highbd_pixel_proj_error_avx2)); #endif // HAVE_AVX2 } // namespace pickrst_test_highbd @@ -372,7 +372,7 @@ typedef void (*set_get_proj_subspace)(const uint8_t *src8, int width, int64_t H[2][2], int64_t C[2], const sgr_params_type *params); -typedef ::testing::tuple GetProjSubspaceTestParam; +typedef std::tuple GetProjSubspaceTestParam; class GetProjSubspaceTest : public ::testing::TestWithParam { @@ -526,8 +526,8 @@ TEST_P(GetProjSubspaceTest, DISABLED_Speed) { RunGetProjSubspaceTest(200000); } #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, GetProjSubspaceTest, - ::testing::Values(av1_calc_proj_params_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, GetProjSubspaceTest, + ::testing::Values(av1_calc_proj_params_avx2)); #endif // HAVE_AVX2 } // namespace get_proj_subspace_test_lowbd diff --git a/media/libaom/src/test/quantize_func_test.cc b/media/libaom/src/test/quantize_func_test.cc index d5b3b1f962..b40b38d5a2 100644 --- a/media/libaom/src/test/quantize_func_test.cc +++ b/media/libaom/src/test/quantize_func_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/aom_config.h" @@ -65,7 +67,7 @@ void highbd_quan64x64_wrapper(QUAN_PARAM_LIST) { enum QuantType { TYPE_B, TYPE_DC, TYPE_FP }; -using ::testing::tuple; +using std::tuple; typedef tuple QuantizeParam; @@ -323,7 +325,7 @@ TEST_P(QuantizeTest, DISABLED_Speed) { } } -using ::testing::make_tuple; +using std::make_tuple; #if HAVE_AVX2 const QuantizeParam kQParamArrayAvx2[] = { @@ -406,8 +408,8 @@ const QuantizeParam kQParamArrayAvx2[] = { static_cast(TX_4X4), TYPE_B, AOM_BITS_8) }; -INSTANTIATE_TEST_CASE_P(AVX2, QuantizeTest, - ::testing::ValuesIn(kQParamArrayAvx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, QuantizeTest, + ::testing::ValuesIn(kQParamArrayAvx2)); #endif // HAVE_AVX2 #if HAVE_SSE2 @@ -497,8 +499,8 @@ const QuantizeParam kQParamArraySSE2[] = { static_cast(TX_64X64), TYPE_B, AOM_BITS_8) }; -INSTANTIATE_TEST_CASE_P(SSE2, QuantizeTest, - ::testing::ValuesIn(kQParamArraySSE2)); +INSTANTIATE_TEST_SUITE_P(SSE2, QuantizeTest, + ::testing::ValuesIn(kQParamArraySSE2)); #endif #if HAVE_NEON @@ -515,12 +517,12 @@ const QuantizeParam kQParamArrayNEON[] = { static_cast(TX_32X8), TYPE_FP, AOM_BITS_8) }; -INSTANTIATE_TEST_CASE_P(NEON, QuantizeTest, - ::testing::ValuesIn(kQParamArrayNEON)); +INSTANTIATE_TEST_SUITE_P(NEON, QuantizeTest, + ::testing::ValuesIn(kQParamArrayNEON)); #endif #if HAVE_SSSE3 && ARCH_X86_64 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, QuantizeTest, ::testing::Values( make_tuple(&aom_quantize_b_c, &aom_quantize_b_ssse3, @@ -533,7 +535,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSSE3 && ARCH_X86_64 #if HAVE_AVX && ARCH_X86_64 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX, QuantizeTest, ::testing::Values( make_tuple(&aom_quantize_b_c, &aom_quantize_b_avx, diff --git a/media/libaom/src/test/reconinter_test.cc b/media/libaom/src/test/reconinter_test.cc index a8536e517c..51bec0eab7 100644 --- a/media/libaom/src/test/reconinter_test.cc +++ b/media/libaom/src/test/reconinter_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "config/aom_config.h" #include "config/av1_rtcd.h" @@ -34,7 +35,7 @@ typedef void (*buildcompdiffwtdmaskd_func)(uint8_t *mask, const uint8_t *src1, int src1_stride, int h, int w); -typedef ::testing::tuple +typedef std::tuple BuildCompDiffwtdMaskDParam; #if HAVE_SSE4_1 @@ -63,7 +64,7 @@ typedef void (*buildcompdiffwtdmaskd16_func)( int src0_stride, const CONV_BUF_TYPE *src1, int src1_stride, int h, int w, ConvolveParams *conv_params, int bd); -typedef ::testing::tuple +typedef std::tuple BuildCompDiffwtdMaskD16Param; #if HAVE_SSE4_1 || HAVE_NEON @@ -234,25 +235,25 @@ TEST_P(BuildCompDiffwtdMaskD16Test, DISABLED_Speed) { } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, BuildCompDiffwtdMaskTest, - BuildParams(av1_build_compound_diffwtd_mask_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, BuildCompDiffwtdMaskTest, + BuildParams(av1_build_compound_diffwtd_mask_sse4_1)); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, BuildCompDiffwtdMaskD16Test, BuildParams(av1_build_compound_diffwtd_mask_d16_sse4_1)); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, BuildCompDiffwtdMaskTest, - BuildParams(av1_build_compound_diffwtd_mask_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, BuildCompDiffwtdMaskTest, + BuildParams(av1_build_compound_diffwtd_mask_avx2)); -INSTANTIATE_TEST_CASE_P(AVX2, BuildCompDiffwtdMaskD16Test, - BuildParams(av1_build_compound_diffwtd_mask_d16_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, BuildCompDiffwtdMaskD16Test, + BuildParams(av1_build_compound_diffwtd_mask_d16_avx2)); #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, BuildCompDiffwtdMaskD16Test, - BuildParams(av1_build_compound_diffwtd_mask_d16_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, BuildCompDiffwtdMaskD16Test, + BuildParams(av1_build_compound_diffwtd_mask_d16_neon)); #endif } // namespace diff --git a/media/libaom/src/test/rt_end_to_end_test.cc b/media/libaom/src/test/rt_end_to_end_test.cc index 9be3db719c..f14d124741 100644 --- a/media/libaom/src/test/rt_end_to_end_test.cc +++ b/media/libaom/src/test/rt_end_to_end_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -31,17 +32,20 @@ const int kBitrate = 500; std::unordered_map>> kPsnrThreshold = { { "park_joy_90p_8_420.y4m", - { { 6, { { 0, 35.5 }, { 3, 36.3 } } }, + { { 5, { { 0, 35.4 }, { 3, 36.4 } } }, + { 6, { { 0, 35.3 }, { 3, 36.2 } } }, { 7, { { 0, 34.9 }, { 3, 35.8 } } }, - { 8, { { 0, 35.0 }, { 3, 36.0 } } } } }, + { 8, { { 0, 35.0 }, { 3, 35.8 } } } } }, { "paris_352_288_30.y4m", - { { 6, { { 0, 36.4 }, { 3, 36.7 } } }, + { { 5, { { 0, 36.2 }, { 3, 36.7 } } }, + { 6, { { 0, 36.1 }, { 3, 36.6 } } }, { 7, { { 0, 35.5 }, { 3, 36.0 } } }, { 8, { { 0, 36.0 }, { 3, 36.5 } } } } }, { "niklas_1280_720_30.y4m", - { { 6, { { 0, 34.2 }, { 3, 34.2 } } }, - { 7, { { 0, 33.7 }, { 3, 34.0 } } }, - { 8, { { 0, 33.7 }, { 3, 33.7 } } } } } }; + { { 5, { { 0, 34.6 }, { 3, 34.6 } } }, + { 6, { { 0, 34.2 }, { 3, 34.2 } } }, + { 7, { { 0, 33.7 }, { 3, 33.6 } } }, + { 8, { { 0, 33.6 }, { 3, 33.4 } } } } } }; typedef struct { const char *filename; @@ -55,7 +59,7 @@ 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 << "}"; + << " profile:" << test_arg.profile << " }"; } const TestVideoParam kTestVectors[] = { @@ -158,13 +162,13 @@ TEST_P(RTEndToEndTest, EndtoEndPSNRTest) { DoTest(); } TEST_P(RTEndToEndTestThreaded, EndtoEndPSNRTest) { DoTest(); } AV1_INSTANTIATE_TEST_CASE(RTEndToEndTest, ::testing::ValuesIn(kTestVectors), - ::testing::Range(6, 9), + ::testing::Range(5, 9), ::testing::Values(0, 3), ::testing::Values(1), ::testing::Values(1)); AV1_INSTANTIATE_TEST_CASE(RTEndToEndTestThreaded, ::testing::ValuesIn(kTestVectors), - ::testing::Range(6, 9), + ::testing::Range(5, 9), ::testing::Values(0, 3), ::testing::Range(2, 5), ::testing::Range(2, 5)); } // namespace diff --git a/media/libaom/src/test/sad_test.cc b/media/libaom/src/test/sad_test.cc index 960a95e0e5..0bdbf37452 100644 --- a/media/libaom/src/test/sad_test.cc +++ b/media/libaom/src/test/sad_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -28,37 +29,42 @@ typedef unsigned int (*SadMxNFunc)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); -typedef ::testing::tuple SadMxNParam; +typedef std::tuple SadMxNParam; typedef uint32_t (*SadMxNAvgFunc)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred); -typedef ::testing::tuple SadMxNAvgParam; +typedef std::tuple SadMxNAvgParam; typedef void (*DistWtdCompAvgFunc)(uint8_t *comp_pred, const uint8_t *pred, int width, int height, const uint8_t *ref, int ref_stride, const DIST_WTD_COMP_PARAMS *jcp_param); -typedef ::testing::tuple DistWtdCompAvgParam; +typedef std::tuple DistWtdCompAvgParam; typedef unsigned int (*DistWtdSadMxhFunc)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, int width, int height); -typedef ::testing::tuple DistWtdSadMxhParam; +typedef std::tuple DistWtdSadMxhParam; typedef uint32_t (*DistWtdSadMxNAvgFunc)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred, const DIST_WTD_COMP_PARAMS *jcp_param); -typedef ::testing::tuple - DistWtdSadMxNAvgParam; +typedef std::tuple DistWtdSadMxNAvgParam; typedef void (*SadMxNx4Func)(const uint8_t *src_ptr, int src_stride, const uint8_t *const ref_ptr[], int ref_stride, uint32_t *sad_array); -typedef ::testing::tuple SadMxNx4Param; +typedef std::tuple SadMxNx4Param; + +typedef void (*SadMxNx4AvgFunc)(const uint8_t *src_ptr, int src_stride, + const uint8_t *const ref_ptr[], int ref_stride, + const uint8_t *second_pred, + uint32_t *sad_array); +typedef std::tuple SadMxNx4AvgParam; using libaom_test::ACMRandom; @@ -339,6 +345,42 @@ class SADx4Test : public ::testing::WithParamInterface, } }; +class SADx4AvgTest : public ::testing::WithParamInterface, + public SADTestBase { + public: + SADx4AvgTest() : SADTestBase(GET_PARAM(0), GET_PARAM(1), GET_PARAM(3)) {} + + protected: + void SADs(unsigned int *results) { + const uint8_t *references[] = { GetReference(0), GetReference(1), + GetReference(2), GetReference(3) }; + + ASM_REGISTER_STATE_CHECK(GET_PARAM(2)(source_data_, source_stride_, + references, reference_stride_, + second_pred_, results)); + } + + void CheckSADs() { + unsigned int reference_sad, exp_sad[4]; + + SADs(exp_sad); + for (int block = 0; block < 4; ++block) { + reference_sad = ReferenceSADavg(block); + + EXPECT_EQ(reference_sad, exp_sad[block]) << "block " << block; + } + } + + void SpeedSAD() { + int test_count = 200000; + unsigned int exp_sad[4]; + while (test_count > 0) { + SADs(exp_sad); + test_count -= 1; + } + } +}; + class SADTest : public ::testing::WithParamInterface, public SADTestBase { public: @@ -812,7 +854,70 @@ TEST_P(SADx4Test, SrcAlignedByWidth) { source_data_ = tmp_source_data; } -using ::testing::make_tuple; +using std::make_tuple; + +#if SPEED_TEST +TEST_P(SADx4AvgTest, Speed) { + int tmp_stride = reference_stride_; + reference_stride_ >>= 1; + FillRandom(source_data_, source_stride_); + FillRandom(GetReference(0), reference_stride_); + FillRandom(GetReference(1), reference_stride_); + FillRandom(GetReference(2), reference_stride_); + FillRandom(GetReference(3), reference_stride_); + FillRandom(second_pred_, width_); + SpeedSAD(); + reference_stride_ = tmp_stride; +} +#endif + +TEST_P(SADx4AvgTest, MaxRef) { + FillConstant(source_data_, source_stride_, 0); + FillConstant(GetReference(0), reference_stride_, mask_); + FillConstant(GetReference(1), reference_stride_, mask_); + FillConstant(GetReference(2), reference_stride_, mask_); + FillConstant(GetReference(3), reference_stride_, mask_); + FillConstant(second_pred_, width_, 0); + CheckSADs(); +} + +TEST_P(SADx4AvgTest, MaxSrc) { + FillConstant(source_data_, source_stride_, mask_); + FillConstant(GetReference(0), reference_stride_, 0); + FillConstant(GetReference(1), reference_stride_, 0); + FillConstant(GetReference(2), reference_stride_, 0); + FillConstant(GetReference(3), reference_stride_, 0); + FillConstant(second_pred_, width_, 0); + CheckSADs(); +} + +TEST_P(SADx4AvgTest, ShortRef) { + int tmp_stride = reference_stride_; + reference_stride_ >>= 1; + FillRandom(source_data_, source_stride_); + FillRandom(GetReference(0), reference_stride_); + FillRandom(GetReference(1), reference_stride_); + FillRandom(GetReference(2), reference_stride_); + FillRandom(GetReference(3), reference_stride_); + FillRandom(second_pred_, width_); + CheckSADs(); + reference_stride_ = tmp_stride; +} + +TEST_P(SADx4AvgTest, UnalignedRef) { + // The reference frame, but not the source frame, may be unaligned for + // certain types of searches. + int tmp_stride = reference_stride_; + reference_stride_ -= 1; + FillRandom(source_data_, source_stride_); + FillRandom(GetReference(0), reference_stride_); + FillRandom(GetReference(1), reference_stride_); + FillRandom(GetReference(2), reference_stride_); + FillRandom(GetReference(3), reference_stride_); + FillRandom(second_pred_, width_); + CheckSADs(); + reference_stride_ = tmp_stride; +} //------------------------------------------------------------------------------ // C functions @@ -914,7 +1019,7 @@ const SadMxNParam c_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16_c, 12), #endif }; -INSTANTIATE_TEST_CASE_P(C, SADTest, ::testing::ValuesIn(c_tests)); +INSTANTIATE_TEST_SUITE_P(C, SADTest, ::testing::ValuesIn(c_tests)); const SadMxNAvgParam avg_c_tests[] = { make_tuple(128, 128, &aom_sad128x128_avg_c, -1), @@ -1014,7 +1119,7 @@ const SadMxNAvgParam avg_c_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16_avg_c, 12), #endif }; -INSTANTIATE_TEST_CASE_P(C, SADavgTest, ::testing::ValuesIn(avg_c_tests)); +INSTANTIATE_TEST_SUITE_P(C, SADavgTest, ::testing::ValuesIn(avg_c_tests)); // TODO(chengchen): add highbd tests const DistWtdCompAvgParam dist_wtd_comp_avg_c_tests[] = { @@ -1043,8 +1148,8 @@ const DistWtdCompAvgParam dist_wtd_comp_avg_c_tests[] = { make_tuple(4, 16, &aom_dist_wtd_comp_avg_pred_c, -1), }; -INSTANTIATE_TEST_CASE_P(C, DistWtdCompAvgTest, - ::testing::ValuesIn(dist_wtd_comp_avg_c_tests)); +INSTANTIATE_TEST_SUITE_P(C, DistWtdCompAvgTest, + ::testing::ValuesIn(dist_wtd_comp_avg_c_tests)); const DistWtdSadMxNAvgParam dist_wtd_avg_c_tests[] = { make_tuple(128, 128, &aom_dist_wtd_sad128x128_avg_c, -1), @@ -1072,8 +1177,8 @@ const DistWtdSadMxNAvgParam dist_wtd_avg_c_tests[] = { make_tuple(4, 16, &aom_dist_wtd_sad4x16_avg_c, -1), }; -INSTANTIATE_TEST_CASE_P(C, DistWtdSADavgTest, - ::testing::ValuesIn(dist_wtd_avg_c_tests)); +INSTANTIATE_TEST_SUITE_P(C, DistWtdSADavgTest, + ::testing::ValuesIn(dist_wtd_avg_c_tests)); const SadMxNx4Param x4d_c_tests[] = { make_tuple(128, 128, &aom_sad128x128x4d_c, -1), @@ -1173,7 +1278,33 @@ const SadMxNx4Param x4d_c_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16x4d_c, 12), #endif }; -INSTANTIATE_TEST_CASE_P(C, SADx4Test, ::testing::ValuesIn(x4d_c_tests)); +INSTANTIATE_TEST_SUITE_P(C, SADx4Test, ::testing::ValuesIn(x4d_c_tests)); + +const SadMxNx4AvgParam x4d_avg_c_tests[] = { + make_tuple(128, 128, &aom_sad128x128x4d_avg_c, -1), + make_tuple(128, 64, &aom_sad128x64x4d_avg_c, -1), + make_tuple(64, 128, &aom_sad64x128x4d_avg_c, -1), + make_tuple(64, 64, &aom_sad64x64x4d_avg_c, -1), + make_tuple(64, 32, &aom_sad64x32x4d_avg_c, -1), + make_tuple(32, 64, &aom_sad32x64x4d_avg_c, -1), + make_tuple(32, 32, &aom_sad32x32x4d_avg_c, -1), + make_tuple(32, 16, &aom_sad32x16x4d_avg_c, -1), + make_tuple(16, 32, &aom_sad16x32x4d_avg_c, -1), + make_tuple(16, 16, &aom_sad16x16x4d_avg_c, -1), + make_tuple(16, 8, &aom_sad16x8x4d_avg_c, -1), + make_tuple(8, 16, &aom_sad8x16x4d_avg_c, -1), + make_tuple(8, 8, &aom_sad8x8x4d_avg_c, -1), + make_tuple(8, 4, &aom_sad8x4x4d_avg_c, -1), + make_tuple(4, 8, &aom_sad4x8x4d_avg_c, -1), + make_tuple(4, 4, &aom_sad4x4x4d_avg_c, -1), + make_tuple(64, 16, &aom_sad64x16x4d_avg_c, -1), + make_tuple(16, 64, &aom_sad16x64x4d_avg_c, -1), + make_tuple(32, 8, &aom_sad32x8x4d_avg_c, -1), + make_tuple(8, 32, &aom_sad8x32x4d_avg_c, -1), + make_tuple(16, 4, &aom_sad16x4x4d_avg_c, -1), + make_tuple(4, 16, &aom_sad4x16x4d_avg_c, -1), +}; +INSTANTIATE_TEST_SUITE_P(C, SADx4AvgTest, ::testing::ValuesIn(x4d_avg_c_tests)); //------------------------------------------------------------------------------ // ARM functions @@ -1187,14 +1318,14 @@ const SadMxNParam neon_tests[] = { make_tuple(8, 8, &aom_sad8x8_neon, -1), make_tuple(4, 4, &aom_sad4x4_neon, -1), }; -INSTANTIATE_TEST_CASE_P(NEON, SADTest, ::testing::ValuesIn(neon_tests)); +INSTANTIATE_TEST_SUITE_P(NEON, SADTest, ::testing::ValuesIn(neon_tests)); const SadMxNx4Param x4d_neon_tests[] = { make_tuple(64, 64, &aom_sad64x64x4d_neon, -1), make_tuple(32, 32, &aom_sad32x32x4d_neon, -1), make_tuple(16, 16, &aom_sad16x16x4d_neon, -1), }; -INSTANTIATE_TEST_CASE_P(NEON, SADx4Test, ::testing::ValuesIn(x4d_neon_tests)); +INSTANTIATE_TEST_SUITE_P(NEON, SADx4Test, ::testing::ValuesIn(x4d_neon_tests)); #endif // HAVE_NEON //------------------------------------------------------------------------------ @@ -1289,7 +1420,7 @@ const SadMxNParam sse2_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16_sse2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(SSE2, SADTest, ::testing::ValuesIn(sse2_tests)); +INSTANTIATE_TEST_SUITE_P(SSE2, SADTest, ::testing::ValuesIn(sse2_tests)); const SadMxNAvgParam avg_sse2_tests[] = { make_tuple(128, 128, &aom_sad128x128_avg_sse2, -1), @@ -1380,7 +1511,7 @@ const SadMxNAvgParam avg_sse2_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16_avg_sse2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(SSE2, SADavgTest, ::testing::ValuesIn(avg_sse2_tests)); +INSTANTIATE_TEST_SUITE_P(SSE2, SADavgTest, ::testing::ValuesIn(avg_sse2_tests)); const SadMxNx4Param x4d_sse2_tests[] = { make_tuple(128, 128, &aom_sad128x128x4d_sse2, -1), @@ -1471,7 +1602,34 @@ const SadMxNx4Param x4d_sse2_tests[] = { make_tuple(4, 16, &aom_highbd_sad4x16x4d_sse2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(SSE2, SADx4Test, ::testing::ValuesIn(x4d_sse2_tests)); +INSTANTIATE_TEST_SUITE_P(SSE2, SADx4Test, ::testing::ValuesIn(x4d_sse2_tests)); + +const SadMxNx4AvgParam x4d_avg_sse2_tests[] = { + make_tuple(128, 128, &aom_sad128x128x4d_avg_sse2, -1), + make_tuple(128, 64, &aom_sad128x64x4d_avg_sse2, -1), + make_tuple(64, 128, &aom_sad64x128x4d_avg_sse2, -1), + make_tuple(64, 64, &aom_sad64x64x4d_avg_sse2, -1), + make_tuple(64, 32, &aom_sad64x32x4d_avg_sse2, -1), + make_tuple(32, 64, &aom_sad32x64x4d_avg_sse2, -1), + make_tuple(32, 32, &aom_sad32x32x4d_avg_sse2, -1), + make_tuple(32, 16, &aom_sad32x16x4d_avg_sse2, -1), + make_tuple(16, 32, &aom_sad16x32x4d_avg_sse2, -1), + make_tuple(16, 16, &aom_sad16x16x4d_avg_sse2, -1), + make_tuple(16, 8, &aom_sad16x8x4d_avg_sse2, -1), + make_tuple(8, 16, &aom_sad8x16x4d_avg_sse2, -1), + make_tuple(8, 8, &aom_sad8x8x4d_avg_sse2, -1), + make_tuple(8, 4, &aom_sad8x4x4d_avg_sse2, -1), + make_tuple(4, 8, &aom_sad4x8x4d_avg_sse2, -1), + make_tuple(4, 4, &aom_sad4x4x4d_avg_sse2, -1), + make_tuple(64, 16, &aom_sad64x16x4d_avg_sse2, -1), + make_tuple(16, 64, &aom_sad16x64x4d_avg_sse2, -1), + make_tuple(32, 8, &aom_sad32x8x4d_avg_sse2, -1), + make_tuple(8, 32, &aom_sad8x32x4d_avg_sse2, -1), + make_tuple(16, 4, &aom_sad16x4x4d_avg_sse2, -1), + make_tuple(4, 16, &aom_sad4x16x4d_avg_sse2, -1), +}; +INSTANTIATE_TEST_SUITE_P(SSE2, SADx4AvgTest, + ::testing::ValuesIn(x4d_avg_sse2_tests)); #endif // HAVE_SSE2 #if HAVE_SSSE3 @@ -1508,8 +1666,8 @@ const DistWtdSadMxhParam dist_wtd_sad_sse2_tests[] = { make_tuple(4, 16, &aom_sad4xh_sse2, -1), make_tuple(16, 4, &aom_sad16xh_sse2, -1), }; -INSTANTIATE_TEST_CASE_P(SSE2, DistWtdSADTest, - ::testing::ValuesIn(dist_wtd_sad_sse2_tests)); +INSTANTIATE_TEST_SUITE_P(SSE2, DistWtdSADTest, + ::testing::ValuesIn(dist_wtd_sad_sse2_tests)); #endif // HAVE_SSSE3 @@ -1545,8 +1703,8 @@ const DistWtdCompAvgParam dist_wtd_comp_avg_ssse3_tests[] = { make_tuple(4, 16, &aom_dist_wtd_comp_avg_pred_ssse3, -1), }; -INSTANTIATE_TEST_CASE_P(SSSE3, DistWtdCompAvgTest, - ::testing::ValuesIn(dist_wtd_comp_avg_ssse3_tests)); +INSTANTIATE_TEST_SUITE_P(SSSE3, DistWtdCompAvgTest, + ::testing::ValuesIn(dist_wtd_comp_avg_ssse3_tests)); const DistWtdSadMxNAvgParam dist_wtd_avg_ssse3_tests[] = { make_tuple(128, 128, &aom_dist_wtd_sad128x128_avg_ssse3, -1), @@ -1573,8 +1731,8 @@ const DistWtdSadMxNAvgParam dist_wtd_avg_ssse3_tests[] = { make_tuple(16, 4, &aom_dist_wtd_sad16x4_avg_ssse3, -1), make_tuple(4, 16, &aom_dist_wtd_sad4x16_avg_ssse3, -1), }; -INSTANTIATE_TEST_CASE_P(SSSE3, DistWtdSADavgTest, - ::testing::ValuesIn(dist_wtd_avg_ssse3_tests)); +INSTANTIATE_TEST_SUITE_P(SSSE3, DistWtdSADavgTest, + ::testing::ValuesIn(dist_wtd_avg_ssse3_tests)); #endif // HAVE_SSSE3 #if HAVE_SSE4_1 @@ -1640,7 +1798,7 @@ const SadMxNParam avx2_tests[] = { make_tuple(16, 4, &aom_highbd_sad16x4_avx2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(AVX2, SADTest, ::testing::ValuesIn(avx2_tests)); +INSTANTIATE_TEST_SUITE_P(AVX2, SADTest, ::testing::ValuesIn(avx2_tests)); const SadMxNAvgParam avg_avx2_tests[] = { make_tuple(64, 128, &aom_sad64x128_avg_avx2, -1), @@ -1700,16 +1858,19 @@ const SadMxNAvgParam avg_avx2_tests[] = { make_tuple(16, 4, &aom_highbd_sad16x4_avg_avx2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(AVX2, SADavgTest, ::testing::ValuesIn(avg_avx2_tests)); +INSTANTIATE_TEST_SUITE_P(AVX2, SADavgTest, ::testing::ValuesIn(avg_avx2_tests)); const SadMxNx4Param x4d_avx2_tests[] = { - make_tuple(64, 128, &aom_sad64x128x4d_avx2, -1), - make_tuple(128, 64, &aom_sad128x64x4d_avx2, -1), - make_tuple(128, 128, &aom_sad128x128x4d_avx2, -1), - make_tuple(64, 64, &aom_sad64x64x4d_avx2, -1), make_tuple(32, 64, &aom_sad32x64x4d_avx2, -1), - make_tuple(64, 32, &aom_sad64x32x4d_avx2, -1), make_tuple(32, 32, &aom_sad32x32x4d_avx2, -1), + make_tuple(32, 16, &aom_sad32x16x4d_avx2, -1), + make_tuple(32, 8, &aom_sad32x8x4d_avx2, -1), + make_tuple(64, 128, &aom_sad64x128x4d_avx2, -1), + make_tuple(64, 64, &aom_sad64x64x4d_avx2, -1), + make_tuple(64, 32, &aom_sad64x32x4d_avx2, -1), + make_tuple(64, 16, &aom_sad64x16x4d_avx2, -1), + make_tuple(128, 128, &aom_sad128x128x4d_avx2, -1), + make_tuple(128, 64, &aom_sad128x64x4d_avx2, -1), #if CONFIG_AV1_HIGHBITDEPTH make_tuple(128, 128, &aom_highbd_sad128x128x4d_avx2, 8), make_tuple(128, 128, &aom_highbd_sad128x128x4d_avx2, 10), @@ -1759,7 +1920,7 @@ const SadMxNx4Param x4d_avx2_tests[] = { make_tuple(16, 4, &aom_highbd_sad16x4x4d_avx2, 12), #endif }; -INSTANTIATE_TEST_CASE_P(AVX2, SADx4Test, ::testing::ValuesIn(x4d_avx2_tests)); +INSTANTIATE_TEST_SUITE_P(AVX2, SADx4Test, ::testing::ValuesIn(x4d_avx2_tests)); #endif // HAVE_AVX2 //------------------------------------------------------------------------------ @@ -1780,7 +1941,7 @@ const SadMxNParam msa_tests[] = { make_tuple(4, 8, &aom_sad4x8_msa, -1), make_tuple(4, 4, &aom_sad4x4_msa, -1), }; -INSTANTIATE_TEST_CASE_P(MSA, SADTest, ::testing::ValuesIn(msa_tests)); +INSTANTIATE_TEST_SUITE_P(MSA, SADTest, ::testing::ValuesIn(msa_tests)); const SadMxNAvgParam avg_msa_tests[] = { make_tuple(64, 64, &aom_sad64x64_avg_msa, -1), @@ -1797,7 +1958,7 @@ const SadMxNAvgParam avg_msa_tests[] = { make_tuple(4, 8, &aom_sad4x8_avg_msa, -1), make_tuple(4, 4, &aom_sad4x4_avg_msa, -1), }; -INSTANTIATE_TEST_CASE_P(MSA, SADavgTest, ::testing::ValuesIn(avg_msa_tests)); +INSTANTIATE_TEST_SUITE_P(MSA, SADavgTest, ::testing::ValuesIn(avg_msa_tests)); const SadMxNx4Param x4d_msa_tests[] = { make_tuple(64, 64, &aom_sad64x64x4d_msa, -1), @@ -1814,7 +1975,7 @@ const SadMxNx4Param x4d_msa_tests[] = { make_tuple(4, 8, &aom_sad4x8x4d_msa, -1), make_tuple(4, 4, &aom_sad4x4x4d_msa, -1), }; -INSTANTIATE_TEST_CASE_P(MSA, SADx4Test, ::testing::ValuesIn(x4d_msa_tests)); +INSTANTIATE_TEST_SUITE_P(MSA, SADx4Test, ::testing::ValuesIn(x4d_msa_tests)); #endif // HAVE_MSA } // namespace diff --git a/media/libaom/src/test/sb_multipass_test.cc b/media/libaom/src/test/sb_multipass_test.cc new file mode 100644 index 0000000000..0ca76ab85b --- /dev/null +++ b/media/libaom/src/test/sb_multipass_test.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020, 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 "third_party/googletest/src/googletest/include/gtest/gtest.h" +#include "test/codec_factory.h" +#include "test/encode_test_driver.h" +#include "test/md5_helper.h" +#include "test/util.h" +#include "test/yuv_video_source.h" + +namespace { +class AV1SBMultipassTest + : public ::libaom_test::CodecTestWith2Params, + public ::libaom_test::EncoderTest { + protected: + AV1SBMultipassTest() + : EncoderTest(GET_PARAM(0)), set_cpu_used_(GET_PARAM(1)), + row_mt_(GET_PARAM(2)) { + init_flags_ = AOM_CODEC_USE_PSNR; + aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t(); + cfg.w = 1280; + cfg.h = 720; + cfg.allow_lowbitdepth = 1; + decoder_ = codec_->CreateDecoder(cfg, 0); + if (decoder_->IsAV1()) { + decoder_->Control(AV1_SET_DECODE_TILE_ROW, -1); + decoder_->Control(AV1_SET_DECODE_TILE_COL, -1); + } + + size_enc_.clear(); + md5_dec_.clear(); + md5_enc_.clear(); + } + virtual ~AV1SBMultipassTest() { delete decoder_; } + + virtual void SetUp() { + InitializeConfig(); + SetMode(::libaom_test::kTwoPassGood); + + cfg_.g_lag_in_frames = 5; + cfg_.rc_end_usage = AOM_VBR; + cfg_.rc_2pass_vbr_minsection_pct = 5; + cfg_.rc_2pass_vbr_maxsection_pct = 2000; + + cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 0; + } + + virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) { + if (video->frame() == 0) { + SetTileSize(encoder); + encoder->Control(AOME_SET_CPUUSED, set_cpu_used_); + encoder->Control(AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST, use_multipass_); + encoder->Control(AV1E_SET_ROW_MT, row_mt_); + + encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1); + encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7); + encoder->Control(AOME_SET_ARNR_STRENGTH, 5); + } + } + + virtual void SetTileSize(libaom_test::Encoder *encoder) { + encoder->Control(AV1E_SET_TILE_COLUMNS, 1); + encoder->Control(AV1E_SET_TILE_ROWS, 1); + } + + virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) { + size_enc_.push_back(pkt->data.frame.sz); + + ::libaom_test::MD5 md5_enc; + md5_enc.Add(reinterpret_cast(pkt->data.frame.buf), + pkt->data.frame.sz); + md5_enc_.push_back(md5_enc.Get()); + + const aom_codec_err_t res = decoder_->DecodeFrame( + reinterpret_cast(pkt->data.frame.buf), pkt->data.frame.sz); + if (res != AOM_CODEC_OK) { + abort_ = true; + ASSERT_EQ(AOM_CODEC_OK, res); + } + const aom_image_t *img = decoder_->GetDxData().Next(); + + if (img) { + ::libaom_test::MD5 md5_res; + md5_res.Add(img); + md5_dec_.push_back(md5_res.Get()); + } + } + + void DoTest() { + ::libaom_test::YUVVideoSource video( + "niklas_640_480_30.yuv", AOM_IMG_FMT_I420, 640, 480, 30, 1, 0, 6); + cfg_.rc_target_bitrate = 1000; + + // Encode while coding each sb once + use_multipass_ = false; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + std::vector single_pass_size_enc; + std::vector single_pass_md5_enc; + std::vector single_pass_md5_dec; + single_pass_size_enc = size_enc_; + single_pass_md5_enc = md5_enc_; + single_pass_md5_dec = md5_dec_; + size_enc_.clear(); + md5_enc_.clear(); + md5_dec_.clear(); + + // Encode while coding each sb twice + use_multipass_ = true; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + std::vector multi_pass_size_enc; + std::vector multi_pass_md5_enc; + std::vector multi_pass_md5_dec; + multi_pass_size_enc = size_enc_; + multi_pass_md5_enc = md5_enc_; + multi_pass_md5_dec = md5_dec_; + size_enc_.clear(); + md5_enc_.clear(); + md5_dec_.clear(); + + // Check that the vectors are equal. + ASSERT_EQ(single_pass_size_enc, multi_pass_size_enc); + ASSERT_EQ(single_pass_md5_enc, multi_pass_md5_enc); + ASSERT_EQ(single_pass_md5_dec, multi_pass_md5_dec); + } + + bool use_multipass_; + int set_cpu_used_; + bool row_mt_; + ::libaom_test::Decoder *decoder_; + std::vector size_enc_; + std::vector md5_enc_; + std::vector md5_dec_; +}; + +TEST_P(AV1SBMultipassTest, TwoPassMatchTest) { DoTest(); } + +AV1_INSTANTIATE_TEST_CASE(AV1SBMultipassTest, ::testing::Range(0, 6), + ::testing::Bool()); + +} // namespace diff --git a/media/libaom/src/test/selfguided_filter_test.cc b/media/libaom/src/test/selfguided_filter_test.cc index 1609f833e7..d65cce58a4 100644 --- a/media/libaom/src/test/selfguided_filter_test.cc +++ b/media/libaom/src/test/selfguided_filter_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -27,8 +28,8 @@ namespace { using libaom_test::ACMRandom; -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; typedef void (*SgrFunc)(const uint8_t *dat8, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst8, int dst_stride, @@ -201,21 +202,19 @@ TEST_P(AV1SelfguidedFilterTest, DISABLED_SpeedTest) { RunSpeedTest(); } TEST_P(AV1SelfguidedFilterTest, CorrectnessTest) { RunCorrectnessTest(); } #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1SelfguidedFilterTest, ::testing::Values(av1_apply_selfguided_restoration_sse4_1)); #endif #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1SelfguidedFilterTest, ::testing::Values(av1_apply_selfguided_restoration_avx2)); #endif -// TODO(b/141858830,b/141859709): neon is currently disabled due to use of -// uninitialized memory. -#if 0 // HAVE_NEON -INSTANTIATE_TEST_CASE_P( +#if HAVE_NEON +INSTANTIATE_TEST_SUITE_P( NEON, AV1SelfguidedFilterTest, ::testing::Values(av1_apply_selfguided_restoration_neon)); #endif @@ -395,7 +394,7 @@ TEST_P(AV1HighbdSelfguidedFilterTest, CorrectnessTest) { RunCorrectnessTest(); } #if HAVE_SSE4_1 const int highbd_params_sse4_1[] = { 8, 10, 12 }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1HighbdSelfguidedFilterTest, ::testing::Combine( ::testing::Values(av1_apply_selfguided_restoration_sse4_1), @@ -404,16 +403,15 @@ INSTANTIATE_TEST_CASE_P( #if HAVE_AVX2 const int highbd_params_avx2[] = { 8, 10, 12 }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1HighbdSelfguidedFilterTest, ::testing::Combine(::testing::Values(av1_apply_selfguided_restoration_avx2), ::testing::ValuesIn(highbd_params_avx2))); #endif -// TODO(b/141858830,b/141859709): neon is currently disabled due to use of -// uninitialized memory. -#if 0 // HAVE_NEON + +#if HAVE_NEON const int highbd_params_neon[] = { 8, 10, 12 }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AV1HighbdSelfguidedFilterTest, ::testing::Combine(::testing::Values(av1_apply_selfguided_restoration_neon), ::testing::ValuesIn(highbd_params_neon))); diff --git a/media/libaom/src/test/simd_cmp_impl.h b/media/libaom/src/test/simd_cmp_impl.h index b7bd5e7199..d3eb33619b 100644 --- a/media/libaom/src/test/simd_cmp_impl.h +++ b/media/libaom/src/test/simd_cmp_impl.h @@ -1475,8 +1475,8 @@ int CompareSimd3Args(fptr store, fptr load1, fptr load2, fptr load3, fptr simd, (CArg1(*const)(const void *))c_load1; CArg2 (*const my_c_load2)(const void *) = (CArg2(*const)(const void *))c_load2; - CArg2 (*const my_c_load3)(const void *) = - (CArg2(*const)(const void *))c_load3; + CArg3 (*const my_c_load3)(const void *) = + (CArg3(*const)(const void *))c_load3; CRet (*const my_c_simd)(CArg1, CArg2, CArg3) = (CRet(*const)(CArg1, CArg2, CArg3))c_simd; @@ -1731,8 +1731,9 @@ void TestSimd1Arg(uint32_t iterations, uint32_t mask, uint32_t maskwidth, } EXPECT_EQ(0, error) << "Error: mismatch for " << name << "(" - << Print(s, sizeof(s)) << ") -> " << Print(d, sizeof(d)) - << " (simd), " << Print(ref_d, sizeof(ref_d)) << " (ref)"; + << Print(s, sizeof(CArg)) << ") -> " + << Print(d, sizeof(CRet)) << " (simd), " + << Print(ref_d, sizeof(CRet)) << " (ref)"; } template @@ -1987,9 +1988,10 @@ void TestSimd2Args(uint32_t iterations, uint32_t mask, uint32_t maskwidth, } EXPECT_EQ(0, error) << "Error: mismatch for " << name << "(" - << Print(s1, sizeof(s1)) << ", " << Print(s2, sizeof(s2)) - << ") -> " << Print(d, sizeof(d)) << " (simd), " - << Print(ref_d, sizeof(ref_d)) << " (ref)"; + << Print(s1, sizeof(CArg1)) << ", " + << Print(s2, sizeof(CArg2)) << ") -> " + << Print(d, sizeof(CRet)) << " (simd), " + << Print(ref_d, sizeof(CRet)) << " (ref)"; } template @@ -2063,10 +2065,11 @@ void TestSimd3Args(uint32_t iterations, uint32_t mask, uint32_t maskwidth, } EXPECT_EQ(0, error) << "Error: mismatch for " << name << "(" - << Print(s1, sizeof(s1)) << ", " << Print(s2, sizeof(s2)) - << ", " << Print(s3, sizeof(s3)) << ") -> " - << Print(d, sizeof(d)) << " (simd), " - << Print(ref_d, sizeof(ref_d)) << " (ref)"; + << Print(s1, sizeof(CArg1)) << ", " + << Print(s2, sizeof(CArg2)) << ", " + << Print(s3, sizeof(CArg3)) << ") -> " + << Print(d, sizeof(CRet)) << " (simd), " + << Print(ref_d, sizeof(CRet)) << " (ref)"; } // Instantiations to make the functions callable from another files diff --git a/media/libaom/src/test/simd_impl.h b/media/libaom/src/test/simd_impl.h index fd06f67fdf..61fda009f1 100644 --- a/media/libaom/src/test/simd_impl.h +++ b/media/libaom/src/test/simd_impl.h @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #define SIMD_CHECK 1 #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/clear_system_state.h" @@ -23,9 +25,9 @@ class TestIntrinsic : public ::testing::TestWithParam { public: virtual ~TestIntrinsic() {} virtual void SetUp() { - mask = ::testing::get<0>(this->GetParam()); - maskwidth = ::testing::get<1>(this->GetParam()); - name = ::testing::get<2>(this->GetParam()); + mask = std::get<0>(this->GetParam()); + maskwidth = std::get<1>(this->GetParam()); + name = std::get<2>(this->GetParam()); } virtual void TearDown() { libaom_test::ClearSystemState(); } @@ -36,8 +38,8 @@ class TestIntrinsic : public ::testing::TestWithParam { }; // Create one typedef for each function signature -#define TYPEDEF_SIMD(name) \ - typedef TestIntrinsic< ::testing::tuple > \ +#define TYPEDEF_SIMD(name) \ + typedef TestIntrinsic > \ ARCH_POSTFIX(name) TYPEDEF_SIMD(V64_U8); @@ -350,16 +352,16 @@ MY_TEST_P(ARCH_POSTFIX(V64_V256), TestIntrinsics) { TestSimd1Arg(kIterations, mask, maskwidth, name); } -// Add a macro layer since INSTANTIATE_TEST_CASE_P will quote the name +// Add a macro layer since INSTANTIATE_TEST_SUITE_P will quote the name // so we need to expand it first with the prefix #define INSTANTIATE(name, type, ...) \ - INSTANTIATE_TEST_CASE_P(name, type, ::testing::Values(__VA_ARGS__)) + INSTANTIATE_TEST_SUITE_P(name, type, ::testing::Values(__VA_ARGS__)) #define SIMD_TUPLE(name, mask, maskwidth) \ - ::testing::make_tuple(mask, maskwidth, static_cast(#name)) + std::make_tuple(mask, maskwidth, static_cast(#name)) -INSTANTIATE(ARCH, ARCH_POSTFIX(U32_V64V64), - (SIMD_TUPLE(v64_sad_u8, 0U, 0U), SIMD_TUPLE(v64_ssd_u8, 0U, 0U))); +INSTANTIATE(ARCH, ARCH_POSTFIX(U32_V64V64), SIMD_TUPLE(v64_sad_u8, 0U, 0U), + SIMD_TUPLE(v64_ssd_u8, 0U, 0U)); INSTANTIATE( ARCH, ARCH_POSTFIX(V64_V64V64), SIMD_TUPLE(v64_add_8, 0U, 0U), diff --git a/media/libaom/src/test/subtract_test.cc b/media/libaom/src/test/subtract_test.cc index e0097714bd..4001e8b7ab 100644 --- a/media/libaom/src/test/subtract_test.cc +++ b/media/libaom/src/test/subtract_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/aom_config.h" @@ -88,20 +90,20 @@ TEST_P(AV1SubtractBlockTest, SimpleSubtract) { } } -INSTANTIATE_TEST_CASE_P(C, AV1SubtractBlockTest, - ::testing::Values(aom_subtract_block_c)); +INSTANTIATE_TEST_SUITE_P(C, AV1SubtractBlockTest, + ::testing::Values(aom_subtract_block_c)); #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, AV1SubtractBlockTest, - ::testing::Values(aom_subtract_block_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1SubtractBlockTest, + ::testing::Values(aom_subtract_block_sse2)); #endif #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, AV1SubtractBlockTest, - ::testing::Values(aom_subtract_block_neon)); +INSTANTIATE_TEST_SUITE_P(NEON, AV1SubtractBlockTest, + ::testing::Values(aom_subtract_block_neon)); #endif #if HAVE_MSA -INSTANTIATE_TEST_CASE_P(MSA, AV1SubtractBlockTest, - ::testing::Values(aom_subtract_block_msa)); +INSTANTIATE_TEST_SUITE_P(MSA, AV1SubtractBlockTest, + ::testing::Values(aom_subtract_block_msa)); #endif #if CONFIG_AV1_HIGHBITDEPTH @@ -110,9 +112,9 @@ typedef void (*HBDSubtractFunc)(int rows, int cols, int16_t *diff_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride, int bd); -using ::testing::get; -using ::testing::make_tuple; -using ::testing::tuple; +using std::get; +using std::make_tuple; +using std::tuple; // typedef tuple Params; @@ -243,8 +245,8 @@ const Params kAV1HBDSubtractBlock_sse2[] = { make_tuple(128, 128, 12, &aom_highbd_subtract_block_c) }; -INSTANTIATE_TEST_CASE_P(SSE2, AV1HBDSubtractBlockTest, - ::testing::ValuesIn(kAV1HBDSubtractBlock_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AV1HBDSubtractBlockTest, + ::testing::ValuesIn(kAV1HBDSubtractBlock_sse2)); #endif // HAVE_SSE2 #endif // CONFIG_AV1_HIGHBITDEPTH } // namespace diff --git a/media/libaom/src/test/sum_squares_test.cc b/media/libaom/src/test/sum_squares_test.cc index 95f4e1679a..8845466b86 100644 --- a/media/libaom/src/test/sum_squares_test.cc +++ b/media/libaom/src/test/sum_squares_test.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -157,7 +158,7 @@ TEST_P(SumSquaresTest, DISABLED_Speed) { RunSpeedTest(); } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, SumSquaresTest, ::testing::Values(TestFuncs(&aom_sum_squares_2d_i16_c, &aom_sum_squares_2d_i16_sse2))); @@ -165,7 +166,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE2 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, SumSquaresTest, ::testing::Values(TestFuncs(&aom_sum_squares_2d_i16_c, &aom_sum_squares_2d_i16_avx2))); @@ -224,9 +225,9 @@ TEST_P(SumSquares1DTest, ExtremeValues) { } #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, SumSquares1DTest, - ::testing::Values(TestFuncs1D( - aom_sum_squares_i16_c, aom_sum_squares_i16_sse2))); +INSTANTIATE_TEST_SUITE_P(SSE2, SumSquares1DTest, + ::testing::Values(TestFuncs1D( + aom_sum_squares_i16_c, aom_sum_squares_i16_sse2))); #endif // HAVE_SSE2 @@ -234,7 +235,7 @@ typedef int64_t (*sse_func)(const uint8_t *a, int a_stride, const uint8_t *b, int b_stride, int width, int height); typedef libaom_test::FuncParam TestSSEFuncs; -typedef ::testing::tuple SSETestParam; +typedef std::tuple SSETestParam; class SSETest : public ::testing::TestWithParam { public: @@ -384,6 +385,18 @@ TEST_P(SSETest, DISABLED_Speed) { RunTest(1, width_, height, 100); } } + +#if HAVE_NEON +TestSSEFuncs sse_neon[] = { + TestSSEFuncs(&aom_sse_c, &aom_sse_neon), +#if CONFIG_AV1_HIGHBITDEPTH + TestSSEFuncs(&aom_highbd_sse_c, &aom_highbd_sse_neon) +#endif +}; +INSTANTIATE_TEST_SUITE_P(NEON, SSETest, + Combine(ValuesIn(sse_neon), Range(4, 129, 4))); +#endif // HAVE_NEON + #if HAVE_SSE4_1 TestSSEFuncs sse_sse4[] = { TestSSEFuncs(&aom_sse_c, &aom_sse_sse4_1), @@ -391,8 +404,8 @@ TestSSEFuncs sse_sse4[] = { TestSSEFuncs(&aom_highbd_sse_c, &aom_highbd_sse_sse4_1) #endif }; -INSTANTIATE_TEST_CASE_P(SSE4_1, SSETest, - Combine(ValuesIn(sse_sse4), Range(4, 129, 4))); +INSTANTIATE_TEST_SUITE_P(SSE4_1, SSETest, + Combine(ValuesIn(sse_sse4), Range(4, 129, 4))); #endif // HAVE_SSE4_1 #if HAVE_AVX2 @@ -403,8 +416,8 @@ TestSSEFuncs sse_avx2[] = { TestSSEFuncs(&aom_highbd_sse_c, &aom_highbd_sse_avx2) #endif }; -INSTANTIATE_TEST_CASE_P(AVX2, SSETest, - Combine(ValuesIn(sse_avx2), Range(4, 129, 4))); +INSTANTIATE_TEST_SUITE_P(AVX2, SSETest, + Combine(ValuesIn(sse_avx2), Range(4, 129, 4))); #endif // HAVE_AVX2 ////////////////////////////////////////////////////////////////////////////// @@ -415,7 +428,7 @@ typedef void (*sse_sum_func)(const int16_t *data, int stride, int bw, int bh, int *x_sum, int64_t *x2_sum); typedef libaom_test::FuncParam TestSSE_SumFuncs; -typedef ::testing::tuple SSE_SumTestParam; +typedef std::tuple SSE_SumTestParam; class SSE_Sum_Test : public ::testing::TestWithParam { public: @@ -542,14 +555,285 @@ TEST_P(SSE_Sum_Test, DISABLED_Speed) { #if HAVE_SSE2 TestSSE_SumFuncs sse_sum_sse2[] = { TestSSE_SumFuncs( &aom_get_blk_sse_sum_c, &aom_get_blk_sse_sum_sse2) }; -INSTANTIATE_TEST_CASE_P(SSE2, SSE_Sum_Test, - Combine(ValuesIn(sse_sum_sse2), Range(4, 65, 4))); +INSTANTIATE_TEST_SUITE_P(SSE2, SSE_Sum_Test, + Combine(ValuesIn(sse_sum_sse2), Range(4, 65, 4))); #endif // HAVE_SSE2 #if HAVE_AVX2 TestSSE_SumFuncs sse_sum_avx2[] = { TestSSE_SumFuncs( &aom_get_blk_sse_sum_c, &aom_get_blk_sse_sum_avx2) }; -INSTANTIATE_TEST_CASE_P(AVX2, SSE_Sum_Test, - Combine(ValuesIn(sse_sum_avx2), Range(4, 65, 4))); +INSTANTIATE_TEST_SUITE_P(AVX2, SSE_Sum_Test, + Combine(ValuesIn(sse_sum_avx2), Range(4, 65, 4))); #endif // HAVE_AVX2 + +////////////////////////////////////////////////////////////////////////////// +// 2D Variance test functions +////////////////////////////////////////////////////////////////////////////// + +typedef uint64_t (*Var2DFunc)(uint8_t *src, int stride, int width, int height); +typedef libaom_test::FuncParam TestFuncVar2D; + +const uint16_t test_block_size[2] = { 128, 256 }; + +class Lowbd2dVarTest : public ::testing::TestWithParam { + public: + virtual ~Lowbd2dVarTest() {} + virtual void SetUp() { + params_ = this->GetParam(); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src_ = reinterpret_cast( + aom_memalign(16, 512 * 512 * sizeof(uint8_t))); + ASSERT_TRUE(src_ != NULL); + } + + virtual void TearDown() { + libaom_test::ClearSystemState(); + aom_free(src_); + } + void RunTest(int isRandom); + void RunSpeedTest(); + + void GenRandomData(int width, int height, int stride) { + const int msb = 7; // Up to 8 bit input + const int limit = 1 << (msb + 1); + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + src_[ii * stride + jj] = rnd_(limit); + } + } + } + + void GenExtremeData(int width, int height, int stride) { + const int msb = 7; // Up to 8 bit input + const int limit = 1 << (msb + 1); + const int val = rnd_(2) ? limit - 1 : 0; + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + src_[ii * stride + jj] = val; + } + } + } + + protected: + TestFuncVar2D params_; + uint8_t *src_; + ACMRandom rnd_; +}; + +void Lowbd2dVarTest::RunTest(int isRandom) { + int failed = 0; + for (int k = 0; k < kNumIterations; k++) { + const int width = 4 * (rnd_(63) + 1); // Up to 256x256 + const int height = 4 * (rnd_(63) + 1); // Up to 256x256 + int stride = 4 << rnd_(8); // Up to 512 stride + while (stride < width) { // Make sure it's valid + stride = 4 << rnd_(8); + } + if (isRandom) { + GenRandomData(width, height, stride); + } else { + GenExtremeData(width, height, stride); + } + + const uint64_t res_ref = params_.ref_func(src_, stride, width, height); + uint64_t res_tst; + ASM_REGISTER_STATE_CHECK(res_tst = + params_.tst_func(src_, stride, width, height)); + + if (!failed) { + failed = res_ref != res_tst; + EXPECT_EQ(res_ref, res_tst) + << "Error: Sum Squares Test [" << width << "x" << height + << "] C output does not match optimized output."; + } + } +} + +void Lowbd2dVarTest::RunSpeedTest() { + for (int block = 0; block < 2; block++) { + const int width = test_block_size[block]; + const int height = test_block_size[block]; + int stride = 4 << rnd_(8); // Up to 512 stride + while (stride < width) { // Make sure it's valid + stride = 4 << rnd_(8); + } + GenExtremeData(width, height, stride); + const int num_loops = 1000000000 / (width + height); + aom_usec_timer timer; + aom_usec_timer_start(&timer); + + for (int i = 0; i < num_loops; ++i) + params_.ref_func(src_, stride, width, height); + + aom_usec_timer_mark(&timer); + const int elapsed_time = static_cast(aom_usec_timer_elapsed(&timer)); + + aom_usec_timer timer1; + aom_usec_timer_start(&timer1); + for (int i = 0; i < num_loops; ++i) + params_.tst_func(src_, stride, width, height); + aom_usec_timer_mark(&timer1); + const int elapsed_time1 = static_cast(aom_usec_timer_elapsed(&timer1)); + printf("%3dx%-3d: Scaling = %.2f\n", width, height, + (double)elapsed_time / elapsed_time1); + } +} + +TEST_P(Lowbd2dVarTest, OperationCheck) { + RunTest(1); // GenRandomData +} + +TEST_P(Lowbd2dVarTest, ExtremeValues) { + RunTest(0); // GenExtremeData +} + +TEST_P(Lowbd2dVarTest, DISABLED_Speed) { RunSpeedTest(); } + +#if HAVE_SSE2 + +INSTANTIATE_TEST_SUITE_P(SSE2, Lowbd2dVarTest, + ::testing::Values(TestFuncVar2D(&aom_var_2d_u8_c, + &aom_var_2d_u8_sse2))); + +#endif // HAVE_SSE2 + +#if HAVE_AVX2 + +INSTANTIATE_TEST_SUITE_P(AVX2, Lowbd2dVarTest, + ::testing::Values(TestFuncVar2D(&aom_var_2d_u8_c, + &aom_var_2d_u8_avx2))); + +#endif // HAVE_SSE2 + +class Highbd2dVarTest : public ::testing::TestWithParam { + public: + virtual ~Highbd2dVarTest() {} + virtual void SetUp() { + params_ = this->GetParam(); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src_ = reinterpret_cast( + aom_memalign(16, 512 * 512 * sizeof(uint16_t))); + ASSERT_TRUE(src_ != NULL); + } + + virtual void TearDown() { + libaom_test::ClearSystemState(); + aom_free(src_); + } + void RunTest(int isRandom); + void RunSpeedTest(); + + void GenRandomData(int width, int height, int stride) { + const int msb = 11; // Up to 12 bit input + const int limit = 1 << (msb + 1); + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + src_[ii * stride + jj] = rnd_(limit); + } + } + } + + void GenExtremeData(int width, int height, int stride) { + const int msb = 11; // Up to 12 bit input + const int limit = 1 << (msb + 1); + const int val = rnd_(2) ? limit - 1 : 0; + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + src_[ii * stride + jj] = val; + } + } + } + + protected: + TestFuncVar2D params_; + uint16_t *src_; + ACMRandom rnd_; +}; + +void Highbd2dVarTest::RunTest(int isRandom) { + int failed = 0; + for (int k = 0; k < kNumIterations; k++) { + const int width = 4 * (rnd_(63) + 1); // Up to 256x256 + const int height = 4 * (rnd_(63) + 1); // Up to 256x256 + int stride = 4 << rnd_(8); // Up to 512 stride + while (stride < width) { // Make sure it's valid + stride = 4 << rnd_(8); + } + if (isRandom) { + GenRandomData(width, height, stride); + } else { + GenExtremeData(width, height, stride); + } + + const uint64_t res_ref = + params_.ref_func(CONVERT_TO_BYTEPTR(src_), stride, width, height); + uint64_t res_tst; + ASM_REGISTER_STATE_CHECK( + res_tst = + params_.tst_func(CONVERT_TO_BYTEPTR(src_), stride, width, height)); + + if (!failed) { + failed = res_ref != res_tst; + EXPECT_EQ(res_ref, res_tst) + << "Error: Sum Squares Test [" << width << "x" << height + << "] C output does not match optimized output."; + } + } +} + +void Highbd2dVarTest::RunSpeedTest() { + for (int block = 0; block < 2; block++) { + const int width = test_block_size[block]; + const int height = test_block_size[block]; + int stride = 4 << rnd_(8); // Up to 512 stride + while (stride < width) { // Make sure it's valid + stride = 4 << rnd_(8); + } + GenExtremeData(width, height, stride); + const int num_loops = 1000000000 / (width + height); + aom_usec_timer timer; + aom_usec_timer_start(&timer); + + for (int i = 0; i < num_loops; ++i) + params_.ref_func(CONVERT_TO_BYTEPTR(src_), stride, width, height); + + aom_usec_timer_mark(&timer); + const int elapsed_time = static_cast(aom_usec_timer_elapsed(&timer)); + + aom_usec_timer timer1; + aom_usec_timer_start(&timer1); + for (int i = 0; i < num_loops; ++i) + params_.tst_func(CONVERT_TO_BYTEPTR(src_), stride, width, height); + aom_usec_timer_mark(&timer1); + const int elapsed_time1 = static_cast(aom_usec_timer_elapsed(&timer1)); + printf("%3dx%-3d: Scaling = %.2f\n", width, height, + (double)elapsed_time / elapsed_time1); + } +} + +TEST_P(Highbd2dVarTest, OperationCheck) { + RunTest(1); // GenRandomData +} + +TEST_P(Highbd2dVarTest, ExtremeValues) { + RunTest(0); // GenExtremeData +} + +TEST_P(Highbd2dVarTest, DISABLED_Speed) { RunSpeedTest(); } + +#if HAVE_SSE2 + +INSTANTIATE_TEST_SUITE_P( + SSE2, Highbd2dVarTest, + ::testing::Values(TestFuncVar2D(&aom_var_2d_u16_c, &aom_var_2d_u16_sse2))); + +#endif // HAVE_SSE2 + +#if HAVE_AVX2 + +INSTANTIATE_TEST_SUITE_P( + AVX2, Highbd2dVarTest, + ::testing::Values(TestFuncVar2D(&aom_var_2d_u16_c, &aom_var_2d_u16_avx2))); + +#endif // HAVE_SSE2 } // namespace diff --git a/media/libaom/src/test/superframe_test.cc b/media/libaom/src/test/superframe_test.cc index 2cec95aa52..024a18b978 100644 --- a/media/libaom/src/test/superframe_test.cc +++ b/media/libaom/src/test/superframe_test.cc @@ -10,6 +10,7 @@ */ #include +#include #include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "test/codec_factory.h" @@ -23,7 +24,7 @@ const int kTestMode = 0; const int kTileCols = 1; const int kTileRows = 2; -typedef ::testing::tuple SuperframeTestParam; +typedef std::tuple SuperframeTestParam; class SuperframeTest : public ::libaom_test::CodecTestWithParam, @@ -35,12 +36,12 @@ class SuperframeTest virtual void SetUp() { InitializeConfig(); const SuperframeTestParam input = GET_PARAM(1); - const libaom_test::TestMode mode = ::testing::get(input); + const libaom_test::TestMode mode = std::get(input); SetMode(mode); sf_count_ = 0; sf_count_max_ = INT_MAX; - n_tile_cols_ = ::testing::get(input); - n_tile_rows_ = ::testing::get(input); + n_tile_cols_ = std::get(input); + n_tile_rows_ = std::get(input); } virtual void PreEncodeFrameHook(libaom_test::VideoSource *video, diff --git a/media/libaom/src/test/svc_datarate_test.cc b/media/libaom/src/test/svc_datarate_test.cc index f806f2dc9e..28e517ba10 100644 --- a/media/libaom/src/test/svc_datarate_test.cc +++ b/media/libaom/src/test/svc_datarate_test.cc @@ -19,6 +19,7 @@ #include "test/util.h" #include "test/y4m_video_source.h" #include "aom/aom_codec.h" +#include "av1/common/enums.h" namespace datarate_test { namespace { @@ -114,12 +115,15 @@ class DatarateTestSVC // Set the referende map buffer idx for the 7 references: // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3), // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6). - for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = i; - for (int i = 0; i < 8; i++) ref_frame_config->refresh[i] = 0; - // Note only use LAST and GF for prediction in non-rd mode (speed 8). - int layer_flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 | - AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD | - AOM_EFLAG_NO_REF_ARF2; + for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { + ref_frame_config->ref_idx[i] = i; + ref_frame_config->reference[i] = 0; + } + for (int i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0; + // Set layer_flags to 0 when using ref_frame_config->reference. + int layer_flags = 0; + // Always reference LAST. + ref_frame_config->reference[0] = 1; if (number_temporal_layers_ == 3 && number_spatial_layers_ == 1) { // 3-layer: // 1 3 5 7 @@ -130,15 +134,14 @@ class DatarateTestSVC layer_id->temporal_layer_id = 0; // Update LAST on layer 0, reference LAST and GF. ref_frame_config->refresh[0] = 1; + ref_frame_config->reference[3] = 1; } else if ((frame_cnt - 1) % 4 == 0) { layer_id->temporal_layer_id = 2; // First top layer: no updates, only reference LAST (TL0). - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if ((frame_cnt - 2) % 4 == 0) { layer_id->temporal_layer_id = 1; // Middle layer (TL1): update LAST2, only reference LAST (TL0). ref_frame_config->refresh[1] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if ((frame_cnt - 3) % 4 == 0) { layer_id->temporal_layer_id = 2; // Second top layer: no updates, only reference LAST. @@ -146,7 +149,6 @@ class DatarateTestSVC // updated in previous frame. So LAST is TL1 frame. ref_frame_config->ref_idx[0] = 1; ref_frame_config->ref_idx[1] = 0; - layer_flags |= AOM_EFLAG_NO_REF_GF; } } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 2) { layer_id->temporal_layer_id = 0; @@ -155,7 +157,6 @@ class DatarateTestSVC ref_frame_config->ref_idx[0] = 0; ref_frame_config->ref_idx[3] = 3; ref_frame_config->refresh[0] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 3 // and GOLDEN to slot 0. Update slot 3 (LAST). @@ -163,6 +164,8 @@ class DatarateTestSVC ref_frame_config->ref_idx[3] = 0; ref_frame_config->refresh[3] = 1; } + // Reference GOLDEN. + if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1; } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 3) { // 3 spatial layers, 1 temporal. // Note for this case , we set the buffer idx for all references to be @@ -174,7 +177,6 @@ class DatarateTestSVC // Reference LAST, update LAST. Set all other buffer_idx to 0. for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; ref_frame_config->refresh[0] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1 // and GOLDEN (and all other refs) to slot 0. @@ -190,6 +192,8 @@ class DatarateTestSVC ref_frame_config->ref_idx[0] = 2; ref_frame_config->refresh[2] = 1; } + // Reference GOLDEN. + if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1; } else if (number_temporal_layers_ == 3 && number_spatial_layers_ == 3) { // 3 spatial and 3 temporal layer. if (superframe_cnt_ % 4 == 0) { @@ -200,7 +204,6 @@ class DatarateTestSVC // Set all buffer_idx to 0. for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; ref_frame_config->refresh[0] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 0. @@ -226,7 +229,6 @@ class DatarateTestSVC for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; ref_frame_config->ref_idx[3] = 3; ref_frame_config->refresh[3] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 3. @@ -252,7 +254,6 @@ class DatarateTestSVC for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; ref_frame_config->ref_idx[3] = 5; ref_frame_config->refresh[5] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1, // GOLDEN (and all other refs) to slot 5. @@ -281,7 +282,6 @@ class DatarateTestSVC ref_frame_config->ref_idx[0] = 5; ref_frame_config->ref_idx[3] = 3; ref_frame_config->refresh[3] = 1; - layer_flags |= AOM_EFLAG_NO_REF_GF; } else if (layer_id->spatial_layer_id == 1) { // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6, // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4. @@ -298,6 +298,8 @@ class DatarateTestSVC ref_frame_config->ref_idx[3] = 4; } } + // Reference GOLDEN. + if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1; } return layer_flags; } @@ -469,6 +471,47 @@ class DatarateTestSVC } } + virtual void BasicRateTargetingSVC3TL3SLHDTest() { + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_dropframe_thresh = 0; + cfg_.rc_min_quantizer = 0; + cfg_.rc_max_quantizer = 63; + cfg_.rc_end_usage = AOM_CBR; + cfg_.g_lag_in_frames = 0; + cfg_.g_error_resilient = 1; + + ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); + const int bitrate_array[2] = { 600, 1200 }; + cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)]; + ResetModel(); + number_temporal_layers_ = 3; + number_spatial_layers_ = 3; + // SL0 + const int bitrate_sl0 = 1 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[0] = 50 * bitrate_sl0 / 100; + target_layer_bitrate_[1] = 70 * bitrate_sl0 / 100; + target_layer_bitrate_[2] = bitrate_sl0; + // SL1 + const int bitrate_sl1 = 3 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[3] = 50 * bitrate_sl1 / 100; + target_layer_bitrate_[4] = 70 * bitrate_sl1 / 100; + target_layer_bitrate_[5] = bitrate_sl1; + // SL2 + const int bitrate_sl2 = 4 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[6] = 50 * bitrate_sl2 / 100; + target_layer_bitrate_[7] = 70 * bitrate_sl2 / 100; + target_layer_bitrate_[8] = bitrate_sl2; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + for (int i = 0; i < number_temporal_layers_ * number_spatial_layers_; i++) { + ASSERT_GE(effective_datarate_tl[i], target_layer_bitrate_[i] * 0.70) + << " The datarate for the file is lower than target by too much!"; + ASSERT_LE(effective_datarate_tl[i], target_layer_bitrate_[i] * 1.4) + << " The datarate for the file is greater than target by too much!"; + } + } + virtual void BasicRateTargetingSVC3TL3SLKfTest() { cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 500; @@ -545,6 +588,11 @@ TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL3SL) { BasicRateTargetingSVC3TL3SLTest(); } +// Check basic rate targeting for CBR, for 3 spatial, 3 temporal layers. +TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL3SLHD) { + BasicRateTargetingSVC3TL3SLHDTest(); +} + // Check basic rate targeting for CBR, for 3 spatial, 3 temporal layers, // for auto key frame mode with short key frame period. TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL3SLKf) { diff --git a/media/libaom/src/test/temporal_filter_planewise_test.cc b/media/libaom/src/test/temporal_filter_planewise_test.cc new file mode 100644 index 0000000000..c3f3e9e050 --- /dev/null +++ b/media/libaom/src/test/temporal_filter_planewise_test.cc @@ -0,0 +1,242 @@ +/* + * 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 "third_party/googletest/src/googletest/include/gtest/gtest.h" + +#include "config/aom_config.h" +#include "config/aom_dsp_rtcd.h" +#include "config/av1_rtcd.h" + +#include "aom_ports/mem.h" +#include "test/acm_random.h" +#include "test/clear_system_state.h" +#include "test/register_state_check.h" +#include "test/util.h" +#include "test/function_equivalence_test.h" + +using libaom_test::ACMRandom; +using libaom_test::FunctionEquivalenceTest; +using ::testing::Combine; +using ::testing::Range; +using ::testing::Values; +using ::testing::ValuesIn; + +#if !CONFIG_REALTIME_ONLY +namespace { + +typedef void (*TemporalFilterPlanewiseFunc)( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const double *noise_level, const int use_subblock, + const int block_mse, const int *subblock_mses, const int q_factor, + const uint8_t *pred, uint32_t *accum, uint16_t *count); +typedef libaom_test::FuncParam + TemporalFilterPlanewiseFuncParam; + +typedef std::tuple + TemporalFilterPlanewiseWithParam; + +class TemporalFilterPlanewiseTest + : public ::testing::TestWithParam { + public: + virtual ~TemporalFilterPlanewiseTest() {} + virtual void SetUp() { + params_ = GET_PARAM(0); + rnd_.Reset(ACMRandom::DeterministicSeed()); + src1_ = reinterpret_cast(aom_memalign(8, 256 * 256)); + src2_ = reinterpret_cast(aom_memalign(8, 256 * 256)); + + ASSERT_TRUE(src1_ != NULL); + ASSERT_TRUE(src2_ != NULL); + } + + virtual void TearDown() { + libaom_test::ClearSystemState(); + aom_free(src1_); + aom_free(src2_); + } + void RunTest(int isRandom, int width, int height, int run_times); + + void GenRandomData(int width, int height, int stride, int stride2) { + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + src1_[ii * stride + jj] = rnd_.Rand8(); + src2_[ii * stride2 + jj] = rnd_.Rand8(); + } + } + } + + void GenExtremeData(int width, int height, int stride, uint8_t *data, + int stride2, uint8_t *data2, uint8_t val) { + for (int ii = 0; ii < height; ii++) { + for (int jj = 0; jj < width; jj++) { + data[ii * stride + jj] = val; + data2[ii * stride2 + jj] = (255 - val); + } + } + } + + protected: + TemporalFilterPlanewiseFuncParam params_; + uint8_t *src1_; + uint8_t *src2_; + ACMRandom rnd_; +}; + +void TemporalFilterPlanewiseTest::RunTest(int isRandom, int width, int height, + int run_times) { + aom_usec_timer ref_timer, test_timer; + for (int k = 0; k < 3; k++) { + const int stride = width; + const int stride2 = width; + if (isRandom) { + GenRandomData(width, height, stride, stride2); + } else { + const int msb = 8; // Up to 8 bit input + const int limit = (1 << msb) - 1; + if (k == 0) { + GenExtremeData(width, height, stride, src1_, stride2, src2_, limit); + } else { + GenExtremeData(width, height, stride, src1_, stride2, src2_, 0); + } + } + double sigma[1] = { 2.1002103677063437 }; + DECLARE_ALIGNED(16, unsigned int, accumulator_ref[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_ref[1024 * 3]); + memset(accumulator_ref, 0, 1024 * 3 * sizeof(accumulator_ref[0])); + memset(count_ref, 0, 1024 * 3 * sizeof(count_ref[0])); + DECLARE_ALIGNED(16, unsigned int, accumulator_mod[1024 * 3]); + DECLARE_ALIGNED(16, uint16_t, count_mod[1024 * 3]); + memset(accumulator_mod, 0, 1024 * 3 * sizeof(accumulator_mod[0])); + memset(count_mod, 0, 1024 * 3 * sizeof(count_mod[0])); + + assert(width == 32 && height == 32); + const BLOCK_SIZE block_size = BLOCK_32X32; + const int use_subblock = 0; + const int block_mse = 20; + const int subblock_mses[4] = { 15, 16, 17, 18 }; + const int q_factor = 12; + const int mb_row = 0; + const int mb_col = 0; + const int num_planes = 1; + YV12_BUFFER_CONFIG *ref_frame = + (YV12_BUFFER_CONFIG *)malloc(sizeof(YV12_BUFFER_CONFIG)); + ref_frame->heights[0] = height; + ref_frame->strides[0] = stride; + DECLARE_ALIGNED(16, uint8_t, src[1024 * 3]); + ref_frame->buffer_alloc = src; + ref_frame->buffers[0] = ref_frame->buffer_alloc; + ref_frame->flags = 0; // Only support low bit-depth test. + memcpy(src, src1_, 1024 * 3 * sizeof(uint8_t)); + + MACROBLOCKD *mbd = (MACROBLOCKD *)malloc(sizeof(MACROBLOCKD)); + mbd->plane[0].subsampling_y = 0; + mbd->plane[0].subsampling_x = 0; + mbd->bd = 8; + + params_.ref_func(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + sigma, use_subblock, block_mse, subblock_mses, q_factor, + src2_, accumulator_ref, count_ref); + params_.tst_func(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + sigma, use_subblock, block_mse, subblock_mses, q_factor, + src2_, accumulator_mod, count_mod); + + if (run_times > 1) { + aom_usec_timer_start(&ref_timer); + for (int j = 0; j < run_times; j++) { + params_.ref_func(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + sigma, use_subblock, block_mse, subblock_mses, + q_factor, src2_, accumulator_ref, count_ref); + } + 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 j = 0; j < run_times; j++) { + params_.tst_func(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + sigma, use_subblock, block_mse, subblock_mses, + q_factor, src2_, accumulator_mod, count_mod); + } + 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=%f\t width=%d\t height=%d \n", + elapsed_time_c, elapsed_time_simd, + (float)((float)elapsed_time_c / (float)elapsed_time_simd), width, + height); + + } else { + for (int i = 0, l = 0; i < height; i++) { + for (int j = 0; j < width; j++, l++) { + EXPECT_EQ(accumulator_ref[l], accumulator_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] C accumulator does not match optimized accumulator."; + EXPECT_EQ(count_ref[l], count_mod[l]) + << "Error:" << k << " SSE Sum Test [" << width << "x" << height + << "] C count does not match optimized count."; + } + } + } + + free(ref_frame); + free(mbd); + } +} + +TEST_P(TemporalFilterPlanewiseTest, OperationCheck) { + for (int height = 32; height <= 32; height = height * 2) { + RunTest(1, height, height, 1); // GenRandomData + } +} + +TEST_P(TemporalFilterPlanewiseTest, ExtremeValues) { + for (int height = 32; height <= 32; height = height * 2) { + RunTest(0, height, height, 1); + } +} + +TEST_P(TemporalFilterPlanewiseTest, DISABLED_Speed) { + for (int height = 32; height <= 32; height = height * 2) { + RunTest(1, height, height, 100000); + } +} + +#if HAVE_AVX2 +TemporalFilterPlanewiseFuncParam temporal_filter_planewise_test_avx2[] = { + TemporalFilterPlanewiseFuncParam(&av1_apply_temporal_filter_planewise_c, + &av1_apply_temporal_filter_planewise_avx2) +}; +INSTANTIATE_TEST_SUITE_P(AVX2, TemporalFilterPlanewiseTest, + Combine(ValuesIn(temporal_filter_planewise_test_avx2), + Range(64, 65, 4))); +#endif // HAVE_AVX2 + +#if HAVE_SSE2 +TemporalFilterPlanewiseFuncParam temporal_filter_planewise_test_sse2[] = { + TemporalFilterPlanewiseFuncParam(&av1_apply_temporal_filter_planewise_c, + &av1_apply_temporal_filter_planewise_sse2) +}; +INSTANTIATE_TEST_SUITE_P(SSE2, TemporalFilterPlanewiseTest, + Combine(ValuesIn(temporal_filter_planewise_test_sse2), + Range(64, 65, 4))); +#endif // HAVE_SSE2 + +} // namespace +#endif diff --git a/media/libaom/src/test/yuv_temporal_filter_test.cc b/media/libaom/src/test/temporal_filter_yuv_test.cc similarity index 78% rename from media/libaom/src/test/yuv_temporal_filter_test.cc rename to media/libaom/src/test/temporal_filter_yuv_test.cc index f5047943e5..dc17aaaf7f 100644 --- a/media/libaom/src/test/yuv_temporal_filter_test.cc +++ b/media/libaom/src/test/temporal_filter_yuv_test.cc @@ -9,6 +9,8 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include + #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "config/av1_rtcd.h" @@ -24,20 +26,17 @@ 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); +typedef void (*TemporalFilterYUVFunc)( + const YV12_BUFFER_CONFIG *ref_frame, const MACROBLOCKD *mbd, + const BLOCK_SIZE block_size, const int mb_row, const int mb_col, + const int num_planes, const int strength, const int use_subblock, + const int *blk_fw, const uint8_t *pred, uint32_t *accum, uint16_t *count); struct TemporalFilterWithBd { - TemporalFilterWithBd(YUVTemporalFilterFunc func, int bitdepth) + TemporalFilterWithBd(TemporalFilterYUVFunc func, int bitdepth) : temporal_filter(func), bd(bitdepth) {} - YUVTemporalFilterFunc temporal_filter; + TemporalFilterYUVFunc temporal_filter; int bd; }; @@ -354,7 +353,7 @@ void ApplyReferenceFilter(const PixelType *y_src, const PixelType *y_pre, } } -class YUVTemporalFilterTest +class TemporalFilterYUVTest : public ::testing::TestWithParam { public: virtual void SetUp() { @@ -390,7 +389,7 @@ class YUVTemporalFilterTest uint32_t *u_accumu, uint16_t *u_count, uint32_t *v_accum, uint16_t *v_count); - YUVTemporalFilterFunc filter_func_; + TemporalFilterYUVFunc filter_func_; ACMRandom rnd_; int saturate_test_; int num_repeats_; @@ -399,7 +398,7 @@ class YUVTemporalFilterTest }; template <> -void YUVTemporalFilterTest::ApplyTestFilter( +void TemporalFilterYUVTest::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, @@ -407,15 +406,73 @@ void YUVTemporalFilterTest::ApplyTestFilter( 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) { + (void)block_width; + (void)block_height; + (void)y_src_stride; + (void)uv_src_stride; + + assert(block_width == MAX_WIDTH && MAX_WIDTH == 32); + assert(block_height == MAX_HEIGHT && MAX_HEIGHT == 32); + const BLOCK_SIZE block_size = BLOCK_32X32; + const int num_planes = 3; + const int mb_pels = MAX_WIDTH * MAX_HEIGHT; + const int mb_row = 0; + const int mb_col = 0; + const int use_subblock = !(use_32x32); + + YV12_BUFFER_CONFIG *ref_frame = + (YV12_BUFFER_CONFIG *)malloc(sizeof(YV12_BUFFER_CONFIG)); + ref_frame->strides[0] = y_pre_stride; + ref_frame->strides[1] = uv_pre_stride; + const int alloc_size = MAX_MB_PLANE * mb_pels; + DECLARE_ALIGNED(16, uint8_t, src[alloc_size]); + ref_frame->buffer_alloc = src; + ref_frame->buffers[0] = ref_frame->buffer_alloc + 0 * mb_pels; + ref_frame->buffers[1] = ref_frame->buffer_alloc + 1 * mb_pels; + ref_frame->buffers[2] = ref_frame->buffer_alloc + 2 * mb_pels; + ref_frame->flags = bd_ > 8 ? YV12_FLAG_HIGHBITDEPTH : 0; + + MACROBLOCKD *mbd = (MACROBLOCKD *)malloc(sizeof(MACROBLOCKD)); + mbd->plane[0].subsampling_y = 0; + mbd->plane[0].subsampling_x = 0; + mbd->plane[1].subsampling_y = ss_y; + mbd->plane[1].subsampling_x = ss_x; + mbd->plane[2].subsampling_y = ss_y; + mbd->plane[2].subsampling_x = ss_x; + + DECLARE_ALIGNED(16, uint8_t, pred[alloc_size]); + DECLARE_ALIGNED(16, uint32_t, accum[alloc_size]); + DECLARE_ALIGNED(16, uint16_t, count[alloc_size]); + memcpy(src + 0 * mb_pels, y_src, mb_pels * sizeof(uint8_t)); + memcpy(src + 1 * mb_pels, u_src, mb_pels * sizeof(uint8_t)); + memcpy(src + 2 * mb_pels, v_src, mb_pels * sizeof(uint8_t)); + memcpy(pred + 0 * mb_pels, y_pre, mb_pels * sizeof(uint8_t)); + memcpy(pred + 1 * mb_pels, u_pre, mb_pels * sizeof(uint8_t)); + memcpy(pred + 2 * mb_pels, v_pre, mb_pels * sizeof(uint8_t)); + memcpy(accum + 0 * mb_pels, y_accum, mb_pels * sizeof(uint32_t)); + memcpy(accum + 1 * mb_pels, u_accum, mb_pels * sizeof(uint32_t)); + memcpy(accum + 2 * mb_pels, v_accum, mb_pels * sizeof(uint32_t)); + memcpy(count + 0 * mb_pels, y_count, mb_pels * sizeof(uint16_t)); + memcpy(count + 1 * mb_pels, u_count, mb_pels * sizeof(uint16_t)); + memcpy(count + 2 * mb_pels, v_count, mb_pels * sizeof(uint16_t)); + 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)); + filter_func_(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + strength, use_subblock, blk_fw, pred, accum, count)); + + memcpy(y_accum, accum + 0 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(u_accum, accum + 1 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(v_accum, accum + 2 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(y_count, count + 0 * mb_pels, mb_pels * sizeof(uint16_t)); + memcpy(u_count, count + 1 * mb_pels, mb_pels * sizeof(uint16_t)); + memcpy(v_count, count + 2 * mb_pels, mb_pels * sizeof(uint16_t)); + + free(ref_frame); + free(mbd); } template <> -void YUVTemporalFilterTest::ApplyTestFilter( +void TemporalFilterYUVTest::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, @@ -423,16 +480,74 @@ void YUVTemporalFilterTest::ApplyTestFilter( 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)); + (void)block_width; + (void)block_height; + (void)y_src_stride; + (void)uv_src_stride; + + assert(block_width == MAX_WIDTH && MAX_WIDTH == 32); + assert(block_height == MAX_HEIGHT && MAX_HEIGHT == 32); + const BLOCK_SIZE block_size = BLOCK_32X32; + const int num_planes = 3; + const int mb_pels = MAX_WIDTH * MAX_HEIGHT; + const int mb_row = 0; + const int mb_col = 0; + const int use_subblock = !(use_32x32); + + YV12_BUFFER_CONFIG *ref_frame = + (YV12_BUFFER_CONFIG *)malloc(sizeof(YV12_BUFFER_CONFIG)); + ref_frame->strides[0] = y_pre_stride; + ref_frame->strides[1] = uv_pre_stride; + const int alloc_size = MAX_MB_PLANE * mb_pels; + DECLARE_ALIGNED(16, uint16_t, src16[alloc_size]); + ref_frame->buffer_alloc = CONVERT_TO_BYTEPTR(src16); + ref_frame->buffers[0] = ref_frame->buffer_alloc + 0 * mb_pels; + ref_frame->buffers[1] = ref_frame->buffer_alloc + 1 * mb_pels; + ref_frame->buffers[2] = ref_frame->buffer_alloc + 2 * mb_pels; + ref_frame->flags = bd_ > 8 ? YV12_FLAG_HIGHBITDEPTH : 0; + + MACROBLOCKD *mbd = (MACROBLOCKD *)malloc(sizeof(MACROBLOCKD)); + mbd->plane[0].subsampling_y = 0; + mbd->plane[0].subsampling_x = 0; + mbd->plane[1].subsampling_y = ss_y; + mbd->plane[1].subsampling_x = ss_x; + mbd->plane[2].subsampling_y = ss_y; + mbd->plane[2].subsampling_x = ss_x; + + DECLARE_ALIGNED(16, uint16_t, pred16[alloc_size]); + DECLARE_ALIGNED(16, uint32_t, accum[alloc_size]); + DECLARE_ALIGNED(16, uint16_t, count[alloc_size]); + memcpy(src16 + 0 * mb_pels, y_src, mb_pels * sizeof(uint16_t)); + memcpy(src16 + 1 * mb_pels, u_src, mb_pels * sizeof(uint16_t)); + memcpy(src16 + 2 * mb_pels, v_src, mb_pels * sizeof(uint16_t)); + memcpy(pred16 + 0 * mb_pels, y_pre, mb_pels * sizeof(uint16_t)); + memcpy(pred16 + 1 * mb_pels, u_pre, mb_pels * sizeof(uint16_t)); + memcpy(pred16 + 2 * mb_pels, v_pre, mb_pels * sizeof(uint16_t)); + memcpy(accum + 0 * mb_pels, y_accum, mb_pels * sizeof(uint32_t)); + memcpy(accum + 1 * mb_pels, u_accum, mb_pels * sizeof(uint32_t)); + memcpy(accum + 2 * mb_pels, v_accum, mb_pels * sizeof(uint32_t)); + memcpy(count + 0 * mb_pels, y_count, mb_pels * sizeof(uint16_t)); + memcpy(count + 1 * mb_pels, u_count, mb_pels * sizeof(uint16_t)); + memcpy(count + 2 * mb_pels, v_count, mb_pels * sizeof(uint16_t)); + const uint8_t *pred = CONVERT_TO_BYTEPTR(pred16); + + ASM_REGISTER_STATE_CHECK( + filter_func_(ref_frame, mbd, block_size, mb_row, mb_col, num_planes, + strength, use_subblock, blk_fw, pred, accum, count)); + + memcpy(y_accum, accum + 0 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(u_accum, accum + 1 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(v_accum, accum + 2 * mb_pels, mb_pels * sizeof(uint32_t)); + memcpy(y_count, count + 0 * mb_pels, mb_pels * sizeof(uint16_t)); + memcpy(u_count, count + 1 * mb_pels, mb_pels * sizeof(uint16_t)); + memcpy(v_count, count + 2 * mb_pels, mb_pels * sizeof(uint16_t)); + + free(ref_frame); + free(mbd); } template -void YUVTemporalFilterTest::CompareTestWithParam(int width, int height, +void TemporalFilterYUVTest::CompareTestWithParam(int width, int height, int ss_x, int ss_y, int filter_strength, int use_32x32, @@ -533,7 +648,7 @@ void YUVTemporalFilterTest::CompareTestWithParam(int width, int height, } template -void YUVTemporalFilterTest::RunTestFilterWithParam(int width, int height, +void TemporalFilterYUVTest::RunTestFilterWithParam(int width, int height, int ss_x, int ss_y, int filter_strength, int use_32x32, @@ -568,7 +683,7 @@ void YUVTemporalFilterTest::RunTestFilterWithParam(int width, int height, } } -TEST_P(YUVTemporalFilterTest, Use32x32) { +TEST_P(TemporalFilterYUVTest, Use32x32) { const int width = 32, height = 32; const int use_32x32 = 1; @@ -594,7 +709,7 @@ TEST_P(YUVTemporalFilterTest, Use32x32) { } } -TEST_P(YUVTemporalFilterTest, Use16x16) { +TEST_P(TemporalFilterYUVTest, Use16x16) { const int width = 32, height = 32; const int use_32x32 = 0; @@ -630,7 +745,7 @@ TEST_P(YUVTemporalFilterTest, Use16x16) { } } -TEST_P(YUVTemporalFilterTest, SaturationTest) { +TEST_P(TemporalFilterYUVTest, SaturationTest) { const int width = 32, height = 32; const int use_32x32 = 1; const int filter_weight = 1; @@ -657,7 +772,7 @@ TEST_P(YUVTemporalFilterTest, SaturationTest) { } } -TEST_P(YUVTemporalFilterTest, DISABLED_Speed) { +TEST_P(TemporalFilterYUVTest, DISABLED_Speed) { const int width = 32, height = 32; num_repeats_ = 1000; @@ -707,20 +822,20 @@ TEST_P(YUVTemporalFilterTest, DISABLED_Speed) { } } -INSTANTIATE_TEST_CASE_P( - C, YUVTemporalFilterTest, +INSTANTIATE_TEST_SUITE_P( + C, TemporalFilterYUVTest, ::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))); + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_c, 8), + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_c, 10), + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_c, 12))); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( - SSE4_1, YUVTemporalFilterTest, +INSTANTIATE_TEST_SUITE_P( + SSE4_1, TemporalFilterYUVTest, ::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))); + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_sse4_1, 8), + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_sse4_1, 10), + TemporalFilterWithBd(&av1_apply_temporal_filter_yuv_sse4_1, 12))); #endif // HAVE_SSE4_1 } // namespace diff --git a/media/libaom/src/test/test.cmake b/media/libaom/src/test/test.cmake index 8c721b5065..d4d3b298dc 100644 --- a/media/libaom/src/test/test.cmake +++ b/media/libaom/src/test/test.cmake @@ -34,8 +34,8 @@ list(APPEND AOM_UNIT_TEST_COMMON_SOURCES "${AOM_ROOT}/test/decode_test_driver.h" "${AOM_ROOT}/test/function_equivalence_test.h" "${AOM_ROOT}/test/log2_test.cc" - "${AOM_ROOT}/test/metadata_memory_handling_test.cc" "${AOM_ROOT}/test/md5_helper.h" + "${AOM_ROOT}/test/metadata_test.cc" "${AOM_ROOT}/test/register_state_check.h" "${AOM_ROOT}/test/test_vectors.cc" "${AOM_ROOT}/test/test_vectors.h" @@ -68,7 +68,7 @@ list(APPEND AOM_UNIT_TEST_ENCODER_SOURCES "${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/gf_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" @@ -93,6 +93,7 @@ list(APPEND AOM_TEST_INTRA_PRED_SPEED_SOURCES "${AOM_GEN_SRC_DIR}/usage_exit.c" if(NOT BUILD_SHARED_LIBS) list(APPEND AOM_UNIT_TEST_COMMON_SOURCES + "${AOM_ROOT}/test/av1_common_int_test.cc" "${AOM_ROOT}/test/cdef_test.cc" "${AOM_ROOT}/test/cfl_test.cc" "${AOM_ROOT}/test/convolve_test.cc" @@ -102,7 +103,6 @@ if(NOT BUILD_SHARED_LIBS) "${AOM_ROOT}/test/intrabc_test.cc" "${AOM_ROOT}/test/intrapred_test.cc" "${AOM_ROOT}/test/lpf_test.cc" - "${AOM_ROOT}/test/onyxc_int_test.cc" "${AOM_ROOT}/test/scan_test.cc" "${AOM_ROOT}/test/selfguided_filter_test.cc" "${AOM_ROOT}/test/simd_cmp_impl.h" @@ -127,14 +127,16 @@ if(NOT BUILD_SHARED_LIBS) "${AOM_ROOT}/test/ec_test.cc" "${AOM_ROOT}/test/ethread_test.cc" "${AOM_ROOT}/test/film_grain_table_test.cc" + "${AOM_ROOT}/test/sb_multipass_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/yuv_temporal_filter_test.cc") + "${AOM_ROOT}/test/temporal_filter_planewise_test.cc" + "${AOM_ROOT}/test/temporal_filter_yuv_test.cc") if(CONFIG_REALTIME_ONLY) list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES "${AOM_ROOT}/test/cnn_test.cc" - "${AOM_ROOT}/test/yuv_temporal_filter_test.cc") + "${AOM_ROOT}/test/temporal_filter_yuv_test.cc") endif() if(NOT CONFIG_AV1_HIGHBITDEPTH) list(REMOVE_ITEM AOM_UNIT_TEST_COMMON_SOURCES @@ -205,6 +207,7 @@ if(NOT BUILD_SHARED_LIBS) "${AOM_ROOT}/test/error_block_test.cc" "${AOM_ROOT}/test/fft_test.cc" "${AOM_ROOT}/test/fwht4x4_test.cc" + "${AOM_ROOT}/test/fdct4x4_test.cc" "${AOM_ROOT}/test/hadamard_test.cc" "${AOM_ROOT}/test/horver_correlation_test.cc" "${AOM_ROOT}/test/masked_sad_test.cc" @@ -237,6 +240,11 @@ if(NOT BUILD_SHARED_LIBS) "${AOM_ROOT}/test/av1_quantize_test.cc") endif() + if(NOT (HAVE_SSE2 OR HAVE_NEON)) + list(REMOVE_ITEM AOM_UNIT_TEST_ENCODER_SOURCES + "${AOM_ROOT}/test/quantize_func_test.cc") + endif() + if(HAVE_SSE4_1) list(APPEND AOM_UNIT_TEST_ENCODER_SOURCES "${AOM_ROOT}/test/av1_convolve_scale_test.cc" diff --git a/media/libaom/src/test/test_vector_test.cc b/media/libaom/src/test/test_vector_test.cc index 82b30317f6..eab92b685a 100644 --- a/media/libaom/src/test/test_vector_test.cc +++ b/media/libaom/src/test/test_vector_test.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" #include "common/tools_common.h" #include "config/aom_config.h" @@ -33,7 +34,7 @@ const int kThreads = 0; const int kFileName = 1; const int kRowMT = 2; -typedef ::testing::tuple DecodeParam; +typedef std::tuple DecodeParam; class TestVectorTest : public ::libaom_test::DecoderTest, public ::libaom_test::CodecTestWithParam { @@ -104,13 +105,13 @@ class TestVectorTest : public ::libaom_test::DecoderTest, // the test failed. TEST_P(TestVectorTest, MD5Match) { const DecodeParam input = GET_PARAM(1); - const std::string filename = ::testing::get(input); + const std::string filename = std::get(input); aom_codec_flags_t flags = 0; aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t(); char str[256]; - cfg.threads = ::testing::get(input); - row_mt_ = ::testing::get(input); + cfg.threads = std::get(input); + row_mt_ = std::get(input); snprintf(str, sizeof(str) / sizeof(str[0]) - 1, "file: %s threads: %d", filename.c_str(), cfg.threads); @@ -156,7 +157,7 @@ AV1_INSTANTIATE_TEST_CASE( ::testing::Values(0))); // Test AV1 decode in with different numbers of threads. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AV1MultiThreaded, TestVectorTest, ::testing::Combine( ::testing::Values( diff --git a/media/libaom/src/test/transform_test_base.h b/media/libaom/src/test/transform_test_base.h index 8ebcf5ff7c..68f5cc74d2 100644 --- a/media/libaom/src/test/transform_test_base.h +++ b/media/libaom/src/test/transform_test_base.h @@ -29,20 +29,23 @@ namespace libaom_test { // to a aom header file. const int kDctMaxValue = 16384; -typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, - TxfmParam *txfm_param); +template +using FhtFunc = void (*)(const int16_t *in, OutputType *out, int stride, + TxfmParam *txfm_param); -typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, - const TxfmParam *txfm_param); +template +using IhtFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride, + const TxfmParam *txfm_param); +template class TransformTestBase { public: virtual ~TransformTestBase() {} protected: - virtual void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) = 0; + virtual void RunFwdTxfm(const int16_t *in, OutType *out, int stride) = 0; - virtual void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) = 0; + virtual void RunInvTxfm(const OutType *out, uint8_t *dst, int stride) = 0; void RunAccuracyCheck(uint32_t ref_max_error, double ref_avg_error) { ACMRandom rnd(ACMRandom::DeterministicSeed()); @@ -52,8 +55,8 @@ class TransformTestBase { int16_t *test_input_block = reinterpret_cast( aom_memalign(16, sizeof(int16_t) * num_coeffs_)); - tran_low_t *test_temp_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); + OutType *test_temp_block = reinterpret_cast( + aom_memalign(16, sizeof(test_temp_block[0]) * num_coeffs_)); uint8_t *dst = reinterpret_cast( aom_memalign(16, sizeof(uint8_t) * num_coeffs_)); uint8_t *src = reinterpret_cast( @@ -123,10 +126,10 @@ class TransformTestBase { int16_t *input_block = reinterpret_cast( aom_memalign(16, sizeof(int16_t) * stride * height_)); - tran_low_t *output_ref_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); - tran_low_t *output_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); + OutType *output_ref_block = reinterpret_cast( + aom_memalign(16, sizeof(output_ref_block[0]) * num_coeffs_)); + OutType *output_block = reinterpret_cast( + aom_memalign(16, sizeof(output_block[0]) * num_coeffs_)); for (int i = 0; i < count_test_block; ++i) { int j, k; @@ -172,8 +175,8 @@ class TransformTestBase { int16_t *input_block = reinterpret_cast( aom_memalign(16, sizeof(int16_t) * num_coeffs_)); - tran_low_t *trans_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); + OutType *trans_block = reinterpret_cast( + aom_memalign(16, sizeof(trans_block[0]) * num_coeffs_)); uint8_t *output_block = reinterpret_cast( aom_memalign(16, sizeof(uint8_t) * stride * height_)); uint8_t *output_ref_block = reinterpret_cast( @@ -218,10 +221,10 @@ class TransformTestBase { int16_t *input_extreme_block = reinterpret_cast( aom_memalign(16, sizeof(int16_t) * num_coeffs_)); - tran_low_t *output_ref_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); - tran_low_t *output_block = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); + OutType *output_ref_block = reinterpret_cast( + aom_memalign(16, sizeof(output_ref_block[0]) * num_coeffs_)); + OutType *output_block = reinterpret_cast( + aom_memalign(16, sizeof(output_block[0]) * num_coeffs_)); for (int i = 0; i < count_test_block; ++i) { // Initialize a test block with input range [-mask_, mask_]. @@ -260,8 +263,8 @@ class TransformTestBase { int16_t *in = reinterpret_cast( aom_memalign(16, sizeof(int16_t) * num_coeffs_)); - tran_low_t *coeff = reinterpret_cast( - aom_memalign(16, sizeof(tran_low_t) * num_coeffs_)); + OutType *coeff = reinterpret_cast( + aom_memalign(16, sizeof(coeff[0]) * num_coeffs_)); uint8_t *dst = reinterpret_cast( aom_memalign(16, sizeof(uint8_t) * num_coeffs_)); uint8_t *src = reinterpret_cast( @@ -313,8 +316,8 @@ class TransformTestBase { int pitch_; int height_; - FhtFunc fwd_txfm_ref; - IhtFunc inv_txfm_ref; + FhtFunc fwd_txfm_ref; + IhtFunc inv_txfm_ref; aom_bit_depth_t bit_depth_; int mask_; int num_coeffs_; diff --git a/media/libaom/src/test/util.h b/media/libaom/src/test/util.h index c3f4e44421..aa4b106e45 100644 --- a/media/libaom/src/test/util.h +++ b/media/libaom/src/test/util.h @@ -20,7 +20,7 @@ #include "aom_ports/aom_timer.h" // Macros -#define GET_PARAM(k) ::testing::get(GetParam()) +#define GET_PARAM(k) std::get(GetParam()) inline double compute_psnr(const aom_image_t *img1, const aom_image_t *img2) { assert((img1->fmt == img2->fmt) && (img1->d_w == img2->d_w) && diff --git a/media/libaom/src/test/variance_test.cc b/media/libaom/src/test/variance_test.cc index 8f525b6934..1458ece287 100644 --- a/media/libaom/src/test/variance_test.cc +++ b/media/libaom/src/test/variance_test.cc @@ -11,6 +11,8 @@ #include #include +#include +#include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -115,8 +117,7 @@ static uint32_t variance_ref(const uint8_t *src, const uint8_t *ref, int l2w, /* The subpel reference functions differ from the codec version in one aspect: * they calculate the bilinear factors directly instead of using a lookup table * and therefore upshift xoff and yoff by 1. Only every other calculated value - * is used so the codec version shrinks the table to save space and maintain - * compatibility with vp8. + * is used so the codec version shrinks the table to save space. */ static uint32_t subpel_variance_ref(const uint8_t *ref, const uint8_t *src, int l2w, int l2h, int xoff, int yoff, @@ -657,9 +658,9 @@ void MainTestClass::MaxTestSse() { //////////////////////////////////////////////////////////////////////////////// -using ::testing::get; -using ::testing::make_tuple; -using ::testing::tuple; +using std::get; +using std::make_tuple; +using std::tuple; template class SubpelVarianceTest @@ -804,7 +805,7 @@ void SubpelVarianceTest::SpeedTest() { } } - unsigned int sse1; + unsigned int sse1, sse2; int run_time = 1000000000 / block_size(); aom_usec_timer timer; @@ -817,8 +818,24 @@ void SubpelVarianceTest::SpeedTest() { 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); + + aom_usec_timer timer_c; + + aom_usec_timer_start(&timer_c); + for (int i = 0; i < run_time; ++i) { + int x = rnd_(8); + int y = rnd_(8); + subpel_variance_ref(ref_, src_, params_.log2width, params_.log2height, x, y, + &sse2, use_high_bit_depth(), params_.bit_depth); + } + aom_usec_timer_mark(&timer_c); + + const int elapsed_time_c = static_cast(aom_usec_timer_elapsed(&timer_c)); + + printf( + "sub_pixel_variance_%dx%d_%d: ref_time=%d us opt_time=%d us gain=%d \n", + width(), height(), params_.bit_depth, elapsed_time_c, elapsed_time, + elapsed_time_c / elapsed_time); } template <> @@ -1075,29 +1092,30 @@ TEST_P(SumOfSquaresTest, Const) { ConstTest(); } TEST_P(SumOfSquaresTest, Ref) { RefTest(); } TEST_P(AvxSubpelVarianceTest, Ref) { RefTest(); } TEST_P(AvxSubpelVarianceTest, ExtremeRef) { ExtremeRefTest(); } +TEST_P(AvxSubpelVarianceTest, DISABLED_Speed) { SpeedTest(); } TEST_P(AvxSubpelAvgVarianceTest, Ref) { RefTest(); } TEST_P(AvxDistWtdSubpelAvgVarianceTest, Ref) { RefTest(); } TEST_P(AvxObmcSubpelVarianceTest, Ref) { RefTest(); } TEST_P(AvxObmcSubpelVarianceTest, ExtremeRef) { ExtremeRefTest(); } TEST_P(AvxObmcSubpelVarianceTest, DISABLED_Speed) { SpeedTest(); } -INSTANTIATE_TEST_CASE_P(C, SumOfSquaresTest, - ::testing::Values(aom_get_mb_ss_c)); +INSTANTIATE_TEST_SUITE_P(C, SumOfSquaresTest, + ::testing::Values(aom_get_mb_ss_c)); typedef TestParams SseParams; -INSTANTIATE_TEST_CASE_P(C, AvxSseTest, - ::testing::Values(SseParams(2, 2, - &aom_get4x4sse_cs_c))); +INSTANTIATE_TEST_SUITE_P(C, AvxSseTest, + ::testing::Values(SseParams(2, 2, + &aom_get4x4sse_cs_c))); typedef TestParams MseParams; -INSTANTIATE_TEST_CASE_P(C, AvxMseTest, - ::testing::Values(MseParams(4, 4, &aom_mse16x16_c), - MseParams(4, 3, &aom_mse16x8_c), - MseParams(3, 4, &aom_mse8x16_c), - MseParams(3, 3, &aom_mse8x8_c))); +INSTANTIATE_TEST_SUITE_P(C, AvxMseTest, + ::testing::Values(MseParams(4, 4, &aom_mse16x16_c), + MseParams(4, 3, &aom_mse16x8_c), + MseParams(3, 4, &aom_mse8x16_c), + MseParams(3, 3, &aom_mse8x8_c))); typedef TestParams VarianceParams; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxVarianceTest, ::testing::Values(VarianceParams(7, 7, &aom_variance128x128_c), VarianceParams(7, 6, &aom_variance128x64_c), @@ -1124,7 +1142,7 @@ INSTANTIATE_TEST_CASE_P( VarianceParams(2, 4, &aom_variance4x16_c))); typedef TestParams SubpelVarianceParams; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(7, 7, &aom_sub_pixel_variance128x128_c, 0), @@ -1152,7 +1170,7 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(2, 4, &aom_sub_pixel_variance4x16_c, 0))); typedef TestParams SubpelAvgVarianceParams; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(7, 7, &aom_sub_pixel_avg_variance128x128_c, 0), @@ -1180,7 +1198,7 @@ INSTANTIATE_TEST_CASE_P( SubpelAvgVarianceParams(2, 4, &aom_sub_pixel_avg_variance4x16_c, 0))); typedef TestParams DistWtdSubpelAvgVarianceParams; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxDistWtdSubpelAvgVarianceTest, ::testing::Values(DistWtdSubpelAvgVarianceParams( 6, 6, &aom_dist_wtd_sub_pixel_avg_variance64x64_c, 0), @@ -1223,7 +1241,7 @@ INSTANTIATE_TEST_CASE_P( 2, 4, &aom_dist_wtd_sub_pixel_avg_variance4x16_c, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxObmcSubpelVarianceTest, ::testing::Values( ObmcSubpelVarianceParams(7, 7, &aom_obmc_sub_pixel_variance128x128_c, @@ -1271,7 +1289,7 @@ TEST_P(AvxHBDSubpelVarianceTest, DISABLED_Speed) { SpeedTest(); } TEST_P(AvxHBDSubpelAvgVarianceTest, Ref) { RefTest(); } /* TODO(debargha): This test does not support the highbd version -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AvxHBDMseTest, ::testing::Values(make_tuple(4, 4, &aom_highbd_12_mse16x16_c), make_tuple(4, 4, &aom_highbd_12_mse16x8_c), @@ -1356,11 +1374,11 @@ const VarianceParams kArrayHBDVariance_c[] = { VarianceParams(4, 2, &aom_highbd_8_variance16x4_c, 8), VarianceParams(2, 4, &aom_highbd_8_variance4x16_c, 8), }; -INSTANTIATE_TEST_CASE_P(C, AvxHBDVarianceTest, - ::testing::ValuesIn(kArrayHBDVariance_c)); +INSTANTIATE_TEST_SUITE_P(C, AvxHBDVarianceTest, + ::testing::ValuesIn(kArrayHBDVariance_c)); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AvxHBDVarianceTest, ::testing::Values( VarianceParams(2, 2, &aom_highbd_8_variance4x4_sse4_1, 8), @@ -1437,8 +1455,8 @@ const SubpelVarianceParams kArrayHBDSubpelVariance_c[] = { SubpelVarianceParams(4, 2, &aom_highbd_12_sub_pixel_variance16x4_c, 12), SubpelVarianceParams(2, 4, &aom_highbd_12_sub_pixel_variance4x16_c, 12), }; -INSTANTIATE_TEST_CASE_P(C, AvxHBDSubpelVarianceTest, - ::testing::ValuesIn(kArrayHBDSubpelVariance_c)); +INSTANTIATE_TEST_SUITE_P(C, AvxHBDSubpelVarianceTest, + ::testing::ValuesIn(kArrayHBDSubpelVariance_c)); const SubpelAvgVarianceParams kArrayHBDSubpelAvgVariance_c[] = { SubpelAvgVarianceParams(7, 7, &aom_highbd_8_sub_pixel_avg_variance128x128_c, @@ -1548,8 +1566,8 @@ const SubpelAvgVarianceParams kArrayHBDSubpelAvgVariance_c[] = { SubpelAvgVarianceParams(2, 4, &aom_highbd_12_sub_pixel_avg_variance4x16_c, 12), }; -INSTANTIATE_TEST_CASE_P(C, AvxHBDSubpelAvgVarianceTest, - ::testing::ValuesIn(kArrayHBDSubpelAvgVariance_c)); +INSTANTIATE_TEST_SUITE_P(C, AvxHBDSubpelAvgVarianceTest, + ::testing::ValuesIn(kArrayHBDSubpelAvgVariance_c)); const ObmcSubpelVarianceParams kArrayHBDObmcSubpelVariance_c[] = { ObmcSubpelVarianceParams(7, 7, &aom_highbd_obmc_sub_pixel_variance128x128_c, @@ -1667,21 +1685,21 @@ const ObmcSubpelVarianceParams kArrayHBDObmcSubpelVariance_c[] = { ObmcSubpelVarianceParams(2, 4, &aom_highbd_12_obmc_sub_pixel_variance4x16_c, 12), }; -INSTANTIATE_TEST_CASE_P(C, AvxHBDObmcSubpelVarianceTest, - ::testing::ValuesIn(kArrayHBDObmcSubpelVariance_c)); +INSTANTIATE_TEST_SUITE_P(C, AvxHBDObmcSubpelVarianceTest, + ::testing::ValuesIn(kArrayHBDObmcSubpelVariance_c)); #endif // CONFIG_AV1_HIGHBITDEPTH #if HAVE_SSE2 -INSTANTIATE_TEST_CASE_P(SSE2, SumOfSquaresTest, - ::testing::Values(aom_get_mb_ss_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, SumOfSquaresTest, + ::testing::Values(aom_get_mb_ss_sse2)); -INSTANTIATE_TEST_CASE_P(SSE2, AvxMseTest, - ::testing::Values(MseParams(4, 4, &aom_mse16x16_sse2), - MseParams(4, 3, &aom_mse16x8_sse2), - MseParams(3, 4, &aom_mse8x16_sse2), - MseParams(3, 3, &aom_mse8x8_sse2))); +INSTANTIATE_TEST_SUITE_P(SSE2, AvxMseTest, + ::testing::Values(MseParams(4, 4, &aom_mse16x16_sse2), + MseParams(4, 3, &aom_mse16x8_sse2), + MseParams(3, 4, &aom_mse8x16_sse2), + MseParams(3, 3, &aom_mse8x8_sse2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AvxVarianceTest, ::testing::Values(VarianceParams(7, 7, &aom_variance128x128_sse2), VarianceParams(7, 6, &aom_variance128x64_sse2), @@ -1706,7 +1724,7 @@ INSTANTIATE_TEST_CASE_P( VarianceParams(2, 3, &aom_variance4x8_sse2), VarianceParams(2, 2, &aom_variance4x4_sse2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(7, 7, &aom_sub_pixel_variance128x128_sse2, 0), @@ -1733,7 +1751,7 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(4, 2, &aom_sub_pixel_variance16x4_sse2, 0), SubpelVarianceParams(2, 4, &aom_sub_pixel_variance4x16_sse2, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(7, 7, &aom_sub_pixel_avg_variance128x128_sse2, @@ -1766,7 +1784,7 @@ INSTANTIATE_TEST_CASE_P( #if CONFIG_AV1_HIGHBITDEPTH #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(2, 2, &aom_highbd_8_sub_pixel_variance4x4_sse4_1, @@ -1776,7 +1794,7 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(2, 2, &aom_highbd_12_sub_pixel_variance4x4_sse4_1, 12))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(2, 2, @@ -1791,7 +1809,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE4_1 /* TODO(debargha): This test does not support the highbd version -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE2, AvxHBDMseTest, ::testing::Values(MseParams(4, 4, &aom_highbd_12_mse16x16_sse2), MseParams(4, 3, &aom_highbd_12_mse16x8_sse2), @@ -1867,8 +1885,8 @@ const VarianceParams kArrayHBDVariance_sse2[] = { // VarianceParams(4, 2, &aom_highbd_8_variance16x4_sse2, 8), // VarianceParams(2, 4, &aom_highbd_8_variance4x16_sse2, 8), }; -INSTANTIATE_TEST_CASE_P(SSE2, AvxHBDVarianceTest, - ::testing::ValuesIn(kArrayHBDVariance_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AvxHBDVarianceTest, + ::testing::ValuesIn(kArrayHBDVariance_sse2)); #if HAVE_AVX2 @@ -1888,8 +1906,8 @@ const VarianceParams kArrayHBDVariance_avx2[] = { VarianceParams(3, 3, &aom_highbd_10_variance8x8_avx2, 10), }; -INSTANTIATE_TEST_CASE_P(AVX2, AvxHBDVarianceTest, - ::testing::ValuesIn(kArrayHBDVariance_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, AvxHBDVarianceTest, + ::testing::ValuesIn(kArrayHBDVariance_avx2)); #endif // HAVE_AVX2 const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { @@ -1955,8 +1973,8 @@ const SubpelVarianceParams kArrayHBDSubpelVariance_sse2[] = { SubpelVarianceParams(4, 2, &aom_highbd_8_sub_pixel_variance16x4_sse2, 8), // SubpelVarianceParams(2, 4, &aom_highbd_8_sub_pixel_variance4x16_sse2, 8), }; -INSTANTIATE_TEST_CASE_P(SSE2, AvxHBDSubpelVarianceTest, - ::testing::ValuesIn(kArrayHBDSubpelVariance_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AvxHBDSubpelVarianceTest, + ::testing::ValuesIn(kArrayHBDSubpelVariance_sse2)); const SubpelAvgVarianceParams kArrayHBDSubpelAvgVariance_sse2[] = { SubpelAvgVarianceParams(6, 6, &aom_highbd_12_sub_pixel_avg_variance64x64_sse2, @@ -2064,13 +2082,13 @@ const SubpelAvgVarianceParams kArrayHBDSubpelAvgVariance_sse2[] = { // &aom_highbd_8_sub_pixel_avg_variance4x16_sse2, 8), }; -INSTANTIATE_TEST_CASE_P(SSE2, AvxHBDSubpelAvgVarianceTest, - ::testing::ValuesIn(kArrayHBDSubpelAvgVariance_sse2)); +INSTANTIATE_TEST_SUITE_P(SSE2, AvxHBDSubpelAvgVarianceTest, + ::testing::ValuesIn(kArrayHBDSubpelAvgVariance_sse2)); #endif // HAVE_SSE2 #endif // CONFIG_AV1_HIGHBITDEPTH #if HAVE_SSSE3 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(7, 7, &aom_sub_pixel_variance128x128_ssse3, 0), @@ -2097,7 +2115,7 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(4, 2, &aom_sub_pixel_variance16x4_ssse3, 0), SubpelVarianceParams(2, 4, &aom_sub_pixel_variance4x16_ssse3, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(7, 7, &aom_sub_pixel_avg_variance128x128_ssse3, @@ -2137,7 +2155,7 @@ INSTANTIATE_TEST_CASE_P( SubpelAvgVarianceParams(2, 4, &aom_sub_pixel_avg_variance4x16_ssse3, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSSE3, AvxDistWtdSubpelAvgVarianceTest, ::testing::Values( DistWtdSubpelAvgVarianceParams( @@ -2188,7 +2206,7 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSSE3 #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AvxObmcSubpelVarianceTest, ::testing::Values( ObmcSubpelVarianceParams(7, 7, @@ -2239,10 +2257,11 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, AvxMseTest, - ::testing::Values(MseParams(4, 4, &aom_mse16x16_avx2))); +INSTANTIATE_TEST_SUITE_P(AVX2, AvxMseTest, + ::testing::Values(MseParams(4, 4, + &aom_mse16x16_avx2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AvxVarianceTest, ::testing::Values(VarianceParams(7, 7, &aom_variance128x128_avx2), VarianceParams(7, 6, &aom_variance128x64_avx2), @@ -2260,7 +2279,7 @@ INSTANTIATE_TEST_CASE_P( VarianceParams(4, 3, &aom_variance16x8_avx2), VarianceParams(4, 2, &aom_variance16x4_avx2))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(7, 7, &aom_sub_pixel_variance128x128_avx2, 0), @@ -2270,9 +2289,14 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(6, 5, &aom_sub_pixel_variance64x32_avx2, 0), SubpelVarianceParams(5, 6, &aom_sub_pixel_variance32x64_avx2, 0), SubpelVarianceParams(5, 5, &aom_sub_pixel_variance32x32_avx2, 0), - SubpelVarianceParams(5, 4, &aom_sub_pixel_variance32x16_avx2, 0))); + SubpelVarianceParams(5, 4, &aom_sub_pixel_variance32x16_avx2, 0), + SubpelVarianceParams(4, 6, &aom_sub_pixel_variance16x64_avx2, 0), + SubpelVarianceParams(4, 5, &aom_sub_pixel_variance16x32_avx2, 0), + SubpelVarianceParams(4, 4, &aom_sub_pixel_variance16x16_avx2, 0), + SubpelVarianceParams(4, 3, &aom_sub_pixel_variance16x8_avx2, 0), + SubpelVarianceParams(4, 2, &aom_sub_pixel_variance16x4_avx2, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(7, 7, &aom_sub_pixel_avg_variance128x128_avx2, @@ -2290,16 +2314,18 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_AVX2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P(NEON, AvxSseTest, - ::testing::Values(SseParams(2, 2, - &aom_get4x4sse_cs_neon))); +INSTANTIATE_TEST_SUITE_P(NEON, AvxSseTest, + ::testing::Values(SseParams(2, 2, + &aom_get4x4sse_cs_neon))); -INSTANTIATE_TEST_CASE_P(NEON, AvxMseTest, - ::testing::Values(MseParams(4, 4, &aom_mse16x16_neon))); +INSTANTIATE_TEST_SUITE_P(NEON, AvxMseTest, + ::testing::Values(MseParams(4, 4, + &aom_mse16x16_neon))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AvxVarianceTest, - ::testing::Values(VarianceParams(6, 6, &aom_variance64x64_neon), + ::testing::Values(VarianceParams(7, 7, &aom_variance128x128_neon), + VarianceParams(6, 6, &aom_variance64x64_neon), VarianceParams(6, 5, &aom_variance64x32_neon), VarianceParams(5, 6, &aom_variance32x64_neon), VarianceParams(5, 5, &aom_variance32x32_neon), @@ -2308,7 +2334,7 @@ INSTANTIATE_TEST_CASE_P( VarianceParams(3, 4, &aom_variance8x16_neon), VarianceParams(3, 3, &aom_variance8x8_neon))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(6, 6, &aom_sub_pixel_variance64x64_neon, 0), @@ -2318,20 +2344,20 @@ INSTANTIATE_TEST_CASE_P( #endif // HAVE_NEON #if HAVE_MSA -INSTANTIATE_TEST_CASE_P(MSA, SumOfSquaresTest, - ::testing::Values(aom_get_mb_ss_msa)); +INSTANTIATE_TEST_SUITE_P(MSA, SumOfSquaresTest, + ::testing::Values(aom_get_mb_ss_msa)); -INSTANTIATE_TEST_CASE_P(MSA, AvxSseTest, - ::testing::Values(SseParams(2, 2, - &aom_get4x4sse_cs_msa))); +INSTANTIATE_TEST_SUITE_P(MSA, AvxSseTest, + ::testing::Values(SseParams(2, 2, + &aom_get4x4sse_cs_msa))); -INSTANTIATE_TEST_CASE_P(MSA, AvxMseTest, - ::testing::Values(MseParams(4, 4, &aom_mse16x16_msa), - MseParams(4, 3, &aom_mse16x8_msa), - MseParams(3, 4, &aom_mse8x16_msa), - MseParams(3, 3, &aom_mse8x8_msa))); +INSTANTIATE_TEST_SUITE_P(MSA, AvxMseTest, + ::testing::Values(MseParams(4, 4, &aom_mse16x16_msa), + MseParams(4, 3, &aom_mse16x8_msa), + MseParams(3, 4, &aom_mse8x16_msa), + MseParams(3, 3, &aom_mse8x8_msa))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MSA, AvxVarianceTest, ::testing::Values(VarianceParams(6, 6, &aom_variance64x64_msa), VarianceParams(6, 5, &aom_variance64x32_msa), @@ -2347,7 +2373,7 @@ INSTANTIATE_TEST_CASE_P( VarianceParams(2, 3, &aom_variance4x8_msa), VarianceParams(2, 2, &aom_variance4x4_msa))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MSA, AvxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(2, 2, &aom_sub_pixel_variance4x4_msa, 0), @@ -2364,7 +2390,7 @@ INSTANTIATE_TEST_CASE_P( SubpelVarianceParams(6, 5, &aom_sub_pixel_variance64x32_msa, 0), SubpelVarianceParams(6, 6, &aom_sub_pixel_variance64x64_msa, 0))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MSA, AvxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(6, 6, &aom_sub_pixel_avg_variance64x64_msa, 0), diff --git a/media/libaom/src/test/warp_filter_test.cc b/media/libaom/src/test/warp_filter_test.cc index cb7ba04aac..c5e87f0859 100644 --- a/media/libaom/src/test/warp_filter_test.cc +++ b/media/libaom/src/test/warp_filter_test.cc @@ -8,6 +8,8 @@ * 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/warp_filter_test_util.h" using libaom_test::ACMRandom; @@ -15,49 +17,49 @@ using libaom_test::ACMRandom; using libaom_test::AV1HighbdWarpFilter::AV1HighbdWarpFilterTest; #endif using libaom_test::AV1WarpFilter::AV1WarpFilterTest; -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace { TEST_P(AV1WarpFilterTest, CheckOutput) { - RunCheckOutput(::testing::get<3>(GET_PARAM(0))); + RunCheckOutput(std::get<3>(GET_PARAM(0))); } TEST_P(AV1WarpFilterTest, DISABLED_Speed) { - RunSpeedTest(::testing::get<3>(GET_PARAM(0))); + RunSpeedTest(std::get<3>(GET_PARAM(0))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( C, AV1WarpFilterTest, libaom_test::AV1WarpFilter::BuildParams(av1_warp_affine_c)); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SSE4_1, AV1WarpFilterTest, libaom_test::AV1WarpFilter::BuildParams(av1_warp_affine_sse4_1)); #if CONFIG_AV1_HIGHBITDEPTH TEST_P(AV1HighbdWarpFilterTest, CheckOutput) { - RunCheckOutput(::testing::get<4>(GET_PARAM(0))); + RunCheckOutput(std::get<4>(GET_PARAM(0))); } TEST_P(AV1HighbdWarpFilterTest, DISABLED_Speed) { - RunSpeedTest(::testing::get<4>(GET_PARAM(0))); + RunSpeedTest(std::get<4>(GET_PARAM(0))); } -INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdWarpFilterTest, - libaom_test::AV1HighbdWarpFilter::BuildParams( - av1_highbd_warp_affine_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1HighbdWarpFilterTest, + libaom_test::AV1HighbdWarpFilter::BuildParams( + av1_highbd_warp_affine_sse4_1)); #endif // CONFIG_AV1_HIGHBITDEPTH #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AVX2, AV1WarpFilterTest, libaom_test::AV1WarpFilter::BuildParams(av1_warp_affine_avx2)); #endif // HAVE_AVX2 #if HAVE_NEON -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NEON, AV1WarpFilterTest, libaom_test::AV1WarpFilter::BuildParams(av1_warp_affine_neon)); #endif // HAVE_NEON diff --git a/media/libaom/src/test/warp_filter_test_util.cc b/media/libaom/src/test/warp_filter_test_util.cc index 91d040ac51..bcb0c18592 100644 --- a/media/libaom/src/test/warp_filter_test_util.cc +++ b/media/libaom/src/test/warp_filter_test_util.cc @@ -11,8 +11,8 @@ #include "aom_ports/aom_timer.h" #include "test/warp_filter_test_util.h" -using ::testing::make_tuple; -using ::testing::tuple; +using std::make_tuple; +using std::tuple; namespace libaom_test { @@ -55,8 +55,9 @@ void generate_warped_model(libaom_test::ACMRandom *rnd, int32_t *mat, if (is_beta_zero == 1) mat[3] = 0; if (is_gamma_zero == 1) mat[4] = 0; if (is_delta_zero == 1) - mat[5] = (((int64_t)mat[3] * mat[4] + (mat[2] / 2)) / mat[2]) + - (1 << WARPEDMODEL_PREC_BITS); + mat[5] = static_cast( + ((static_cast(mat[3]) * mat[4] + (mat[2] / 2)) / mat[2]) + + (1 << WARPEDMODEL_PREC_BITS)); } // Calculate the derived parameters and check that they are suitable @@ -65,12 +66,14 @@ void generate_warped_model(libaom_test::ACMRandom *rnd, int32_t *mat, *alpha = clamp(mat[2] - (1 << WARPEDMODEL_PREC_BITS), INT16_MIN, INT16_MAX); *beta = clamp(mat[3], INT16_MIN, INT16_MAX); - *gamma = clamp(((int64_t)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) / mat[2], - INT16_MIN, INT16_MAX); - *delta = - clamp(mat[5] - (((int64_t)mat[3] * mat[4] + (mat[2] / 2)) / mat[2]) - - (1 << WARPEDMODEL_PREC_BITS), - INT16_MIN, INT16_MAX); + *gamma = static_cast(clamp64( + (static_cast(mat[4]) * (1 << WARPEDMODEL_PREC_BITS)) / mat[2], + INT16_MIN, INT16_MAX)); + *delta = static_cast(clamp64( + mat[5] - + ((static_cast(mat[3]) * mat[4] + (mat[2] / 2)) / mat[2]) - + (1 << WARPEDMODEL_PREC_BITS), + INT16_MIN, INT16_MAX)); if ((4 * abs(*alpha) + 7 * abs(*beta) >= (1 << WARPEDMODEL_PREC_BITS)) || (4 * abs(*gamma) + 4 * abs(*delta) >= (1 << WARPEDMODEL_PREC_BITS))) @@ -113,8 +116,7 @@ void AV1WarpFilterTest::RunSpeedTest(warp_affine_func test_impl) { const int border = 16; const int stride = w + 2 * border; WarpTestParam params = GET_PARAM(0); - const int out_w = ::testing::get<0>(params), - out_h = ::testing::get<1>(params); + const int out_w = std::get<0>(params), out_h = std::get<1>(params); const int is_alpha_zero = GET_PARAM(1); const int is_beta_zero = GET_PARAM(2); const int is_gamma_zero = GET_PARAM(3); @@ -177,9 +179,8 @@ void AV1WarpFilterTest::RunCheckOutput(warp_affine_func test_impl) { const int is_beta_zero = GET_PARAM(2); const int is_gamma_zero = GET_PARAM(3); const int is_delta_zero = GET_PARAM(4); - const int out_w = ::testing::get<0>(params), - out_h = ::testing::get<1>(params); - const int num_iters = ::testing::get<2>(params); + const int out_w = std::get<0>(params), out_h = std::get<1>(params); + const int num_iters = std::get<2>(params); int i, j, sub_x, sub_y; const int bd = 8; @@ -311,8 +312,8 @@ void AV1HighbdWarpFilterTest::RunSpeedTest(highbd_warp_affine_func test_impl) { const int is_beta_zero = GET_PARAM(2); const int is_gamma_zero = GET_PARAM(3); const int is_delta_zero = GET_PARAM(4); - const int out_w = ::testing::get<0>(param), out_h = ::testing::get<1>(param); - const int bd = ::testing::get<3>(param); + const int out_w = std::get<0>(param), out_h = std::get<1>(param); + const int bd = std::get<3>(param); const int mask = (1 << bd) - 1; int sub_x, sub_y; @@ -374,9 +375,9 @@ void AV1HighbdWarpFilterTest::RunCheckOutput( const int is_beta_zero = GET_PARAM(2); const int is_gamma_zero = GET_PARAM(3); const int is_delta_zero = GET_PARAM(4); - const int out_w = ::testing::get<0>(param), out_h = ::testing::get<1>(param); - const int bd = ::testing::get<3>(param); - const int num_iters = ::testing::get<2>(param); + const int out_w = std::get<0>(param), out_h = std::get<1>(param); + const int bd = std::get<3>(param); + const int num_iters = std::get<2>(param); const int mask = (1 << bd) - 1; int i, j, sub_x, sub_y; diff --git a/media/libaom/src/test/warp_filter_test_util.h b/media/libaom/src/test/warp_filter_test_util.h index 23749fb18b..66a6e244be 100644 --- a/media/libaom/src/test/warp_filter_test_util.h +++ b/media/libaom/src/test/warp_filter_test_util.h @@ -12,6 +12,8 @@ #ifndef AOM_TEST_WARP_FILTER_TEST_UTIL_H_ #define AOM_TEST_WARP_FILTER_TEST_UTIL_H_ +#include + #include "config/av1_rtcd.h" #include "config/aom_dsp_rtcd.h" @@ -41,8 +43,8 @@ typedef void (*warp_affine_func)(const int32_t *mat, const uint8_t *ref, ConvolveParams *conv_params, int16_t alpha, int16_t beta, int16_t gamma, int16_t delta); -typedef ::testing::tuple WarpTestParam; -typedef ::testing::tuple WarpTestParams; +typedef std::tuple WarpTestParam; +typedef std::tuple WarpTestParams; ::testing::internal::ParamGenerator BuildParams( warp_affine_func filter); @@ -74,9 +76,9 @@ typedef void (*highbd_warp_affine_func)(const int32_t *mat, const uint16_t *ref, int16_t alpha, int16_t beta, int16_t gamma, int16_t delta); -typedef ::testing::tuple +typedef std::tuple HighbdWarpTestParam; -typedef ::testing::tuple +typedef std::tuple HighbdWarpTestParams; ::testing::internal::ParamGenerator BuildParams( diff --git a/media/libaom/src/test/wiener_test.cc b/media/libaom/src/test/wiener_test.cc index 68bf3ad7c5..81839fd56f 100644 --- a/media/libaom/src/test/wiener_test.cc +++ b/media/libaom/src/test/wiener_test.cc @@ -9,6 +9,7 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include #include #include "third_party/googletest/src/googletest/include/gtest/gtest.h" @@ -115,7 +116,7 @@ typedef void (*compute_stats_Func)(int wiener_win, const uint8_t *dgd, // 8 bit //////////////////////////////////////////////////////////////////////////////// -typedef ::testing::tuple WienerTestParam; +typedef std::tuple WienerTestParam; class WienerTest : public ::testing::TestWithParam { public: @@ -269,17 +270,17 @@ TEST_P(WienerTest, DISABLED_Speed) { RunWienerTest(WIENER_WIN_CHROMA, 200); } -INSTANTIATE_TEST_CASE_P(C, WienerTest, ::testing::Values(compute_stats_opt_c)); +INSTANTIATE_TEST_SUITE_P(C, WienerTest, ::testing::Values(compute_stats_opt_c)); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, WienerTest, - ::testing::Values(av1_compute_stats_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, WienerTest, + ::testing::Values(av1_compute_stats_sse4_1)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, WienerTest, - ::testing::Values(av1_compute_stats_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, WienerTest, + ::testing::Values(av1_compute_stats_avx2)); #endif // HAVE_AVX2 } // namespace wiener_lowbd @@ -390,7 +391,7 @@ typedef void (*compute_stats_Func)(int wiener_win, const uint8_t *dgd, int src_stride, int64_t *M, int64_t *H, aom_bit_depth_t bit_depth); -typedef ::testing::tuple WienerTestParam; +typedef std::tuple WienerTestParam; class WienerTestHighbd : public ::testing::TestWithParam { public: @@ -569,17 +570,17 @@ TEST_P(WienerTestHighbd, DISABLED_Speed) { RunWienerTest(WIENER_WIN_CHROMA, 200, AOM_BITS_12); } -INSTANTIATE_TEST_CASE_P(C, WienerTestHighbd, - ::testing::Values(compute_stats_highbd_opt_c)); +INSTANTIATE_TEST_SUITE_P(C, WienerTestHighbd, + ::testing::Values(compute_stats_highbd_opt_c)); #if HAVE_SSE4_1 -INSTANTIATE_TEST_CASE_P(SSE4_1, WienerTestHighbd, - ::testing::Values(av1_compute_stats_highbd_sse4_1)); +INSTANTIATE_TEST_SUITE_P(SSE4_1, WienerTestHighbd, + ::testing::Values(av1_compute_stats_highbd_sse4_1)); #endif // HAVE_SSE4_1 #if HAVE_AVX2 -INSTANTIATE_TEST_CASE_P(AVX2, WienerTestHighbd, - ::testing::Values(av1_compute_stats_highbd_avx2)); +INSTANTIATE_TEST_SUITE_P(AVX2, WienerTestHighbd, + ::testing::Values(av1_compute_stats_highbd_avx2)); #endif // HAVE_AVX2 } // namespace wiener_highbd diff --git a/media/libaom/src/test/y4m_test.cc b/media/libaom/src/test/y4m_test.cc index 6cc75ef5b0..5d795fad9d 100644 --- a/media/libaom/src/test/y4m_test.cc +++ b/media/libaom/src/test/y4m_test.cc @@ -121,8 +121,8 @@ TEST_P(Y4mVideoSourceTest, SourceTest) { Md5Check(t.md5raw); } -INSTANTIATE_TEST_CASE_P(C, Y4mVideoSourceTest, - ::testing::ValuesIn(kY4mTestVectors)); +INSTANTIATE_TEST_SUITE_P(C, Y4mVideoSourceTest, + ::testing::ValuesIn(kY4mTestVectors)); class Y4mVideoWriteTest : public Y4mVideoSourceTest { protected: @@ -175,6 +175,6 @@ TEST_P(Y4mVideoWriteTest, WriteTest) { Md5Check(t.md5raw); } -INSTANTIATE_TEST_CASE_P(C, Y4mVideoWriteTest, - ::testing::ValuesIn(kY4mTestVectors)); +INSTANTIATE_TEST_SUITE_P(C, Y4mVideoWriteTest, + ::testing::ValuesIn(kY4mTestVectors)); } // namespace diff --git a/media/libaom/src/third_party/googletest/README.libaom b/media/libaom/src/third_party/googletest/README.libaom index 6fd567c28f..9b8a863980 100644 --- a/media/libaom/src/third_party/googletest/README.libaom +++ b/media/libaom/src/third_party/googletest/README.libaom @@ -1,5 +1,5 @@ URL: https://github.com/google/googletest -Version: 1.8.1 +Version: 1.10.x License: BSD License File: LICENSE @@ -12,13 +12,6 @@ failures, various options for running the tests, and XML test report generation. Local Modifications: -- Remove everything but: - googletest-release-1.8.0/googletest/ - cmake/ - include/ - src/ - CHANGES - CMakelists.txt - CONTRIBUTORS - LICENSE - README.md +- Replace everything in: + third_party/googletest/src/googletest/src/ + third_party/googletest/src/googletest/include/ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-death-test.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-death-test.h index 20c54d8695..39f0ded1b5 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-death-test.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-death-test.h @@ -161,29 +161,28 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// FIXME: make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. -# define ASSERT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) +#define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: -# define EXPECT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) +// test suite, if any: +#define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. -# define ASSERT_DEATH(statement, regex) \ - ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) +#define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: -# define EXPECT_DEATH(statement, regex) \ - EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) +// test suite, if any: +#define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: @@ -192,14 +191,15 @@ class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; + private: // No implementation - assignment is unsupported. - void operator=(const ExitedWithCode& other); + void operator=(const ExitedWithCode &other); const int exit_code_; }; -# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. // GOOGLETEST_CM0006 DO NOT DELETE @@ -207,10 +207,11 @@ class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; + private: const int signum_; }; -# endif // !GTEST_OS_WINDOWS +#endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, @@ -228,7 +229,7 @@ class GTEST_API_ KilledBySignal { // return 12; // } // -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); @@ -255,42 +256,40 @@ class GTEST_API_ KilledBySignal { // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // -# ifdef NDEBUG +#ifdef NDEBUG -# define EXPECT_DEBUG_DEATH(statement, regex) \ +#define EXPECT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) -# define ASSERT_DEBUG_DEATH(statement, regex) \ +#define ASSERT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) -# else +#else -# define EXPECT_DEBUG_DEATH(statement, regex) \ - EXPECT_DEATH(statement, regex) +#define EXPECT_DEBUG_DEATH(statement, regex) EXPECT_DEATH(statement, regex) -# define ASSERT_DEBUG_DEATH(statement, regex) \ - ASSERT_DEATH(statement, regex) +#define ASSERT_DEBUG_DEATH(statement, regex) ASSERT_DEATH(statement, regex) -# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. It is exposed publicly so that -// systems that have death-tests with stricter requirements than -// GTEST_HAS_DEATH_TEST can write their own equivalent of -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED. +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. +// parameter if and only if EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that @@ -309,18 +308,17 @@ class GTEST_API_ KilledBySignal { // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() +#define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if @@ -328,15 +326,15 @@ class GTEST_API_ KilledBySignal { // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH(statement, regex) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - ASSERT_DEATH(statement, regex) +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) #else -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return ) #endif } // namespace testing diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-matchers.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-matchers.h new file mode 100644 index 0000000000..20be24f43c --- /dev/null +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-matchers.h @@ -0,0 +1,769 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +// IWYU pragma: private, include "testing/base/public/gunit.h" +// IWYU pragma: friend third_party/googletest/googlemock/.* +// IWYU pragma: friend third_party/googletest/googletest/.* + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherImpl that implements the +// MatcherInterface interface, and +// 2. a factory function that creates a Matcher object from a +// FooMatcherImpl*. +// +// The two-level delegation design makes it possible to allow a user +// to write "v" instead of "Eq(v)" where a Matcher is expected, which +// is impossible if we pass matchers by pointers. It also eases +// ownership management as Matcher objects can now be copied like +// plain values. + +// MatchResultListener is an abstract class. Its << operator can be +// used by a matcher to explain why a value matches or doesn't match. +// +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream *os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener &operator<<(const T &x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream *stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream *const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() {} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream *os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream *os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener *listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +// Converts a MatcherInterface to a MatcherInterface. +template +class MatcherInterfaceAdapter : public MatcherInterface { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface *impl) + : impl_(impl) {} + ~MatcherInterfaceAdapter() override { delete impl_; } + + void DescribeTo(::std::ostream *os) const override { impl_->DescribeTo(os); } + + void DescribeNegationTo(::std::ostream *os) const override { + impl_->DescribeNegationTo(os); + } + + bool MatchAndExplain(const T &x, + MatchResultListener *listener) const override { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface *const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +struct AnyEq { + template + bool operator()(const A &a, const B &b) const { + return a == b; + } +}; +struct AnyNe { + template + bool operator()(const A &a, const B &b) const { + return a != b; + } +}; +struct AnyLt { + template + bool operator()(const A &a, const B &b) const { + return a < b; + } +}; +struct AnyGt { + template + bool operator()(const A &a, const B &b) const { + return a > b; + } +}; +struct AnyLe { + template + bool operator()(const A &a, const B &b) const { + return a <= b; + } +}; +struct AnyGe { + template + bool operator()(const A &a, const B &b) const { + return a >= b; + } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream *os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T &x, MatchResultListener *listener) const { + return impl_->MatchAndExplain(x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T &x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream *os) const { impl_->DescribeTo(os); } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream *os) const { + impl_->DescribeNegationTo(os); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T &x, ::std::ostream *os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface *GetDescriber() const { return impl_.get(); } + + protected: + MatcherBase() {} + + // Constructs a matcher from its implementation. + explicit MatcherBase(const MatcherInterface *impl) : impl_(impl) {} + + template + explicit MatcherBase( + const MatcherInterface *impl, + typename std::enable_if::value>::type * = + nullptr) + : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + + MatcherBase(const MatcherBase &) = default; + MatcherBase &operator=(const MatcherBase &) = default; + MatcherBase(MatcherBase &&) = default; + MatcherBase &operator=(MatcherBase &&) = default; + + virtual ~MatcherBase() {} + + private: + std::shared_ptr> impl_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + + template + explicit Matcher( + const MatcherInterface *impl, + typename std::enable_if::value>::type * = + nullptr) + : internal::MatcherBase(impl) {} + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string &s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char *s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string &s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char *s); // NOLINT +}; + +#if GTEST_INTERNAL_HAS_STRING_VIEW +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string &s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char *s); // NOLINT + + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface *impl) + : internal::MatcherBase(impl) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string &s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char *s); // NOLINT + + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT +}; +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + +// Prints a matcher in a human-readable format. +template +std::ostream &operator<<(std::ostream &os, const Matcher &matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl &an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl &mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl &impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl &impl) : impl_(impl) {} + + void DescribeTo(::std::ostream *os) const override { impl_.DescribeTo(os); } + + void DescribeNegationTo(::std::ostream *os) const override { + impl_.DescribeNegationTo(os); + } + + bool MatchAndExplain(T x, MatchResultListener *listener) const override { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher(new MyMatcherImpl(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template +inline Matcher MakeMatcher(const MatcherInterface *impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl &impl) { + return PolymorphicMatcher(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs &rhs) : rhs_(rhs) {} + template + operator Matcher() const { + return Matcher(new Impl(rhs_)); + } + + private: + template + static const T &Unwrap(const T &v) { + return v; + } + template + static const T &Unwrap(std::reference_wrapper v) { + return v; + } + + template + class Impl : public MatcherInterface { + public: + explicit Impl(const Rhs &rhs) : rhs_(rhs) {} + bool MatchAndExplain(Lhs lhs, + MatchResultListener * /* listener */) const override { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(::std::ostream *os) const override { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(::std::ostream *os) const override { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + Rhs rhs_; + }; + Rhs rhs_; +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) {} + static const char *Desc() { return "is equal to"; } + static const char *NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) {} + static const char *Desc() { return "isn't equal to"; } + static const char *NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) {} + static const char *Desc() { return "is <"; } + static const char *NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) {} + static const char *Desc() { return "is >"; } + static const char *NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) {} + static const char *Desc() { return "is <="; } + static const char *NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs &rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) {} + static const char *Desc() { return "is >="; } + static const char *NegatedDesc() { return "isn't >="; } +}; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE *regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_INTERNAL_HAS_STRING_VIEW + bool MatchAndExplain(const internal::StringView &s, + MatchResultListener *listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType *s, MatchResultListener *listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType &s, + MatchResultListener * /* listener */) const { + const std::string &s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream *os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream *os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE *regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +inline PolymorphicMatcher MatchesRegex( + const std::string ®ex) { + return MatchesRegex(new internal::RE(regex)); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE *regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +inline PolymorphicMatcher ContainsRegex( + const std::string ®ex) { + return ContainsRegex(new internal::RE(regex)); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { + return internal::EqMatcher(x); +} + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { + *this = Eq(value); +} + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs &rhs) { + return Eq(rhs); +} + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-message.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-message.h index 5ca041614c..713facae84 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-message.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-message.h @@ -48,6 +48,8 @@ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include +#include +#include #include "gtest/internal/gtest-port.h" @@ -56,7 +58,7 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. -void operator<<(const testing::internal::Secret&, int); +void operator<<(const testing::internal::Secret &, int); namespace testing { @@ -90,33 +92,25 @@ class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. - typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + typedef std::ostream &(*BasicNarrowIoManip)(std::ostream &); public: // Constructs an empty Message. Message(); // Copy constructor. - Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + Message(const Message &msg) : ss_(new ::std::stringstream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. - explicit Message(const char* str) : ss_(new ::std::stringstream) { + explicit Message(const char *str) : ss_(new ::std::stringstream) { *ss_ << str; } -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else // Streams a non-pointer value to this object. template - inline Message& operator <<(const T& val) { + inline Message &operator<<(const T &val) { // Some libraries overload << for STL containers. These // overloads are defined in the global namespace instead of ::std. // @@ -131,7 +125,7 @@ class GTEST_API_ Message { // from the global namespace. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. - using ::operator <<; + using ::operator<<; *ss_ << val; return *this; } @@ -150,15 +144,14 @@ class GTEST_API_ Message { // ensure consistent result across compilers, we always treat NULL // as "(null)". template - inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { + inline Message &operator<<(T *const &pointer) { // NOLINT + if (pointer == nullptr) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } -#endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition @@ -166,33 +159,25 @@ class GTEST_API_ Message { // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. - Message& operator <<(BasicNarrowIoManip val) { + Message &operator<<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. - Message& operator <<(bool b) { - return *this << (b ? "true" : "false"); - } + Message &operator<<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. - Message& operator <<(const wchar_t* wide_c_str); - Message& operator <<(wchar_t* wide_c_str); + Message &operator<<(const wchar_t *wide_c_str); + Message &operator<<(wchar_t *wide_c_str); #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. - Message& operator <<(const ::std::wstring& wstr); + Message &operator<<(const ::std::wstring &wstr); #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // @@ -200,39 +185,16 @@ class GTEST_API_ Message { std::string GetString() const; private: -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; + const std::unique_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. - void operator=(const Message&); + void operator=(const Message &); }; // Streams a Message to an ostream. -inline std::ostream& operator <<(std::ostream& os, const Message& sb) { +inline std::ostream &operator<<(std::ostream &os, const Message &sb) { return os << sb.GetString(); } @@ -243,7 +205,7 @@ namespace internal { // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". template -std::string StreamableToString(const T& streamable) { +std::string StreamableToString(const T &streamable) { return (Message() << streamable).GetString(); } diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h index 3e95e4390e..8d01df5250 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2008, Google Inc. // All rights reserved. // @@ -40,7 +36,6 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // @@ -75,7 +70,7 @@ TEST_P(FooTest, HasBlahBlah) { ... } -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which @@ -96,17 +91,17 @@ TEST_P(FooTest, HasBlahBlah) { // For more details, see comments at the definitions of these functions below // in this file. // -// The following statement will instantiate tests from the FooTest test case +// The following statement will instantiate tests from the FooTest test suite // each with parameter values "meeny", "miny", and "moe". -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // @@ -123,7 +118,7 @@ INSTANTIATE_TEST_CASE_P(InstantiationName, // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // @@ -132,9 +127,9 @@ INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. @@ -178,26 +173,23 @@ TEST_P(DerivedTest, DoesBlah) { #endif // 0 -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include -#endif +#include +#include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" +#include "gtest/internal/gtest-port.h" namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated +// parameterized tests. When a parameterized test suite is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // -// In the following sample, tests from test case FooTest are instantiated +// In the following sample, tests from test suite FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; @@ -206,7 +198,7 @@ namespace testing { // } // TEST_P(FooTest, TestThat) { // } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. @@ -263,13 +255,13 @@ internal::ParamGenerator Range(T start, T end) { // // Examples: // -// This instantiates tests from test case StringTest +// This instantiates tests from test suite StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); // -// This instantiates tests from test case StlStringTest +// This instantiates tests from test suite StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { @@ -279,9 +271,9 @@ internal::ParamGenerator Range(T start, T end) { // return v; // } // -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest @@ -294,16 +286,15 @@ internal::ParamGenerator Range(T start, T end) { // return list; // } // ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> + typename std::iterator_traits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; + typedef typename std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } @@ -315,7 +306,7 @@ internal::ParamGenerator ValuesIn(const T (&array)[N]) { template internal::ParamGenerator ValuesIn( - const Container& container) { + const Container &container) { return ValuesIn(container.begin(), container.end()); } @@ -326,869 +317,22 @@ internal::ParamGenerator ValuesIn( // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // -// For example, this instantiates tests from test case BarTest each +// For example, this instantiates tests from test suite BarTest each // with values "one", "two", and "three": // -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); // -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // -// Currently, Values() supports from 1 to 50 parameters. // -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); +template +internal::ValueArray Values(T... v) { + return internal::ValueArray(std::move(v)...); } // Bool() allows generating tests with parameters in a set of (false, true). @@ -1201,7 +345,7 @@ internal::ValueArray50 { @@ -1209,13 +353,10 @@ internal::ValueArray50 Bool() { - return Values(false, true); -} +inline internal::ParamGenerator Bool() { return Values(false, true); } -# if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // @@ -1224,184 +365,83 @@ inline internal::ParamGenerator Bool() { // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types +// std::tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. +// Combine can have up to 10 arguments. // // Example: // -// This will instantiate tests in test case AnimalTest each one with +// This will instantiate tests in test suite AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest -// : public testing::TestWithParam > {...}; +// : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest -// : public testing::TestWithParam > { +// : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); +// std::tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); // -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); +template +internal::CartesianProductHolder Combine(const Generator &... g) { + return internal::CartesianProductHolder(g...); } -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + void TestBody() override; \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + GTEST_STRINGIFY_(test_suite_name), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory()); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestPattern(\ - GTEST_STRINGIFY_(test_case_name), \ - GTEST_STRINGIFY_(test_name), \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(\ - test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user -// to specify a function or functor that generates custom test name suffixes -// based on the test parameters. The function should accept one argument of -// type testing::TestParamInfo, and return std::string. +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo, and +// return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that // returns the value of testing::PrintToString(GetParam()). @@ -1410,24 +450,57 @@ internal::CartesianProductHolder10 \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ - const ::testing::TestParamInfo& info) { \ - return ::testing::internal::GetParamNameGen \ - (__VA_ARGS__)(info); \ - } \ - static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - >est_##prefix##test_case_name##_EvalGenerateName_, \ - __FILE__, __LINE__) +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo &info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + GTEST_STRINGIFY_(test_suite_name), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + GTEST_STRINGIFY_(prefix), \ + >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ + __FILE__, __LINE__) + +// Allow Marking a Parameterized test class as not needing to be instantiated. +#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \ + namespace gtest_do_not_use_outside_namespace_scope {} \ + static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \ + GTEST_STRINGIFY_(T)) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ } // namespace testing diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h.pump b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h.pump deleted file mode 100644 index 274f2b3b56..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-param-test.h.pump +++ /dev/null @@ -1,500 +0,0 @@ -$$ -*- mode: c++; -*- -$var n = 50 $$ Maximum length of Values arguments we want to support. -$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Macros and functions for implementing parameterized tests -// in Google C++ Testing and Mocking Framework (Google Test) -// -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// GOOGLETEST_CM0001 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - - -// Value-parameterized tests allow you to test your code with different -// parameters without writing multiple copies of the same test. -// -// Here is how you use value-parameterized tests: - -#if 0 - -// To write value-parameterized tests, first you should define a fixture -// class. It is usually derived from testing::TestWithParam (see below for -// another inheritance scheme that's sometimes useful in more complicated -// class hierarchies), where the type of your parameter values. -// TestWithParam is itself derived from testing::Test. T can be any -// copyable type. If it's a raw pointer, you are responsible for managing the -// lifespan of the pointed values. - -class FooTest : public ::testing::TestWithParam { - // You can implement all the usual class fixture members here. -}; - -// Then, use the TEST_P macro to define as many parameterized tests -// for this fixture as you want. The _P suffix is for "parameterized" -// or "pattern", whichever you prefer to think. - -TEST_P(FooTest, DoesBlah) { - // Inside a test, access the test parameter with the GetParam() method - // of the TestWithParam class: - EXPECT_TRUE(foo.Blah(GetParam())); - ... -} - -TEST_P(FooTest, HasBlahBlah) { - ... -} - -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test -// case with any set of parameters you want. Google Test defines a number -// of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which -// are all in the testing namespace: -// -// -// Range(begin, end [, step]) - Yields values {begin, begin+step, -// begin+step+step, ...}. The values do not -// include end. step defaults to 1. -// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. -// ValuesIn(container) - Yields values from a C-style array, an STL -// ValuesIn(begin,end) container, or an iterator range [begin, end). -// Bool() - Yields sequence {false, true}. -// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product -// for the math savvy) of the values generated -// by the N generators. -// -// For more details, see comments at the definitions of these functions below -// in this file. -// -// The following statement will instantiate tests from the FooTest test case -// each with parameter values "meeny", "miny", and "moe". - -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); - -// To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different -// instantiations. The tests from the instantiation above will have -// these names: -// -// * InstantiationName/FooTest.DoesBlah/0 for "meeny" -// * InstantiationName/FooTest.DoesBlah/1 for "miny" -// * InstantiationName/FooTest.DoesBlah/2 for "moe" -// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" -// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" -// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" -// -// You can use these names in --gtest_filter. -// -// This statement will instantiate all tests from FooTest again, each -// with parameter values "cat" and "dog": - -const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); - -// The tests from the instantiation above will have these names: -// -// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" -// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" -// -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. -// -// Please also note that generator expressions (including parameters to the -// generators) are evaluated in InitGoogleTest(), after main() has started. -// This allows the user on one hand, to adjust generator parameters in order -// to dynamically determine a set of tests to run and on the other hand, -// give the user a chance to inspect the generated tests with Google Test -// reflection API before RUN_ALL_TESTS() is executed. -// -// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc -// for more examples. -// -// In the future, we plan to publish the API for defining new parameter -// generators. But for now this interface remains part of the internal -// implementation and is subject to change. -// -// -// A parameterized test fixture must be derived from testing::Test and from -// testing::WithParamInterface, where T is the type of the parameter -// values. Inheriting from TestWithParam satisfies that requirement because -// TestWithParam inherits from both Test and WithParamInterface. In more -// complicated hierarchies, however, it is occasionally useful to inherit -// separately from Test and WithParamInterface. For example: - -class BaseTest : public ::testing::Test { - // You can inherit all the usual members for a non-parameterized test - // fixture here. -}; - -class DerivedTest : public BaseTest, public ::testing::WithParamInterface { - // The usual test fixture members go here too. -}; - -TEST_F(BaseTest, HasFoo) { - // This is an ordinary non-parameterized test. -} - -TEST_P(DerivedTest, DoesBlah) { - // GetParam works just the same here as if you inherit from TestWithParam. - EXPECT_TRUE(foo.Blah(GetParam())); -} - -#endif // 0 - -#include "gtest/internal/gtest-port.h" - -#if !GTEST_OS_SYMBIAN -# include -#endif - -#include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-param-util-generated.h" - -namespace testing { - -// Functions producing parameter generators. -// -// Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated -// with a particular generator, Google Test creates and runs tests -// for each element in the sequence produced by the generator. -// -// In the following sample, tests from test case FooTest are instantiated -// each three times with parameter values 3, 5, and 8: -// -// class FooTest : public TestWithParam { ... }; -// -// TEST_P(FooTest, TestThis) { -// } -// TEST_P(FooTest, TestThat) { -// } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); -// - -// Range() returns generators providing sequences of values in a range. -// -// Synopsis: -// Range(start, end) -// - returns a generator producing a sequence of values {start, start+1, -// start+2, ..., }. -// Range(start, end, step) -// - returns a generator producing a sequence of values {start, start+step, -// start+step+step, ..., }. -// Notes: -// * The generated sequences never include end. For example, Range(1, 5) -// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) -// returns a generator producing {1, 3, 5, 7}. -// * start and end must have the same type. That type may be any integral or -// floating-point type or a user defined type satisfying these conditions: -// * It must be assignable (have operator=() defined). -// * It must have operator+() (operator+(int-compatible type) for -// two-operand version). -// * It must have operator<() defined. -// Elements in the resulting sequences will also have that type. -// * Condition start < end must be satisfied in order for resulting sequences -// to contain any elements. -// -template -internal::ParamGenerator Range(T start, T end, IncrementT step) { - return internal::ParamGenerator( - new internal::RangeGenerator(start, end, step)); -} - -template -internal::ParamGenerator Range(T start, T end) { - return Range(start, end, 1); -} - -// ValuesIn() function allows generation of tests with parameters coming from -// a container. -// -// Synopsis: -// ValuesIn(const T (&array)[N]) -// - returns a generator producing sequences with elements from -// a C-style array. -// ValuesIn(const Container& container) -// - returns a generator producing sequences with elements from -// an STL-style container. -// ValuesIn(Iterator begin, Iterator end) -// - returns a generator producing sequences with elements from -// a range [begin, end) defined by a pair of STL-style iterators. These -// iterators can also be plain C pointers. -// -// Please note that ValuesIn copies the values from the containers -// passed in and keeps them to generate tests in RUN_ALL_TESTS(). -// -// Examples: -// -// This instantiates tests from test case StringTest -// each with C-string values of "foo", "bar", and "baz": -// -// const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); -// -// This instantiates tests from test case StlStringTest -// each with STL strings with values "a" and "b": -// -// ::std::vector< ::std::string> GetParameterStrings() { -// ::std::vector< ::std::string> v; -// v.push_back("a"); -// v.push_back("b"); -// return v; -// } -// -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); -// -// -// This will also instantiate tests from CharTest -// each with parameter values 'a' and 'b': -// -// ::std::list GetParameterChars() { -// ::std::list list; -// list.push_back('a'); -// list.push_back('b'); -// return list; -// } -// ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); -// -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; - return internal::ParamGenerator( - new internal::ValuesInIteratorRangeGenerator(begin, end)); -} - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]) { - return ValuesIn(array, array + N); -} - -template -internal::ParamGenerator ValuesIn( - const Container& container) { - return ValuesIn(container.begin(), container.end()); -} - -// Values() allows generating tests from explicitly specified list of -// parameters. -// -// Synopsis: -// Values(T v1, T v2, ..., T vN) -// - returns a generator producing sequences with elements v1, v2, ..., vN. -// -// For example, this instantiates tests from test case BarTest each -// with values "one", "two", and "three": -// -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); -// -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. -// The exact type of values will depend on the type of parameter in BazTest. -// -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); -// -// Currently, Values() supports from 1 to $n parameters. -// -$range i 1..n -$for i [[ -$range j 1..i - -template <$for j, [[typename T$j]]> -internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) { - return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]); -} - -]] - -// Bool() allows generating tests with parameters in a set of (false, true). -// -// Synopsis: -// Bool() -// - returns a generator producing sequences with elements {false, true}. -// -// It is useful when testing code that depends on Boolean flags. Combinations -// of multiple flags can be tested when several Bool()'s are combined using -// Combine() function. -// -// In the following example all tests in the test case FlagDependentTest -// will be instantiated twice with parameters false and true. -// -// class FlagDependentTest : public testing::TestWithParam { -// virtual void SetUp() { -// external_flag = GetParam(); -// } -// } -// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); -// -inline internal::ParamGenerator Bool() { - return Values(false, true); -} - -# if GTEST_HAS_COMBINE -// Combine() allows the user to combine two or more sequences to produce -// values of a Cartesian product of those sequences' elements. -// -// Synopsis: -// Combine(gen1, gen2, ..., genN) -// - returns a generator producing sequences with elements coming from -// the Cartesian product of elements from the sequences generated by -// gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types -// of elements from sequences produces by gen1, gen2, ..., genN. -// -// Combine can have up to $maxtuple arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. -// -// Example: -// -// This will instantiate tests in test case AnimalTest each one with -// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), -// tuple("dog", BLACK), and tuple("dog", WHITE): -// -// enum Color { BLACK, GRAY, WHITE }; -// class AnimalTest -// : public testing::TestWithParam > {...}; -// -// TEST_P(AnimalTest, AnimalLooksNice) {...} -// -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); -// -// This will instantiate tests in FlagDependentTest with all variations of two -// Boolean flags: -// -// class FlagDependentTest -// : public testing::TestWithParam > { -// virtual void SetUp() { -// // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); -// } -// }; -// -// TEST_P(FlagDependentTest, TestFeature1) { -// // Test your code using external_flag_1 and external_flag_2 here. -// } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -$range i 2..maxtuple -$for i [[ -$range j 1..i - -template <$for j, [[typename Generator$j]]> -internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( - $for j, [[const Generator$j& g$j]]) { - return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>( - $for j, [[g$j]]); -} - -]] -# endif // GTEST_HAS_COMBINE - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestPattern(\ - GTEST_STRINGIFY_(test_case_name), \ - GTEST_STRINGIFY_(test_name), \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(\ - test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user -// to specify a function or functor that generates custom test name suffixes -// based on the test parameters. The function should accept one argument of -// type testing::TestParamInfo, and return std::string. -// -// testing::PrintToStringParamName is a builtin test suffix generator that -// returns the value of testing::PrintToString(GetParam()). -// -// Note: test names must be non-empty, unique, and may only contain ASCII -// alphanumeric characters or underscore. Because PrintToString adds quotes -// to std::string and C strings, it won't work for these types. - -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ - static ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ - const ::testing::TestParamInfo& info) { \ - return ::testing::internal::GetParamNameGen \ - (__VA_ARGS__)(info); \ - } \ - static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, \ - ::testing::internal::CodeLocation(\ - __FILE__, __LINE__))->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - >est_##prefix##test_case_name##_EvalGenerateName_, \ - __FILE__, __LINE__) - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-printers.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-printers.h index 51865f84e6..950247cf67 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-printers.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-printers.h @@ -27,7 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a @@ -100,17 +99,16 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#include #include // NOLINT #include #include +#include +#include #include #include -#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" - -#if GTEST_HAS_STD_TUPLE_ -# include -#endif +#include "gtest/internal/gtest-port.h" #if GTEST_HAS_ABSL #include "absl/strings/string_view.h" @@ -126,9 +124,8 @@ namespace internal2 { // Prints the given number of bytes in the given object to the given // ostream. -GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, - size_t count, - ::std::ostream* os); +GTEST_API_ void PrintBytesInObjectTo(const unsigned char *obj_bytes, + size_t count, ::std::ostream *os); // For selecting which printer to use when a given type has neither << // nor PrintTo(). @@ -136,9 +133,9 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) -#if GTEST_HAS_ABSL +#if GTEST_INTERNAL_HAS_STRING_VIEW kConvertibleToStringView, // a type implicitly convertible to - // absl::string_view + // absl::string_view or std::string_view #endif kOtherType // anything else }; @@ -151,10 +148,11 @@ template class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. - static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(static_cast( - reinterpret_cast(&value)), - sizeof(value), os); + static void PrintValue(const T &value, ::std::ostream *os) { + PrintBytesInObjectTo( + static_cast( + reinterpret_cast(std::addressof(value))), + sizeof(value), os); } }; @@ -166,7 +164,7 @@ const size_t kProtobufOneLinerMaxLength = 50; template class TypeWithoutFormatter { public: - static void PrintValue(const T& value, ::std::ostream* os) { + static void PrintValue(const T &value, ::std::ostream *os) { std::string pretty_str = value.ShortDebugString(); if (pretty_str.length() > kProtobufOneLinerMaxLength) { pretty_str = "\n" + value.DebugString(); @@ -185,22 +183,23 @@ class TypeWithoutFormatter { // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. - static void PrintValue(const T& value, ::std::ostream* os) { + static void PrintValue(const T &value, ::std::ostream *os) { const internal::BiggestInt kBigInt = value; *os << kBigInt; } }; -#if GTEST_HAS_ABSL +#if GTEST_INTERNAL_HAS_STRING_VIEW template class TypeWithoutFormatter { public: // Since T has neither operator<< nor PrintTo() but can be implicitly - // converted to absl::string_view, we print it as a absl::string_view. + // converted to absl::string_view, we print it as a absl::string_view + // (or std::string_view). // // Note: the implementation is further below, as it depends on // internal::PrintTo symbol which is defined later in the file. - static void PrintValue(const T& value, ::std::ostream* os); + static void PrintValue(const T &value, ::std::ostream *os); }; #endif @@ -229,21 +228,20 @@ class TypeWithoutFormatter { // operator<<(std::basic_stream, const Foo&) is more // specific. template -::std::basic_ostream& operator<<( - ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value - ? kProtobuf - : internal::ImplicitlyConvertible< - const T&, internal::BiggestInt>::value - ? kConvertibleToInteger - : -#if GTEST_HAS_ABSL - internal::ImplicitlyConvertible< - const T&, absl::string_view>::value - ? kConvertibleToStringView - : +::std::basic_ostream &operator<<( + ::std::basic_ostream &os, const T &x) { + TypeWithoutFormatter< + T, (internal::IsAProtocolMessage::value + ? kProtobuf + : std::is_convertible::value + ? kConvertibleToInteger + : +#if GTEST_INTERNAL_HAS_STRING_VIEW + std::is_convertible::value + ? kConvertibleToStringView + : #endif - kOtherType)>::PrintValue(x, &os); + kOtherType)>::PrintValue(x, &os); return os; } @@ -257,7 +255,7 @@ namespace testing_internal { // Used to print a value that is not an STL-style container when the // user doesn't define PrintTo() for it. template -void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { +void DefaultPrintNonContainerTo(const T &value, ::std::ostream *os) { // With the following statement, during unqualified name lookup, // testing::internal2::operator<< appears as if it was declared in // the nearest enclosing namespace that contains both @@ -266,10 +264,8 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // 7.3.4-1 [namespace.udir]. This allows us to fall back onto // testing::internal2::operator<< in case T doesn't come with a << // operator. - // - // We cannot write 'using ::testing::internal2::operator<<;', which - // gcc 3.3 fails to compile due to a compiler bug. - using namespace ::testing::internal2; // NOLINT + + using ::testing::internal2::operator<<; // Assuming T is defined in namespace foo, in the next statement, // the compiler will consider all of: @@ -310,7 +306,7 @@ namespace internal { template class FormatForComparison { public: - static ::std::string Format(const ToPrint& value) { + static ::std::string Format(const ToPrint &value) { return ::testing::PrintToString(value); } }; @@ -319,21 +315,21 @@ class FormatForComparison { template class FormatForComparison { public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); + static ::std::string Format(const ToPrint *value) { + return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType *value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); @@ -347,27 +343,17 @@ GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType *value) { \ + return ::testing::PrintToString(value); \ + } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif - #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); @@ -384,8 +370,8 @@ GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { +std::string FormatForComparisonFailureMessage(const T1 &value, + const T2 & /* other_operand */) { return FormatForComparison::Format(value); } @@ -400,7 +386,7 @@ template class UniversalPrinter; template -void UniversalPrint(const T& value, ::std::ostream* os); +void UniversalPrint(const T &value, ::std::ostream *os); enum DefaultPrinterType { kPrintContainer, @@ -408,18 +394,19 @@ enum DefaultPrinterType { kPrintFunctionPointer, kPrintOther, }; -template struct WrapPrinterType {}; +template +struct WrapPrinterType {}; // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template void DefaultPrintTo(WrapPrinterType /* dummy */, - const C& container, ::std::ostream* os) { + const C &container, ::std::ostream *os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; - for (typename C::const_iterator it = container.begin(); - it != container.end(); ++it, ++count) { + for (typename C::const_iterator it = container.begin(); it != container.end(); + ++it, ++count) { if (count > 0) { *os << ','; if (count == kMaxCount) { // Enough has been printed. @@ -446,9 +433,9 @@ void DefaultPrintTo(WrapPrinterType /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template -void DefaultPrintTo(WrapPrinterType /* dummy */, - T* p, ::std::ostream* os) { - if (p == NULL) { +void DefaultPrintTo(WrapPrinterType /* dummy */, T *p, + ::std::ostream *os) { + if (p == nullptr) { *os << "NULL"; } else { // T is not a function type. We just call << to print p, @@ -458,23 +445,23 @@ void DefaultPrintTo(WrapPrinterType /* dummy */, } } template -void DefaultPrintTo(WrapPrinterType /* dummy */, - T* p, ::std::ostream* os) { - if (p == NULL) { +void DefaultPrintTo(WrapPrinterType /* dummy */, T *p, + ::std::ostream *os) { + if (p == nullptr) { *os << "NULL"; } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. - *os << reinterpret_cast(p); + *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template -void DefaultPrintTo(WrapPrinterType /* dummy */, - const T& value, ::std::ostream* os) { +void DefaultPrintTo(WrapPrinterType /* dummy */, const T &value, + ::std::ostream *os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -490,7 +477,7 @@ void DefaultPrintTo(WrapPrinterType /* dummy */, // or there is already a << operator but it doesn't do what the user // wants). template -void PrintTo(const T& value, ::std::ostream* os) { +void PrintTo(const T &value, ::std::ostream *os) { // DefaultPrintTo() is overloaded. The type of its first argument // determines which version will be picked. // @@ -515,13 +502,9 @@ void PrintTo(const T& value, ::std::ostream* os) { (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && !IsRecursiveContainer::value ? kPrintContainer - : !is_pointer::value + : !std::is_pointer::value ? kPrintOther -#if GTEST_LANG_CXX11 : std::is_function::type>::value -#else - : !internal::ImplicitlyConvertible::value -#endif ? kPrintFunctionPointer : kPrintPointer > (), value, os); @@ -532,9 +515,9 @@ void PrintTo(const T& value, ::std::ostream* os) { // types, strings, plain arrays, and pointers). // Overloads for various char types. -GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); -GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); -inline void PrintTo(char c, ::std::ostream* os) { +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream *os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream *os); +inline void PrintTo(char c, ::std::ostream *os) { // When printing a plain char, we always treat it as unsigned. This // way, the output won't be affected by whether the compiler thinks // char is signed or not. @@ -542,7 +525,7 @@ inline void PrintTo(char c, ::std::ostream* os) { } // Overloads for other simple built-in types. -inline void PrintTo(bool x, ::std::ostream* os) { +inline void PrintTo(bool x, ::std::ostream *os) { *os << (x ? "true" : "false"); } @@ -553,27 +536,27 @@ inline void PrintTo(bool x, ::std::ostream* os) { // as signed integer when wchar_t is implemented by the compiler // as a signed type and is printed as an unsigned integer when wchar_t // is implemented as an unsigned type. -GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream *os); // Overloads for C strings. -GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); -inline void PrintTo(char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +GTEST_API_ void PrintTo(const char *s, ::std::ostream *os); +inline void PrintTo(char *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } // signed/unsigned char is often used for representing binary data, so // we print pointers to it as void* to be safe. -inline void PrintTo(const signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +inline void PrintTo(const signed char *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } -inline void PrintTo(signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +inline void PrintTo(signed char *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } -inline void PrintTo(const unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +inline void PrintTo(const unsigned char *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } -inline void PrintTo(unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +inline void PrintTo(unsigned char *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } // MSVC can be configured to define wchar_t as a typedef of unsigned @@ -583,9 +566,9 @@ inline void PrintTo(unsigned char* s, ::std::ostream* os) { // possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings -GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); -inline void PrintTo(wchar_t* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); +GTEST_API_ void PrintTo(const wchar_t *s, ::std::ostream *os); +inline void PrintTo(wchar_t *s, ::std::ostream *os) { + PrintTo(ImplicitCast_(s), os); } #endif @@ -595,7 +578,7 @@ inline void PrintTo(wchar_t* s, ::std::ostream* os) { // Prints the given number of elements in an array, without printing // the curly braces. template -void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream *os) { UniversalPrint(a[0], os); for (size_t i = 1; i != count; i++) { *os << ", "; @@ -603,138 +586,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { } } -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); -inline void PrintTo(const ::std::string& s, ::std::ostream* os) { +// Overloads for ::std::string. +GTEST_API_ void PrintStringTo(const ::std::string &s, ::std::ostream *os); +inline void PrintTo(const ::std::string &s, ::std::ostream *os) { PrintStringTo(s, os); } -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - +// Overloads for ::std::wstring. #if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { +GTEST_API_ void PrintWideStringTo(const ::std::wstring &s, ::std::ostream *os); +inline void PrintTo(const ::std::wstring &s, ::std::ostream *os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_ABSL -// Overload for absl::string_view. -inline void PrintTo(absl::string_view sp, ::std::ostream* os) { +#if GTEST_INTERNAL_HAS_STRING_VIEW +// Overload for internal::StringView. +inline void PrintTo(internal::StringView sp, ::std::ostream *os) { PrintTo(::std::string(sp), os); } -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_STRING_VIEW -#if GTEST_LANG_CXX11 -inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } -#endif // GTEST_LANG_CXX11 +inline void PrintTo(std::nullptr_t, ::std::ostream *os) { *os << "(nullptr)"; } + +template +void PrintTo(std::reference_wrapper ref, ::std::ostream *os) { + UniversalPrinter::Print(ref.get(), os); +} -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // Helper function for printing a tuple. T must be instantiated with // a tuple type. template -void PrintTupleTo(const T& t, ::std::ostream* os); -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ +void PrintTupleTo(const T &, std::integral_constant, + ::std::ostream *) {} -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); +template +void PrintTupleTo(const T &t, std::integral_constant, + ::std::ostream *os) { + PrintTupleTo(t, std::integral_constant(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter::type>::Print( + std::get(t), os); } -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} -#endif // GTEST_HAS_TR1_TUPLE - -#if GTEST_HAS_STD_TUPLE_ template -void PrintTo(const ::std::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); +void PrintTo(const ::std::tuple &t, ::std::ostream *os) { + *os << "("; + PrintTupleTo(t, std::integral_constant(), os); + *os << ")"; } -#endif // GTEST_HAS_STD_TUPLE_ // Overload for std::pair. template -void PrintTo(const ::std::pair& value, ::std::ostream* os) { +void PrintTo(const ::std::pair &value, ::std::ostream *os) { *os << '('; // We cannot use UniversalPrint(value.first, os) here, as T1 may be // a reference type. The same for printing value.second. @@ -756,7 +664,7 @@ class UniversalPrinter { // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the // function. - static void Print(const T& value, ::std::ostream* os) { + static void Print(const T &value, ::std::ostream *os) { // By default, ::testing::internal::PrintTo() is used for printing // the value. // @@ -778,7 +686,7 @@ class UniversalPrinter { template class UniversalPrinter<::absl::optional> { public: - static void Print(const ::absl::optional& value, ::std::ostream* os) { + static void Print(const ::absl::optional &value, ::std::ostream *os) { *os << '('; if (!value) { *os << "nullopt"; @@ -794,20 +702,20 @@ class UniversalPrinter<::absl::optional> { template class UniversalPrinter<::absl::variant> { public: - static void Print(const ::absl::variant& value, ::std::ostream* os) { + static void Print(const ::absl::variant &value, ::std::ostream *os) { *os << '('; - absl::visit(Visitor{os}, value); + absl::visit(Visitor{ os }, value); *os << ')'; } private: struct Visitor { template - void operator()(const U& u) const { + void operator()(const U &u) const { *os << "'" << GetTypeName() << "' with value "; UniversalPrint(u, os); } - ::std::ostream* os; + ::std::ostream *os; }; }; @@ -816,7 +724,7 @@ class UniversalPrinter<::absl::variant> { // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template -void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { +void UniversalPrintArray(const T *begin, size_t len, ::std::ostream *os) { if (len == 0) { *os << "{}"; } else { @@ -826,7 +734,6 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // FIXME: let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -838,12 +745,12 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { } } // This overload prints a (const) char array compactly. -GTEST_API_ void UniversalPrintArray( - const char* begin, size_t len, ::std::ostream* os); +GTEST_API_ void UniversalPrintArray(const char *begin, size_t len, + ::std::ostream *os); // This overload prints a (const) wchar_t array compactly. -GTEST_API_ void UniversalPrintArray( - const wchar_t* begin, size_t len, ::std::ostream* os); +GTEST_API_ void UniversalPrintArray(const wchar_t *begin, size_t len, + ::std::ostream *os); // Implements printing an array type T[N]. template @@ -851,23 +758,23 @@ class UniversalPrinter { public: // Prints the given array, omitting some elements when there are too // many. - static void Print(const T (&a)[N], ::std::ostream* os) { + static void Print(const T (&a)[N], ::std::ostream *os) { UniversalPrintArray(a, N, os); } }; // Implements printing a reference type T&. template -class UniversalPrinter { +class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) - static void Print(const T& value, ::std::ostream* os) { + static void Print(const T &value, ::std::ostream *os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. - *os << "@" << reinterpret_cast(&value) << " "; + *os << "@" << reinterpret_cast(&value) << " "; // Then prints the value itself. UniversalPrint(value, os); @@ -883,29 +790,29 @@ class UniversalPrinter { template class UniversalTersePrinter { public: - static void Print(const T& value, ::std::ostream* os) { + static void Print(const T &value, ::std::ostream *os) { UniversalPrint(value, os); } }; template -class UniversalTersePrinter { +class UniversalTersePrinter { public: - static void Print(const T& value, ::std::ostream* os) { + static void Print(const T &value, ::std::ostream *os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: - static void Print(const T (&value)[N], ::std::ostream* os) { + static void Print(const T (&value)[N], ::std::ostream *os) { UniversalPrinter::Print(value, os); } }; template <> -class UniversalTersePrinter { +class UniversalTersePrinter { public: - static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { + static void Print(const char *str, ::std::ostream *os) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(std::string(str), os); @@ -913,19 +820,19 @@ class UniversalTersePrinter { } }; template <> -class UniversalTersePrinter { +class UniversalTersePrinter { public: - static void Print(char* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); + static void Print(char *str, ::std::ostream *os) { + UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> -class UniversalTersePrinter { +class UniversalTersePrinter { public: - static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { + static void Print(const wchar_t *str, ::std::ostream *os) { + if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); @@ -935,15 +842,15 @@ class UniversalTersePrinter { #endif template <> -class UniversalTersePrinter { +class UniversalTersePrinter { public: - static void Print(wchar_t* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); + static void Print(wchar_t *str, ::std::ostream *os) { + UniversalTersePrinter::Print(str, os); } }; template -void UniversalTersePrint(const T& value, ::std::ostream* os) { +void UniversalTersePrint(const T &value, ::std::ostream *os) { UniversalTersePrinter::Print(value, os); } @@ -952,146 +859,57 @@ void UniversalTersePrint(const T& value, ::std::ostream* os) { // (const) char pointer, this prints both the pointer and the // NUL-terminated string. template -void UniversalPrint(const T& value, ::std::ostream* os) { +void UniversalPrint(const T &value, ::std::ostream *os) { // A workarond for the bug in VC++ 7.1 that prevents us from instantiating // UniversalPrinter with T directly. typedef T T1; UniversalPrinter::Print(value, os); } -typedef ::std::vector< ::std::string> Strings; +typedef ::std::vector<::std::string> Strings; -// TuplePolicy must provide: -// - tuple_size -// size of tuple TupleT. -// - get(const TupleT& t) -// static function extracting element I of tuple TupleT. -// - tuple_element::type -// type of element I of tuple TupleT. -template -struct TuplePolicy; - -#if GTEST_HAS_TR1_TUPLE -template -struct TuplePolicy { - typedef TupleT Tuple; - static const size_t tuple_size = ::std::tr1::tuple_size::value; - - template - struct tuple_element : ::std::tr1::tuple_element(I), Tuple> { - }; - - template - static typename AddReference(I), Tuple>::type>::type - get(const Tuple& tuple) { - return ::std::tr1::get(tuple); - } -}; -template -const size_t TuplePolicy::tuple_size; -#endif // GTEST_HAS_TR1_TUPLE - -#if GTEST_HAS_STD_TUPLE_ -template -struct TuplePolicy< ::std::tuple > { - typedef ::std::tuple Tuple; - static const size_t tuple_size = ::std::tuple_size::value; - - template - struct tuple_element : ::std::tuple_element {}; - - template - static const typename ::std::tuple_element::type& get( - const Tuple& tuple) { - return ::std::get(tuple); - } -}; -template -const size_t TuplePolicy< ::std::tuple >::tuple_size; -#endif // GTEST_HAS_STD_TUPLE_ - -#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. -// -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - GTEST_INTENTIONAL_CONST_COND_PUSH_() - if (N > 1) { - GTEST_INTENTIONAL_CONST_COND_POP_() - *os << ", "; - } - UniversalPrinter< - typename TuplePolicy::template tuple_element::type> - ::Print(TuplePolicy::template get(t), os); - } - - // Tersely prints the first N fields of a tuple to a string vector, - // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(TuplePolicy::template get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base case. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; - -// Helper function for printing a tuple. -// Tuple must be either std::tr1::tuple or std::tuple type. +// Tersely prints the first N fields of a tuple to a string vector, +// one element for each field. template -void PrintTupleTo(const Tuple& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter::tuple_size>::PrintPrefixTo(t, os); - *os << ")"; +void TersePrintPrefixToStrings(const Tuple &, std::integral_constant, + Strings *) {} +template +void TersePrintPrefixToStrings(const Tuple &t, + std::integral_constant, + Strings *strings) { + TersePrintPrefixToStrings(t, std::integral_constant(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get(t), &ss); + strings->push_back(ss.str()); } // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". template -Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple &value) { Strings result; - TuplePrefixPrinter::tuple_size>:: - TersePrintPrefixToStrings(value, &result); + TersePrintPrefixToStrings( + value, std::integral_constant::value>(), + &result); return result; } -#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ } // namespace internal -#if GTEST_HAS_ABSL +#if GTEST_INTERNAL_HAS_STRING_VIEW namespace internal2 { template void TypeWithoutFormatter::PrintValue( - const T& value, ::std::ostream* os) { - internal::PrintTo(absl::string_view(value), os); + const T &value, ::std::ostream *os) { + internal::PrintTo(internal::StringView(value), os); } } // namespace internal2 #endif template -::std::string PrintToString(const T& value) { +::std::string PrintToString(const T &value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-spi.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-spi.h index 1e8983938e..e263b1033f 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-spi.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-spi.h @@ -65,27 +65,28 @@ class GTEST_API_ ScopedFakeTestPartResultReporter // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED - explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + explicit ScopedFakeTestPartResultReporter(TestPartResultArray *result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, - TestPartResultArray* result); + TestPartResultArray *result); // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); + ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; + private: void Init(); const InterceptMode intercept_mode_; - TestPartResultReporterInterface* old_reporter_; - TestPartResultArray* const result_; + TestPartResultReporterInterface *old_reporter_; + TestPartResultArray *const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; @@ -100,11 +101,12 @@ namespace internal { class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. - SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, const std::string& substr); + SingleFailureChecker(const TestPartResultArray *results, + TestPartResult::Type type, const std::string &substr); ~SingleFailureChecker(); + private: - const TestPartResultArray* const results_; + const TestPartResultArray *const results_; const TestPartResult::Type type_; const std::string substr_; @@ -140,38 +142,39 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. -#define EXPECT_FATAL_FAILURE(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper { \ + public: \ + static void Execute() { statement; } \ + }; \ + ::testing::TestPartResultArray gtest_failures; \ + ::testing::internal::SingleFailureChecker gtest_checker( \ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \ + { \ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, \ + >est_failures); \ + GTestExpectFatalFailureHelper::Execute(); \ + } \ } while (::testing::internal::AlwaysFalse()) -#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ALL_THREADS, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper { \ + public: \ + static void Execute() { statement; } \ + }; \ + ::testing::TestPartResultArray gtest_failures; \ + ::testing::internal::SingleFailureChecker gtest_checker( \ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr)); \ + { \ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ + >est_failures); \ + GTestExpectFatalFailureHelper::Execute(); \ + } \ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to @@ -206,32 +209,37 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. -#define EXPECT_NONFATAL_FAILURE(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do { \ + ::testing::TestPartResultArray gtest_failures; \ + ::testing::internal::SingleFailureChecker gtest_checker( \ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ + (substr)); \ + { \ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, \ + >est_failures); \ + if (::testing::internal::AlwaysTrue()) { \ + statement; \ + } \ + } \ } while (::testing::internal::AlwaysFalse()) -#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + ::testing::TestPartResultArray gtest_failures; \ + ::testing::internal::SingleFailureChecker gtest_checker( \ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr)); \ + { \ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter( \ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ - >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ + >est_failures); \ + if (::testing::internal::AlwaysTrue()) { \ + statement; \ + } \ + } \ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-test-part.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-test-part.h index 1c7b89e087..a28afb309b 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-test-part.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-test-part.h @@ -53,30 +53,26 @@ class GTEST_API_ TestPartResult { enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, - const char* a_message) - : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), - line_number_(a_line_number), - summary_(ExtractSummary(a_message)), - message_(a_message) { - } + TestPartResult(Type a_type, const char *a_file_name, int a_line_number, + const char *a_message) + : type_(a_type), file_name_(a_file_name == nullptr ? "" : a_file_name), + line_number_(a_line_number), summary_(ExtractSummary(a_message)), + message_(a_message) {} // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. - const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); + const char *file_name() const { + return file_name_.empty() ? nullptr : file_name_.c_str(); } // Gets the line in the source file where the test part took place, @@ -84,29 +80,32 @@ class GTEST_API_ TestPartResult { int line_number() const { return line_number_; } // Gets the summary of the failure message. - const char* summary() const { return summary_.c_str(); } + const char *summary() const { return summary_.c_str(); } // Gets the message associated with the test part. - const char* message() const { return message_.c_str(); } + const char *message() const { return message_.c_str(); } - // Returns true iff the test part passed. + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } + + // Returns true if and only if the test part passed. bool passed() const { return type_ == kSuccess; } - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } - - // Returns true iff the test part non-fatally failed. + // Returns true if and only if the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - // Returns true iff the test part fatally failed. + // Returns true if and only if the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. - static std::string ExtractSummary(const char* message); + static std::string ExtractSummary(const char *message); // The name of the source file where the test part took place, or // "" if the source file is unknown. @@ -119,7 +118,7 @@ class GTEST_API_ TestPartResult { }; // Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result); +std::ostream &operator<<(std::ostream &os, const TestPartResult &result); // An array of TestPartResult objects. // @@ -130,10 +129,10 @@ class GTEST_API_ TestPartResultArray { TestPartResultArray() {} // Appends the given TestPartResult to the array. - void Append(const TestPartResult& result); + void Append(const TestPartResult &result); // Returns the TestPartResult at the given index (0-based). - const TestPartResult& GetTestPartResult(int index) const; + const TestPartResult &GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; @@ -149,7 +148,7 @@ class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} - virtual void ReportTestPartResult(const TestPartResult& result) = 0; + virtual void ReportTestPartResult(const TestPartResult &result) = 0; }; namespace internal { @@ -164,12 +163,13 @@ class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult &result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: bool has_new_fatal_failure_; - TestPartResultReporterInterface* original_reporter_; + TestPartResultReporterInterface *original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-typed-test.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-typed-test.h index 74bce46bdc..f5afc4db87 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-typed-test.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest-typed-test.h @@ -27,7 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ @@ -52,22 +51,22 @@ class FooTest : public testing::Test { T value_; }; -// Next, associate a list of types with the test case, which will be +// Next, associate a list of types with the test suite, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); +TYPED_TEST_SUITE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); +// TYPED_TEST_SUITE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. +// tests for this test suite as you want. TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: @@ -83,7 +82,7 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } -// TYPED_TEST_CASE takes an optional third argument which allows to specify a +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a // class that generates custom test name suffixes based on the type. This should // be a class which has a static template function GetName(int index) returning // a string for each type. The provided integer index equals the index of the @@ -99,7 +98,7 @@ TYPED_TEST(FooTest, HasPropertyA) { ... } // if (std::is_same()) return "unsignedInt"; // } // }; -// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames); +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -126,13 +125,13 @@ class FooTest : public testing::Test { ... }; -// Next, declare that you will define a type-parameterized test case +// Next, declare that you will define a type-parameterized test suite // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): -TYPED_TEST_CASE_P(FooTest); +TYPED_TEST_SUITE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. +// for this type-parameterized test suite as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; @@ -143,10 +142,10 @@ TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test +// test suite name; the rest are the names of the tests in this test // case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include @@ -154,22 +153,23 @@ REGISTER_TYPED_TEST_CASE_P(FooTest, // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for +// to the actual test suite name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); // -// Similar to the optional argument of TYPED_TEST_CASE above, -// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to // generate custom names. -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames); +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 +#include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-type-util.h" @@ -180,35 +180,33 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ // Expands to the name of the typedef for the NameGenerator, responsible for // creating the suffixes of the name. -#define GTEST_NAME_GENERATOR_(TestCaseName) \ - gtest_type_params_##TestCaseName##_NameGenerator +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types, ...) \ - typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \ - CaseName); \ - typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::GenerateTypeList::type \ + GTEST_TYPE_PARAMS_(CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ GTEST_NAME_GENERATOR_(CaseName) -# define TYPED_TEST(CaseName, TestName) \ +#define TYPED_TEST(CaseName, TestName) \ + static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \ + "test-name must not be empty"); \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ + void TestBody() override; \ }; \ static bool gtest_##CaseName##_##TestName##_registered_ \ - GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ + GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel, \ @@ -216,7 +214,8 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); CaseName)>::Register("", \ ::testing::internal::CodeLocation( \ __FILE__, __LINE__), \ - #CaseName, #TestName, 0, \ + GTEST_STRINGIFY_(CaseName), \ + GTEST_STRINGIFY_(TestName), 0, \ ::testing::internal::GenerateNames< \ GTEST_NAME_GENERATOR_(CaseName), \ GTEST_TYPE_PARAMS_(CaseName)>()); \ @@ -224,6 +223,13 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); void GTEST_TEST_CLASS_NAME_(CaseName, \ TestName)::TestBody() +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. @@ -233,73 +239,98 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact +// the given type-parameterized test suite are defined in. The exact // name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) \ - GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames( \ - __FILE__, __LINE__, #__VA_ARGS__) +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ + GTEST_STRINGIFY_(TestName)); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName::TestBody() -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \ - static bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase< \ - CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ - ::testing::internal::TypeList< Types >::type>:: \ - Register(#Prefix, \ +// Note: this won't work correctly if the trailing arguments are macros. +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \ + } \ + static const char *const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ + GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \ + "test-suit-prefix must not be empty"); \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::GenerateTypeList::type>:: \ + Register(GTEST_STRINGIFY_(Prefix), \ ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \ - GTEST_REGISTERED_TEST_NAMES_(CaseName), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \ + GTEST_STRINGIFY_(SuiteName), \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ ::testing::internal::GenerateNames< \ ::testing::internal::NameGeneratorSelector< \ __VA_ARGS__>::type, \ - ::testing::internal::TypeList< Types >::type>()) + ::testing::internal::GenerateTypeList::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST_P diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest.h index 5df4b0a3a7..8fd7eea1e7 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest.h @@ -52,13 +52,17 @@ #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ +#include #include +#include #include +#include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" @@ -69,32 +73,16 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If ::std::string and ::string are the same class on your platform -// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. - namespace testing { // Silence C4100 (unreferenced formal parameter) and 4805 // unsafe mix of type 'const int' and type 'const bool' #ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4805) -# pragma warning(disable:4100) +#pragma warning(push) +#pragma warning(disable : 4805) +#pragma warning(disable : 4100) #endif - // Declares the flags. // This flag temporary enables the disabled tests. @@ -185,9 +173,10 @@ class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class FuchsiaDeathTest; -class UnitTestImpl* GetUnitTestImpl(); +class UnitTestImpl *GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message); + const std::string &message); +std::set *GetIgnoredParameterizedTestSuites(); } // namespace internal @@ -195,7 +184,12 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; -class TestCase; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif class TestInfo; class UnitTest; @@ -282,9 +276,13 @@ class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). - AssertionResult(const AssertionResult& other); + AssertionResult(const AssertionResult &other); -#if defined(_MSC_VER) && _MSC_VER < 1910 +// C4800 is a level 3 warning in Visual Studio 2015 and earlier. +// This warning is not emitted in Visual Studio 2017. +// This warning is off by default starting in Visual Studio 2019 but can be +// enabled with command-line options. +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) #endif @@ -297,23 +295,24 @@ class GTEST_API_ AssertionResult { // we want AssertionResult's copy constructor to be used. template explicit AssertionResult( - const T& success, - typename internal::EnableIf< - !internal::ImplicitlyConvertible::value>::type* - /*enabler*/ = NULL) + const T &success, + typename std::enable_if< + !std::is_convertible::value>::type * + /*enabler*/ + = nullptr) : success_(success) {} -#if defined(_MSC_VER) && _MSC_VER < 1910 +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Assignment operator. - AssertionResult& operator=(AssertionResult other) { + AssertionResult &operator=(AssertionResult other) { swap(other); return *this; } - // Returns true iff the assertion succeeded. + // Returns true if and only if the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. @@ -323,37 +322,36 @@ class GTEST_API_ AssertionResult { // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. - const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; + const char *message() const { + return message_.get() != nullptr ? message_->c_str() : ""; } - // FIXME: Remove this after making sure no clients use it. // Deprecated; please use message() instead. - const char* failure_message() const { return message(); } + const char *failure_message() const { return message(); } // Streams a custom failure message into this object. - template AssertionResult& operator<<(const T& value) { + template + AssertionResult &operator<<(const T &value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. - AssertionResult& operator<<( - ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AssertionResult &operator<<( + ::std::ostream &(*basic_manipulator)(::std::ostream &stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. - void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); + void AppendMessage(const Message &a_message) { + if (message_.get() == nullptr) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Swap the contents of this AssertionResult with other. - void swap(AssertionResult& other); + void swap(AssertionResult &other); // Stores result of the assertion predicate. bool success_; @@ -361,7 +359,7 @@ class GTEST_API_ AssertionResult { // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. - internal::scoped_ptr< ::std::string> message_; + std::unique_ptr< ::std::string> message_; }; // Makes a successful assertion result. @@ -372,7 +370,7 @@ GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. -GTEST_API_ AssertionResult AssertionFailure(const Message& msg); +GTEST_API_ AssertionResult AssertionFailure(const Message &msg); } // namespace testing @@ -385,8 +383,8 @@ namespace testing { // The abstract class that all tests inherit from. // -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does @@ -410,55 +408,59 @@ class GTEST_API_ Test { public: friend class TestInfo; - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // - // Google Test will call Foo::SetUpTestCase() before running the first + // Google Test will call Foo::SetUpTestSuite() before running the first // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super + // SetUpTestSuite() method to shadow the one defined in the super // class. - static void SetUpTestCase() {} + static void SetUpTestSuite() {} - // Tears down the stuff shared by all tests in this test case. + // Tears down the stuff shared by all tests in this test suite. // - // Google Test will call Foo::TearDownTestCase() after running the last + // Google Test will call Foo::TearDownTestSuite() after running the last // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super + // TearDownTestSuite() method to shadow the one defined in the super // class. - static void TearDownTestCase() {} + static void TearDownTestSuite() {} - // Returns true iff the current test has a fatal failure. + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns true if and only if the current test has a fatal failure. static bool HasFatalFailure(); - // Returns true iff the current test has a non-fatal failure. + // Returns true if and only if the current test has a non-fatal failure. static bool HasNonfatalFailure(); - // Returns true iff the current test has a (either fatal or + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - // Logs a property for the current test, test case, or for the entire + // Logs a property for the current test, test suite, or for the entire // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These + // test suite. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. - static void RecordProperty(const std::string& key, const std::string& value); - static void RecordProperty(const std::string& key, int value); + static void RecordProperty(const std::string &key, const std::string &value); + static void RecordProperty(const std::string &key, int value); protected: // Creates a Test object. @@ -471,8 +473,8 @@ class GTEST_API_ Test { virtual void TearDown(); private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. @@ -490,7 +492,7 @@ class GTEST_API_ Test { // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } - const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; + const std::unique_ptr gtest_flag_saver_; // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of @@ -509,7 +511,7 @@ class GTEST_API_ Test { // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp *Setup() { return nullptr; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); @@ -526,24 +528,17 @@ class TestProperty { // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. - TestProperty(const std::string& a_key, const std::string& a_value) : - key_(a_key), value_(a_value) { - } + TestProperty(const std::string &a_key, const std::string &a_value) + : key_(a_key), value_(a_value) {} // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } + const char *key() const { return key_.c_str(); } // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } + const char *value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const std::string& new_value) { - value_ = new_value; - } + void SetValue(const std::string &new_value) { value_ = new_value; } private: // The key supplied by the user. @@ -573,33 +568,40 @@ class GTEST_API_ TestResult { // Returns the number of the test properties. int test_property_count() const; - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } - // Returns true iff the test failed. + // Returns true if and only if the test was skipped. + bool Skipped() const; + + // Returns true if and only if the test failed. bool Failed() const; - // Returns true iff the test fatally failed. + // Returns true if and only if the test fatally failed. bool HasFatalFailure() const; - // Returns true iff the test has a non-fatal failure. + // Returns true if and only if the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test part result among all the results. i can range from 0 // to total_part_count() - 1. If i is not in that range, aborts the program. - const TestPartResult& GetTestPartResult(int i) const; + const TestPartResult &GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. - const TestProperty& GetTestProperty(int i) const; + const TestProperty &GetTestProperty(int i) const; private: friend class TestInfo; - friend class TestCase; + friend class TestSuite; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; @@ -609,15 +611,18 @@ class GTEST_API_ TestResult { friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. - const std::vector& test_part_results() const { + const std::vector &test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. - const std::vector& test_properties() const { + const std::vector &test_properties() const { return test_properties_; } + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } @@ -627,17 +632,17 @@ class GTEST_API_ TestResult { // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. - void RecordProperty(const std::string& xml_element, - const TestProperty& test_property); + void RecordProperty(const std::string &xml_element, + const TestProperty &test_property); // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. + // testsuite tags. Returns true if the property is valid. // FIXME: Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property); + static bool ValidateTestProperty(const std::string &xml_element, + const TestProperty &test_property); // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); + void AddTestPartResult(const TestPartResult &test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } @@ -661,6 +666,8 @@ class GTEST_API_ TestResult { std::vector test_properties_; // Running count of death tests. int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; @@ -670,7 +677,7 @@ class GTEST_API_ TestResult { // A TestInfo object stores the following information about a test: // -// Test case name +// Test suite name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked @@ -685,30 +692,33 @@ class GTEST_API_ TestInfo { // don't inherit from TestInfo. ~TestInfo(); - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } + // Returns the test suite name. + const char *test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char *test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the test name. - const char* name() const { return name_.c_str(); } + const char *name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + const char *type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. - const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; + const char *value_param() const { + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; } // Returns the file name where this test is defined. - const char* file() const { return location_.file.c_str(); } + const char *file() const { return location_.file.c_str(); } // Returns the line where this test is defined. int line() const { return location_.line; } @@ -721,7 +731,7 @@ class GTEST_API_ TestInfo { // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as + // The full name of a test Bar in test suite Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, @@ -734,7 +744,7 @@ class GTEST_API_ TestInfo { // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } - // Returns true iff this test will appear in the XML report. + // Returns true if and only if this test will appear in the XML report. bool is_reportable() const { // The XML report includes tests matching the filter, excluding those // run in other shards. @@ -742,36 +752,31 @@ class GTEST_API_ TestInfo { } // Returns the result of the test. - const TestResult* result() const { return &result_; } + const TestResult *result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; - friend class TestCase; + friend class TestSuite; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; - friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::CodeLocation code_location, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory); + friend TestInfo *internal::MakeAndRegisterTestInfo( + const char *test_suite_name, const char *name, const char *type_param, + const char *value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, + internal::TestFactoryBase *factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, - const char* a_type_param, // NULL if not a type-parameterized test - const char* a_value_param, // NULL if not a value-parameterized test + TestInfo(const std::string &test_suite_name, const std::string &name, + const char *a_type_param, // NULL if not a type-parameterized test + const char *a_value_param, // NULL if not a value-parameterized test internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory); + internal::TestFactoryBase *factory); // Increments the number of death tests encountered in this test so // far. @@ -783,27 +788,27 @@ class GTEST_API_ TestInfo { // deletes it. void Run(); - static void ClearTestResult(TestInfo* test_info) { + static void ClearTestResult(TestInfo *test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name - const std::string name_; // Test name + const std::string test_suite_name_; // test suite name + const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. - const internal::scoped_ptr value_param_; + const std::unique_ptr value_param_; internal::CodeLocation location_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - bool is_in_another_shard_; // Will be run in another shard. - internal::TestFactoryBase* const factory_; // The factory that creates + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. + internal::TestFactoryBase *const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the @@ -813,187 +818,210 @@ class GTEST_API_ TestInfo { GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; -// A test case, which consists of a vector of TestInfos. +// A test suite, which consists of a vector of TestInfos. // -// TestCase is not copyable. -class GTEST_API_ TestCase { +// TestSuite is not copyable. +class GTEST_API_ TestSuite { public: - // Creates a TestCase with the given name. + // Creates a TestSuite with the given name. // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. // // Arguments: // - // name: name of the test case + // name: name of the test suite // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char *name, const char *a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); - // Destructor of TestCase. - virtual ~TestCase(); + // Destructor of TestSuite. + virtual ~TestSuite(); - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } + // Gets the name of the TestSuite. + const char *name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; + // type-parameterized test suite. + const char *type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; } - // Returns true if any test in this test case should run. + // Returns true if any test in this test suite should run. bool should_run() const { return should_run_; } - // Gets the number of successful tests in this test case. + // Gets the number of successful tests in this test suite. int successful_test_count() const; - // Gets the number of failed tests in this test case. + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; - // Gets the number of disabled tests in this test case. + // Gets the number of disabled tests in this test suite. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; - // Get the number of tests in this test case that should run. + // Get the number of tests in this test suite that should run. int test_to_run_count() const; - // Gets the number of all tests in this test case. + // Gets the number of all tests in this test suite. int total_test_count() const; - // Returns true iff the test case passed. + // Returns true if and only if the test suite passed. bool Passed() const { return !Failed(); } - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } + // Returns true if and only if the test suite failed. + bool Failed() const { + return failed_test_count() > 0 || ad_hoc_test_result().Failed(); + } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. - const TestInfo* GetTestInfo(int i) const; + const TestInfo *GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. - const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + // execution of SetUpTestSuite and TearDownTestSuite. + const TestResult &ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; - // Gets the (mutable) vector of TestInfos in this TestCase. - std::vector& test_info_list() { return test_info_list_; } + // Gets the (mutable) vector of TestInfos in this TestSuite. + std::vector &test_info_list() { return test_info_list_; } - // Gets the (immutable) vector of TestInfos in this TestCase. - const std::vector& test_info_list() const { + // Gets the (immutable) vector of TestInfos in this TestSuite. + const std::vector &test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. - TestInfo* GetMutableTestInfo(int i); + TestInfo *GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. + void AddTestInfo(TestInfo *test_info); - // Clears the results of all tests in this test case. + // Clears the results of all tests in this test suite. void ClearResult(); - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite *test_suite) { + test_suite->ClearResult(); } - // Runs every test in this TestCase. + // Runs every test in this TestSuite. void Run(); - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } - // Returns true iff test passed. - static bool TestPassed(const TestInfo* test_info) { + // Returns true if and only if test passed. + static bool TestPassed(const TestInfo *test_info) { return test_info->should_run() && test_info->result()->Passed(); } - // Returns true iff test failed. - static bool TestFailed(const TestInfo* test_info) { + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo *test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. + static bool TestFailed(const TestInfo *test_info) { return test_info->should_run() && test_info->result()->Failed(); } - // Returns true iff the test is disabled and will be reported in the XML - // report. - static bool TestReportableDisabled(const TestInfo* test_info) { + // Returns true if and only if the test is disabled and will be reported in + // the XML report. + static bool TestReportableDisabled(const TestInfo *test_info) { return test_info->is_reportable() && test_info->is_disabled_; } - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo* test_info) { + // Returns true if and only if test is disabled. + static bool TestDisabled(const TestInfo *test_info) { return test_info->is_disabled_; } - // Returns true iff this test will appear in the XML report. - static bool TestReportable(const TestInfo* test_info) { + // Returns true if and only if this test will appear in the XML report. + static bool TestReportable(const TestInfo *test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo* test_info) { + static bool ShouldRunTest(const TestInfo *test_info) { return test_info->should_run(); } - // Shuffles the tests in this test case. - void ShuffleTests(internal::Random* random); + // Shuffles the tests in this test suite. + void ShuffleTests(internal::Random *random); // Restores the test order to before the first shuffle. void UnshuffleTests(); - // Name of the test case. + // Name of the test suite. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. - const internal::scoped_ptr type_param_; + const std::unique_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. - std::vector test_info_list_; + std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. TestResult ad_hoc_test_result_; - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); }; // An Environment object is capable of setting up and tearing down an @@ -1020,11 +1048,12 @@ class Environment { // Override this to define how to tear down the environment. virtual void TearDown() {} + private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + virtual Setup_should_be_spelled_SetUp *Setup() { return nullptr; } }; #if GTEST_HAS_EXCEPTIONS @@ -1033,7 +1062,7 @@ class Environment { class GTEST_API_ AssertionException : public internal::GoogleTestFailureException { public: - explicit AssertionException(const TestPartResult& result) + explicit AssertionException(const TestPartResult &result) : GoogleTestFailureException(result) {} }; @@ -1046,49 +1075,58 @@ class TestEventListener { virtual ~TestEventListener() {} // Fired before any test activity starts. - virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + virtual void OnTestProgramStart(const UnitTest &unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. - virtual void OnTestIterationStart(const UnitTest& unit_test, + virtual void OnTestIterationStart(const UnitTest &unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + virtual void OnEnvironmentsSetUpStart(const UnitTest &unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + virtual void OnEnvironmentsSetUpEnd(const UnitTest &unit_test) = 0; - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite & /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase & /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; + virtual void OnTestStart(const TestInfo &test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. // If you want to throw an exception from this function to skip to the next // TEST, it must be AssertionException defined above, or inherited from it. - virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + virtual void OnTestPartResult(const TestPartResult &test_part_result) = 0; // Fired after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; + virtual void OnTestEnd(const TestInfo &test_info) = 0; - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite & /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase & /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before environment tear-down for each iteration of tests starts. - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + virtual void OnEnvironmentsTearDownStart(const UnitTest &unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + virtual void OnEnvironmentsTearDownEnd(const UnitTest &unit_test) = 0; // Fired after each iteration of tests finishes. - virtual void OnTestIterationEnd(const UnitTest& unit_test, - int iteration) = 0; + virtual void OnTestIterationEnd(const UnitTest &unit_test, int iteration) = 0; // Fired after all test activities have ended. - virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; + virtual void OnTestProgramEnd(const UnitTest &unit_test) = 0; }; // The convenience class for users who need to override just one or two @@ -1098,21 +1136,30 @@ class TestEventListener { // above. class EmptyTestEventListener : public TestEventListener { public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest & /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest & /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest & /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest & /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite & /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase & /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo & /*test_info*/) override {} + void OnTestPartResult(const TestPartResult & /*test_part_result*/) override {} + void OnTestEnd(const TestInfo & /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite & /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase & /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest & /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest & /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest & /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest & /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. @@ -1124,19 +1171,19 @@ class GTEST_API_ TestEventListeners { // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). - void Append(TestEventListener* listener); + void Append(TestEventListener *listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. - TestEventListener* Release(TestEventListener* listener); + TestEventListener *Release(TestEventListener *listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. - TestEventListener* default_result_printer() const { + TestEventListener *default_result_printer() const { return default_result_printer_; } @@ -1147,12 +1194,12 @@ class GTEST_API_ TestEventListeners { // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. - TestEventListener* default_xml_generator() const { + TestEventListener *default_xml_generator() const { return default_xml_generator_; } private: - friend class TestCase; + friend class TestSuite; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; @@ -1161,21 +1208,21 @@ class GTEST_API_ TestEventListeners { // Returns repeater that broadcasts the TestEventListener events to all // subscribers. - TestEventListener* repeater(); + TestEventListener *repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. - void SetDefaultResultPrinter(TestEventListener* listener); + void SetDefaultResultPrinter(TestEventListener *listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. - void SetDefaultXmlGenerator(TestEventListener* listener); + void SetDefaultXmlGenerator(TestEventListener *listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. @@ -1183,17 +1230,17 @@ class GTEST_API_ TestEventListeners { void SuppressEventForwarding(); // The actual list of listeners. - internal::TestEventRepeater* repeater_; + internal::TestEventRepeater *repeater_; // Listener responsible for the standard result output. - TestEventListener* default_result_printer_; + TestEventListener *default_result_printer_; // Listener responsible for the creation of the XML output file. - TestEventListener* default_xml_generator_; + TestEventListener *default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; -// A UnitTest consists of a vector of TestCases. +// A UnitTest consists of a vector of TestSuites. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This @@ -1208,7 +1255,7 @@ class GTEST_API_ UnitTest { // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. - static UnitTest* GetInstance(); + static UnitTest *GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. @@ -1220,44 +1267,58 @@ class GTEST_API_ UnitTest { // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. - const char* original_working_dir() const; + const char *original_working_dir() const; - // Returns the TestCase object for the test that's currently running, + // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); + const TestSuite *current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase *current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. - const TestInfo* current_test_info() const - GTEST_LOCK_EXCLUDED_(mutex_); + const TestInfo *current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; - // Returns the ParameterizedTestCaseRegistry object used to keep track of + // Returns the ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + internal::ParameterizedTestSuiteRegistry ¶meterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -1283,24 +1344,30 @@ class GTEST_API_ UnitTest { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const; - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const; - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const; + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite *GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase *GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. - const TestResult& ad_hoc_test_result() const; + // properties logged outside of individual test suites. + const TestResult &ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. - TestEventListeners& listeners(); + TestEventListeners &listeners(); private: // Registers and returns a global test environment. When a test @@ -1312,33 +1379,32 @@ class GTEST_API_ UnitTest { // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. - Environment* AddEnvironment(Environment* env); + Environment *AddEnvironment(Environment *env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) + const char *file_name, int line_number, + const std::string &message, + const std::string &os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. - void RecordProperty(const std::string& key, const std::string& value); + void RecordProperty(const std::string &key, const std::string &value); - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite *GetMutableTestSuite(int i); // Accessors for the implementation object. - internal::UnitTestImpl* impl() { return impl_; } - const internal::UnitTestImpl* impl() const { return impl_; } + internal::UnitTestImpl *impl() { return impl_; } + const internal::UnitTestImpl *impl() const { return impl_; } // These classes and functions are friends as they need to access private // members of UnitTest. @@ -1347,11 +1413,11 @@ class GTEST_API_ UnitTest { friend class internal::AssertHelper; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; - friend Environment* AddGlobalTestEnvironment(Environment* env); - friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend Environment *AddGlobalTestEnvironment(Environment *env); + friend std::set *internal::GetIgnoredParameterizedTestSuites(); + friend internal::UnitTestImpl *internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( - TestPartResult::Type result_type, - const std::string& message); + TestPartResult::Type result_type, const std::string &message); // Creates an empty UnitTest. UnitTest(); @@ -1361,12 +1427,11 @@ class GTEST_API_ UnitTest { // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. - void PushGTestTrace(const internal::TraceInfo& trace) + void PushGTestTrace(const internal::TraceInfo &trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. - void PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_); + void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. @@ -1376,7 +1441,7 @@ class GTEST_API_ UnitTest { // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. - internal::UnitTestImpl* impl_; + internal::UnitTestImpl *impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); @@ -1400,7 +1465,7 @@ class GTEST_API_ UnitTest { // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). -inline Environment* AddGlobalTestEnvironment(Environment* env) { +inline Environment *AddGlobalTestEnvironment(Environment *env) { return UnitTest::GetInstance()->AddEnvironment(env); } @@ -1413,11 +1478,15 @@ inline Environment* AddGlobalTestEnvironment(Environment* env) { // updated. // // Calling the function for the second time has no user-visible effect. -GTEST_API_ void InitGoogleTest(int* argc, char** argv); +GTEST_API_ void InitGoogleTest(int *argc, char **argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. -GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); +GTEST_API_ void InitGoogleTest(int *argc, wchar_t **argv); + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); namespace internal { @@ -1425,22 +1494,26 @@ namespace internal { // frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers // when calling EXPECT_* in a tight loop. template -AssertionResult CmpHelperEQFailure(const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, const T2& rhs) { - return EqFailure(lhs_expression, - rhs_expression, +AssertionResult CmpHelperEQFailure(const char *lhs_expression, + const char *rhs_expression, const T1 &lhs, + const T2 &rhs) { + return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), - FormatForComparisonFailureMessage(rhs, lhs), - false); + FormatForComparisonFailureMessage(rhs, lhs), false); } +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + // The helper function for {ASSERT|EXPECT}_EQ. template -AssertionResult CmpHelperEQ(const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, - const T2& rhs) { +AssertionResult CmpHelperEQ(const char *lhs_expression, + const char *rhs_expression, const T1 &lhs, + const T2 &rhs) { if (lhs == rhs) { return AssertionSuccess(); } @@ -1451,24 +1524,22 @@ AssertionResult CmpHelperEQ(const char* lhs_expression, // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, - const char* rhs_expression, - BiggestInt lhs, - BiggestInt rhs); +GTEST_API_ AssertionResult CmpHelperEQ(const char *lhs_expression, + const char *rhs_expression, + BiggestInt lhs, BiggestInt rhs); -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template class EqHelper { public: // This templatized version is for the general case. - template - static AssertionResult Compare(const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, - const T2& rhs) { + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if::value || + !std::is_pointer::value>::type * = nullptr> + static AssertionResult Compare(const char *lhs_expression, + const char *rhs_expression, const T1 &lhs, + const T2 &rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } @@ -1478,55 +1549,20 @@ class EqHelper { // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* lhs_expression, - const char* rhs_expression, - BiggestInt lhs, + static AssertionResult Compare(const char *lhs_expression, + const char *rhs_expression, BiggestInt lhs, BiggestInt rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } -}; -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare( - const char* lhs_expression, - const char* rhs_expression, - const T1& lhs, - const T2& rhs, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); - } - - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( - const char* lhs_expression, - const char* rhs_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* lhs (NULL) */, - T* rhs) { + const char *lhs_expression, const char *rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T *rhs) { // We already know that 'lhs' is a null pointer. return CmpHelperEQ(lhs_expression, rhs_expression, - static_cast(NULL), rhs); + static_cast(nullptr), rhs); } }; @@ -1534,9 +1570,9 @@ class EqHelper { // frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers // when calling EXPECT_OP in a tight loop. template -AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, - const T1& val1, const T2& val2, - const char* op) { +AssertionResult CmpHelperOpFailure(const char *expr1, const char *expr2, + const T1 &val1, const T2 &val2, + const char *op) { return AssertionFailure() << "Expected: (" << expr1 << ") " << op << " (" << expr2 << "), actual: " << FormatForComparisonFailureMessage(val1, val2) @@ -1554,18 +1590,18 @@ AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -template \ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - const T1& val1, const T2& val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ - }\ -}\ -GTEST_API_ AssertionResult CmpHelper##op_name(\ - const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) +#define GTEST_IMPL_CMP_HELPER_(op_name, op) \ + template \ + AssertionResult CmpHelper##op_name(const char *expr1, const char *expr2, \ + const T1 &val1, const T2 &val2) { \ + if (val1 op val2) { \ + return AssertionSuccess(); \ + } else { \ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op); \ + } \ + } \ + GTEST_API_ AssertionResult CmpHelper##op_name( \ + const char *expr1, const char *expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. @@ -1585,51 +1621,44 @@ GTEST_IMPL_CMP_HELPER_(GT, >); // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char *s1_expression, + const char *s2_expression, + const char *s1, const char *s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char *s1_expression, + const char *s2_expression, + const char *s1, const char *s2); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); +GTEST_API_ AssertionResult CmpHelperSTRNE(const char *s1_expression, + const char *s2_expression, + const char *s1, const char *s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char *s1_expression, + const char *s2_expression, + const char *s1, const char *s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char *s1_expression, + const char *s2_expression, + const wchar_t *s1, const wchar_t *s2); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2); +GTEST_API_ AssertionResult CmpHelperSTRNE(const char *s1_expression, + const char *s2_expression, + const wchar_t *s1, const wchar_t *s2); } // namespace internal @@ -1641,32 +1670,40 @@ GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, + const char *haystack_expr, + const char *needle, + const char *haystack); +GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, + const char *haystack_expr, + const wchar_t *needle, + const wchar_t *haystack); +GTEST_API_ AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const char *needle, + const char *haystack); +GTEST_API_ AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const wchar_t *needle, + const wchar_t *haystack); +GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::string &needle, + const ::std::string &haystack); +GTEST_API_ AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::string &needle, + const ::std::string &haystack); #if GTEST_HAS_STD_WSTRING -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::wstring &needle, + const ::std::wstring &haystack); +GTEST_API_ AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::wstring &needle, + const ::std::wstring &haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { @@ -1679,10 +1716,9 @@ namespace internal { // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, - const char* rhs_expression, - RawType lhs_value, - RawType rhs_value) { +AssertionResult CmpHelperFloatingPointEQ(const char *lhs_expression, + const char *rhs_expression, + RawType lhs_value, RawType rhs_value) { const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { @@ -1697,21 +1733,18 @@ AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) << rhs_value; - return EqFailure(lhs_expression, - rhs_expression, - StringStreamToString(&lhs_ss), - StringStreamToString(&rhs_ss), + return EqFailure(lhs_expression, rhs_expression, + StringStreamToString(&lhs_ss), StringStreamToString(&rhs_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, +GTEST_API_ AssertionResult DoubleNearPredFormat(const char *expr1, + const char *expr2, + const char *abs_error_expr, + double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -1719,15 +1752,13 @@ GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, class GTEST_API_ AssertHelper { public: // Constructor. - AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message); + AssertHelper(TestPartResult::Type type, const char *file, int line, + const char *message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. - void operator=(const Message& message) const; + void operator=(const Message &message) const; private: // We put our data in a struct so that the size of the AssertHelper class can @@ -1735,14 +1766,12 @@ class GTEST_API_ AssertHelper { // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { - AssertHelperData(TestPartResult::Type t, - const char* srcfile, - int line_num, - const char* msg) - : type(t), file(srcfile), line(line_num), message(msg) { } + AssertHelperData(TestPartResult::Type t, const char *srcfile, int line_num, + const char *msg) + : type(t), file(srcfile), line(line_num), message(msg) {} TestPartResult::Type const type; - const char* const file; + const char *const file; int const line; std::string const message; @@ -1750,11 +1779,17 @@ class GTEST_API_ AssertHelper { GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; - AssertHelperData* const data_; + AssertHelperData *const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; +enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; + +GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, + const char *fmt, + ...); + } // namespace internal // The pure interface class that all value-parameterized tests inherit from. @@ -1774,13 +1809,13 @@ class GTEST_API_ AssertHelper { // FooTest() { // // Can use GetParam() here. // } -// virtual ~FooTest() { +// ~FooTest() override { // // Can use GetParam() here. // } -// virtual void SetUp() { +// void SetUp() override { // // Can use GetParam() here. // } -// virtual void TearDown { +// void TearDown override { // // Can use GetParam() here. // } // }; @@ -1789,7 +1824,7 @@ class GTEST_API_ AssertHelper { // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { @@ -1798,12 +1833,9 @@ class WithParamInterface { virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) + // constructor. + static const ParamType &GetParam() { + GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; @@ -1812,29 +1844,32 @@ class WithParamInterface { private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. - static void SetParam(const ParamType* parameter) { - parameter_ = parameter; - } + static void SetParam(const ParamType *parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. - static const ParamType* parameter_; + static const ParamType *parameter_; // TestClass must be a subclass of WithParamInterface and Test. - template friend class internal::ParameterizedTestFactory; + template + friend class internal::ParameterizedTestFactory; }; template -const T* WithParamInterface::parameter_ = NULL; +const T *WithParamInterface::parameter_ = nullptr; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template -class TestWithParam : public Test, public WithParamInterface { -}; +class TestWithParam : public Test, public WithParamInterface {}; // Macros for indicating success/failure in test code. +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("") + // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has @@ -1857,17 +1892,22 @@ class TestWithParam : public Test, public WithParamInterface { // Generates a nonfatal failure at the given source file location with // a generic message. -#define ADD_FAILURE_AT(file, line) \ +#define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL -# define FAIL() GTEST_FAIL() +#define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. @@ -1876,7 +1916,7 @@ class TestWithParam : public Test, public WithParamInterface { // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED -# define SUCCEED() GTEST_SUCCEED() +#define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. @@ -1904,16 +1944,15 @@ class TestWithParam : public Test, public WithParamInterface { // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. -#define EXPECT_TRUE(condition) \ +#define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) -#define EXPECT_FALSE(condition) \ +#define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_FATAL_FAILURE_) -#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) @@ -1964,9 +2003,7 @@ class TestWithParam : public Test, public WithParamInterface { // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - val1, val2) + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define EXPECT_NE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ @@ -1979,9 +2016,7 @@ class TestWithParam : public Test, public WithParamInterface { EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - val1, val2) + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ @@ -1997,27 +2032,27 @@ class TestWithParam : public Test, public WithParamInterface { // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ -# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE -# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE -# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT -# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE -# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT -# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string @@ -2042,7 +2077,7 @@ class TestWithParam : public Test, public WithParamInterface { EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) -#define EXPECT_STRCASENE(s1, s2)\ +#define EXPECT_STRCASENE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(s1, s2) \ @@ -2051,7 +2086,7 @@ class TestWithParam : public Test, public WithParamInterface { ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) -#define ASSERT_STRCASENE(s1, s2)\ +#define ASSERT_STRCASENE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. @@ -2068,29 +2103,29 @@ class TestWithParam : public Test, public WithParamInterface { // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. -#define EXPECT_FLOAT_EQ(val1, val2)\ +#define EXPECT_FLOAT_EQ(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) -#define EXPECT_DOUBLE_EQ(val1, val2)\ +#define EXPECT_DOUBLE_EQ(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) -#define ASSERT_FLOAT_EQ(val1, val2)\ +#define ASSERT_FLOAT_EQ(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) -#define ASSERT_DOUBLE_EQ(val1, val2)\ +#define ASSERT_DOUBLE_EQ(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) -#define EXPECT_NEAR(val1, val2, abs_error)\ - EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) +#define EXPECT_NEAR(val1, val2, abs_error) \ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, val1, val2, \ + abs_error) -#define ASSERT_NEAR(val1, val2, abs_error)\ - ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) +#define ASSERT_NEAR(val1, val2, abs_error) \ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, val1, val2, \ + abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. @@ -2099,12 +2134,11 @@ class TestWithParam : public Test, public WithParamInterface { // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. -GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, +GTEST_API_ AssertionResult FloatLE(const char *expr1, const char *expr2, float val1, float val2); -GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, +GTEST_API_ AssertionResult DoubleLE(const char *expr1, const char *expr2, double val1, double val2); - #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful @@ -2116,17 +2150,17 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. -# define EXPECT_HRESULT_SUCCEEDED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) +#define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) -# define ASSERT_HRESULT_SUCCEEDED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) +#define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) -# define EXPECT_HRESULT_FAILED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) +#define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) -# define ASSERT_HRESULT_FAILED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) +#define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS @@ -2141,9 +2175,9 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the given source file path and line number, // and the given message) to be included in every test failure message generated @@ -2163,22 +2197,16 @@ class GTEST_API_ ScopedTrace { // Template version. Uses Message() to convert the values into strings. // Slow, but flexible. template - ScopedTrace(const char* file, int line, const T& message) { + ScopedTrace(const char *file, int line, const T &message) { PushTrace(file, line, (Message() << message).GetString()); } // Optimize for some known types. - ScopedTrace(const char* file, int line, const char* message) { + ScopedTrace(const char *file, int line, const char *message) { PushTrace(file, line, message ? message : "(null)"); } -#if GTEST_HAS_GLOBAL_STRING - ScopedTrace(const char* file, int line, const ::string& message) { - PushTrace(file, line, message); - } -#endif - - ScopedTrace(const char* file, int line, const std::string& message) { + ScopedTrace(const char *file, int line, const std::string &message) { PushTrace(file, line, message); } @@ -2189,7 +2217,7 @@ class GTEST_API_ ScopedTrace { ~ScopedTrace(); private: - void PushTrace(const char* file, int line, std::string message); + void PushTrace(const char *file, int line, std::string message); GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its @@ -2211,14 +2239,13 @@ class GTEST_API_ ScopedTrace { // Assuming that each thread maintains its own stack of traces. // Therefore, a SCOPED_TRACE() would (correctly) only affect the // assertions in its own thread. -#define SCOPED_TRACE(message) \ - ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, (message)) - +#define SCOPED_TRACE(message) \ + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)( \ + __FILE__, __LINE__, (message)) // Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. +// StaticAssertTypeEq() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This @@ -2247,18 +2274,18 @@ class GTEST_API_ ScopedTrace { // // to cause a compiler error. template -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper(); +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same::value, "T1 and T2 are not the same type"); return true; } // Defines a test. // -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. // -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. // // Test code should appear between braces after an invocation of // this macro. Example: @@ -2277,28 +2304,28 @@ bool StaticAssertTypeEq() { // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. // // A test fixture class must be declared earlier. The user should put // the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { b_.AddElement(3); } +// void SetUp() override { b_.AddElement(3); } // // Foo a_; // Foo b_; @@ -2312,19 +2339,102 @@ bool StaticAssertTypeEq() { // EXPECT_EQ(a_.size(), 0); // EXPECT_EQ(b_.size(), 1); // } - -#define TEST_F(test_fixture, test_name)\ +// +// GOOGLETEST_CM0011 DO NOT DELETE +#if !GTEST_DONT_DEFINE_TEST +#define TEST_F(test_fixture, test_name) \ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +#endif // !GTEST_DONT_DEFINE_TEST // Returns a path to temporary directory. // Tries to determine an appropriate directory for the platform. GTEST_API_ std::string TempDir(); #ifdef _MSC_VER -# pragma warning(pop) +#pragma warning(pop) #endif +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo *RegisterTest(const char *test_suite_name, const char *test_name, + const char *type_param, const char *value_param, + const char *file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test *CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{ std::move(factory) }); +} + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -2337,9 +2447,7 @@ GTEST_API_ std::string TempDir(); // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; -inline int RUN_ALL_TESTS() { - return ::testing::UnitTest::GetInstance()->Run(); -} +inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_pred_impl.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_pred_impl.h index 0c1105cb8e..1fc21910bd 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_pred_impl.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_pred_impl.h @@ -27,11 +27,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This file is AUTOMATICALLY GENERATED on 01/02/2018 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. - // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ @@ -67,94 +66,76 @@ namespace testing { // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. -#define GTEST_ASSERT_(expression, on_failure) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ - ; \ - else \ + ; \ + else \ on_failure(gtest_ar.failure_message()) - // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. -template -AssertionResult AssertPred1Helper(const char* pred_text, - const char* e1, - Pred pred, - const T1& v1) { +template +AssertionResult AssertPred1Helper(const char *pred_text, const char *e1, + Pred pred, const T1 &v1) { if (pred(v1)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. -#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, v1), \ - on_failure) +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure) \ + GTEST_ASSERT_(pred_format(#v1, v1), on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. -#define GTEST_PRED1_(pred, v1, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ - #v1, \ - pred, \ - v1), on_failure) +#define GTEST_PRED1_(pred, v1, on_failure) \ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, #v1, pred, v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - - +#define ASSERT_PRED1(pred, v1) GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. -template -AssertionResult AssertPred2Helper(const char* pred_text, - const char* e1, - const char* e2, - Pred pred, - const T1& v1, - const T2& v2) { +template +AssertionResult AssertPred2Helper(const char *pred_text, const char *e1, + const char *e2, Pred pred, const T1 &v1, + const T2 &v2) { if (pred(v1, v2)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. -#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ - on_failure) +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure) \ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. -#define GTEST_PRED2_(pred, v1, v2, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ - #v1, \ - #v2, \ - pred, \ - v1, \ - v2), on_failure) +#define GTEST_PRED2_(pred, v1, v2, on_failure) \ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, #v1, #v2, pred, v1, v2), \ + on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ @@ -166,50 +147,34 @@ AssertionResult AssertPred2Helper(const char* pred_text, #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - - // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. -template -AssertionResult AssertPred3Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3) { +template +AssertionResult AssertPred3Helper(const char *pred_text, const char *e1, + const char *e2, const char *e3, Pred pred, + const T1 &v1, const T2 &v2, const T3 &v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. -#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ - on_failure) +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure) \ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. -#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - pred, \ - v1, \ - v2, \ - v3), on_failure) +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure) \ + GTEST_ASSERT_( \ + ::testing::AssertPred3Helper(#pred, #v1, #v2, #v3, pred, v1, v2, v3), \ + on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ @@ -221,57 +186,36 @@ AssertionResult AssertPred3Helper(const char* pred_text, #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - - // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. -template -AssertionResult AssertPred4Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4) { +template +AssertionResult AssertPred4Helper(const char *pred_text, const char *e1, + const char *e2, const char *e3, + const char *e4, Pred pred, const T1 &v1, + const T2 &v2, const T3 &v3, const T4 &v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. -#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ - on_failure) +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure) \ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. -#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4), on_failure) +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure) \ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, #v1, #v2, #v3, #v4, pred, \ + v1, v2, v3, v4), \ + on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ @@ -283,64 +227,40 @@ AssertionResult AssertPred4Helper(const char* pred_text, #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) - - // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. -template -AssertionResult AssertPred5Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - const char* e5, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4, - const T5& v5) { +AssertionResult AssertPred5Helper(const char *pred_text, const char *e1, + const char *e2, const char *e3, + const char *e4, const char *e5, Pred pred, + const T1 &v1, const T2 &v2, const T3 &v3, + const T4 &v4, const T5 &v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. -#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure) \ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. -#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - #v5, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4, \ - v5), on_failure) +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure) \ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, #v1, #v2, #v3, #v4, #v5, \ + pred, v1, v2, v3, v4, v5), \ + on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ @@ -352,8 +272,6 @@ AssertionResult AssertPred5Helper(const char* pred_text, #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) - - } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_prod.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_prod.h index e651671ebd..3dc5b23868 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_prod.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/gtest_prod.h @@ -28,8 +28,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Google C++ Testing and Mocking Framework definitions useful in production code. -// GOOGLETEST_CM0003 DO NOT DELETE +// Google C++ Testing and Mocking Framework definitions useful in production +// code. GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ @@ -55,7 +55,7 @@ // Note: The test class must be in the same namespace as the class being tested. // For example, putting MyClassTest in an anonymous namespace will not work. -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test +#define FRIEND_TEST(test_case_name, test_name) \ + friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-death-test-internal.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-death-test-internal.h index 0a9b42c8a5..3e9497d450 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -36,9 +36,11 @@ #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" #include +#include namespace testing { namespace internal { @@ -78,18 +80,20 @@ class GTEST_API_ DeathTest { // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + static bool Create(const char *statement, + Matcher matcher, const char *file, + int line, DeathTest **test); DeathTest(); - virtual ~DeathTest() { } + virtual ~DeathTest() {} // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: - explicit ReturnSentinel(DeathTest* test) : test_(test) { } + explicit ReturnSentinel(DeathTest *test) : test_(test) {} ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: - DeathTest* const test_; + DeathTest *const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; @@ -127,9 +131,9 @@ class GTEST_API_ DeathTest { // Returns a human-readable outcome message regarding the outcome of // the last death test. - static const char* LastMessage(); + static const char *LastMessage(); - static void set_last_death_test_message(const std::string& message); + static void set_last_death_test_message(const std::string &message); private: // A string containing a description of the outcome of the last death test. @@ -143,81 +147,103 @@ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: - virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; + virtual ~DeathTestFactory() {} + virtual bool Create(const char *statement, + Matcher matcher, const char *file, + int line, DeathTest **test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + bool Create(const char *statement, Matcher matcher, + const char *file, int line, DeathTest **test) override; }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher MakeDeathTestMatcher(const char *regex) { + return ContainsRegex(regex); +} +inline Matcher MakeDeathTestMatcher( + const ::std::string ®ex) { + return ContainsRegex(regex); +} + +// If a Matcher is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher MakeDeathTestMatcher( + Matcher matcher) { + return matcher; +} + // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. -# if GTEST_HAS_EXCEPTIONS -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } catch (const ::std::exception& gtest_exception) { \ - fprintf(\ - stderr, \ - "\n%s: Caught std::exception-derived exception escaping the " \ - "death test statement. Exception message: %s\n", \ +#if GTEST_HAS_EXCEPTIONS +#define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception >est_exception) { \ + fprintf( \ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ - gtest_exception.what()); \ - fflush(stderr); \ + gtest_exception.what()); \ + fflush(stderr); \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ - } catch (...) { \ + } catch (...) { \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } -# else -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ +#else +#define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) -# endif +#endif // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest *gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. @@ -226,14 +252,13 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // must accept a streamed message even though the message is never printed. // The regex object is not evaluated, but it is used to prevent "unused" // warnings and to avoid an expression that doesn't compile in debug mode. -#define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else if (!::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - static_cast(gtest_regex); \ - } else \ +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -241,19 +266,15 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: - InternalRunDeathTestFlag(const std::string& a_file, - int a_line, - int an_index, + InternalRunDeathTestFlag(const std::string &a_file, int a_line, int an_index, int a_write_fd) - : file_(a_file), line_(a_line), index_(an_index), - write_fd_(a_write_fd) {} + : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { - if (write_fd_ >= 0) - posix::Close(write_fd_); + if (write_fd_ >= 0) posix::Close(write_fd_); } - const std::string& file() const { return file_; } + const std::string &file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } @@ -270,7 +291,7 @@ class InternalRunDeathTestFlag { // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); +InternalRunDeathTestFlag *ParseInternalRunDeathTestFlag(); #endif // GTEST_HAS_DEATH_TEST diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-filepath.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-filepath.h index ae38d95bf8..b228d47342 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-filepath.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-filepath.h @@ -61,24 +61,22 @@ namespace internal { class GTEST_API_ FilePath { public: - FilePath() : pathname_("") { } - FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + FilePath() : pathname_("") {} + FilePath(const FilePath &rhs) : pathname_(rhs.pathname_) {} - explicit FilePath(const std::string& pathname) : pathname_(pathname) { + explicit FilePath(const std::string &pathname) : pathname_(pathname) { Normalize(); } - FilePath& operator=(const FilePath& rhs) { + FilePath &operator=(const FilePath &rhs) { Set(rhs); return *this; } - void Set(const FilePath& rhs) { - pathname_ = rhs.pathname_; - } + void Set(const FilePath &rhs) { pathname_ = rhs.pathname_; } - const std::string& string() const { return pathname_; } - const char* c_str() const { return pathname_.c_str(); } + const std::string &string() const { return pathname_; } + const char *c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); @@ -87,16 +85,15 @@ class GTEST_API_ FilePath { // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. - static FilePath MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension); + static FilePath MakeFileName(const FilePath &directory, + const FilePath &base_name, int number, + const char *extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. - static FilePath ConcatPaths(const FilePath& directory, - const FilePath& relative_path); + static FilePath ConcatPaths(const FilePath &directory, + const FilePath &relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or @@ -106,11 +103,11 @@ class GTEST_API_ FilePath { // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. - static FilePath GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension); + static FilePath GenerateUniqueFileName(const FilePath &directory, + const FilePath &base_name, + const char *extension); - // Returns true iff the path is "". + // Returns true if and only if the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns @@ -138,7 +135,7 @@ class GTEST_API_ FilePath { // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. - FilePath RemoveExtension(const char* extension) const; + FilePath RemoveExtension(const char *extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create @@ -198,7 +195,7 @@ class GTEST_API_ FilePath { // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. - const char* FindLastPathSeparator() const; + const char *FindLastPathSeparator() const; std::string pathname_; }; // class FilePath diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h index b762f61fc5..9640aba836 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-internal.h @@ -40,24 +40,26 @@ #include "gtest/internal/gtest-port.h" #if GTEST_OS_LINUX -# include -# include -# include -# include +#include +#include +#include +#include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS -# include +#include #endif #include #include #include +#include #include #include #include #include #include +#include #include #include "gtest/gtest-message.h" @@ -74,75 +76,74 @@ // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) -#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo##bar // Stringifies its argument. -#define GTEST_STRINGIFY_(name) #name +// Work around a bug in visual studio which doesn't accept code like this: +// +// #define GTEST_STRINGIFY_(name) #name +// #define MACRO(a, b, c) ... GTEST_STRINGIFY_(a) ... +// MACRO(, x, y) +// +// Complaining about the argument to GTEST_STRINGIFY_ being empty. +// This is allowed by the spec. +#define GTEST_STRINGIFY_HELPER_(name, ...) #name +#define GTEST_STRINGIFY_(...) GTEST_STRINGIFY_HELPER_(__VA_ARGS__, ) -class ProtocolMessage; -namespace proto2 { class Message; } +namespace proto2 { +class Message; +} namespace testing { // Forward declarations. -class AssertionResult; // Result of an assertion. -class Message; // Represents a failure message. -class Test; // Represents a test. -class TestInfo; // Information about a test. -class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test suites. template -::std::string PrintToString(const T& value); +::std::string PrintToString(const T &value); namespace internal { -struct TraceInfo; // Information about a trace point. -class TestInfoImpl; // Opaque implementation of TestInfo -class UnitTestImpl; // Opaque implementation of UnitTest +struct TraceInfo; // Information about a trace point. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> + IgnoredValue(const T & /* ignored */) {} // NOLINT(runtime/explicit) +}; // Appends the user-supplied message to the Google-Test-generated message. -GTEST_API_ std::string AppendUserMessage( - const std::string& gtest_msg, const Message& user_msg); +GTEST_API_ std::string AppendUserMessage(const std::string >est_msg, + const Message &user_msg); #if GTEST_HAS_EXCEPTIONS -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ -/* an exported class was derived from a class that was not exported */) +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4275 /* an exported class was derived from a class that was not exported */) // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions @@ -152,7 +153,7 @@ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: - explicit GoogleTestFailureException(const TestPartResult& failure); + explicit GoogleTestFailureException(const TestPartResult &failure); }; GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 @@ -167,16 +168,16 @@ namespace edit_distance { // See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm enum EditType { kMatch, kAdd, kRemove, kReplace }; GTEST_API_ std::vector CalculateOptimalEdits( - const std::vector& left, const std::vector& right); + const std::vector &left, const std::vector &right); // Same as above, but the input is represented as strings. GTEST_API_ std::vector CalculateOptimalEdits( - const std::vector& left, - const std::vector& right); + const std::vector &left, + const std::vector &right); // Create a diff of the input strings in Unified diff format. -GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, - const std::vector& right, +GTEST_API_ std::string CreateUnifiedDiff(const std::vector &left, + const std::vector &right, size_t context = 2); } // namespace edit_distance @@ -185,9 +186,9 @@ GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, // format. // If not null, stores in 'total_line_count' the total number of lines found // in left + right. -GTEST_API_ std::string DiffStrings(const std::string& left, - const std::string& right, - size_t* total_line_count); +GTEST_API_ std::string DiffStrings(const std::string &left, + const std::string &right, + size_t *total_line_count); // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. @@ -201,21 +202,19 @@ GTEST_API_ std::string DiffStrings(const std::string& left, // expected_value: "5" // actual_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. -GTEST_API_ AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, +GTEST_API_ AssertionResult EqFailure(const char *expected_expression, + const char *actual_expression, + const std::string &expected_value, + const std::string &actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value); + const AssertionResult &assertion_result, const char *expression_text, + const char *actual_predicate_value, const char *expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the @@ -256,11 +255,11 @@ class FloatingPoint { // Constants. // # of bits in a number. - static const size_t kBitCount = 8*sizeof(RawType); + static const size_t kBitCount = 8 * sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = - std::numeric_limits::digits - 1; + std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; @@ -269,8 +268,8 @@ class FloatingPoint { static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. - static const Bits kFractionBitMask = - ~static_cast(0) >> (kExponentBitCount + 1); + static const Bits kFractionBitMask = ~static_cast(0) >> + (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); @@ -295,7 +294,7 @@ class FloatingPoint { // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + explicit FloatingPoint(const RawType &x) { u_.value_ = x; } // Static methods @@ -309,9 +308,7 @@ class FloatingPoint { } // Returns the floating-point number that represent positive infinity. - static RawType Infinity() { - return ReinterpretBits(kExponentBitMask); - } + static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); @@ -330,26 +327,26 @@ class FloatingPoint { // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } - // Returns true iff this is NAN (not a number). + // Returns true if and only if this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. - bool AlmostEquals(const FloatingPoint& rhs) const { + bool AlmostEquals(const FloatingPoint &rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) - <= kMaxUlps; + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= + kMaxUlps; } private: @@ -399,9 +396,13 @@ class FloatingPoint { // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> -inline float FloatingPoint::Max() { return FLT_MAX; } +inline float FloatingPoint::Max() { + return FLT_MAX; +} template <> -inline double FloatingPoint::Max() { return DBL_MAX; } +inline double FloatingPoint::Max() { + return DBL_MAX; +} // Typedefs the instances of the FloatingPoint template class that we // care to use. @@ -409,12 +410,12 @@ typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign +// test fixture classes in the same test suite, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. -typedef const void* TypeId; +typedef const void *TypeId; template class TypeIdHelper { @@ -455,7 +456,7 @@ class TestFactoryBase { // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() - virtual Test* CreateTest() = 0; + virtual Test *CreateTest() = 0; protected: TestFactoryBase() {} @@ -469,7 +470,7 @@ class TestFactoryBase { template class TestFactoryImpl : public TestFactoryBase { public: - virtual Test* CreateTest() { return new TestClass; } + Test *CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS @@ -478,31 +479,83 @@ class TestFactoryImpl : public TestFactoryBase { // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. -GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, +GTEST_API_ AssertionResult IsHRESULTSuccess(const char *expr, long hr); // NOLINT -GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, +GTEST_API_ AssertionResult IsHRESULTFailure(const char *expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); struct CodeLocation { - CodeLocation(const std::string& a_file, int a_line) + CodeLocation(const std::string &a_file, int a_line) : file(a_file), line(a_line) {} std::string file; int line; }; +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char *filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char *filename, + int line_num) { + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; + } +}; + // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. @@ -510,45 +563,41 @@ struct CodeLocation { // or NULL if this is not a type-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. -GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - CodeLocation code_location, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); +GTEST_API_ TestInfo *MakeAndRegisterTestInfo( + const char *test_suite_name, const char *name, const char *type_param, + const char *value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase *factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. -GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); +GTEST_API_ bool SkipPrefix(const char *prefix, const char **pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { public: - TypedTestCasePState() : registered_(false) {} + TypedTestSuitePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the + // if the test suite hasn't been registered; otherwise aborts the // program. - bool AddTestName(const char* file, int line, const char* case_name, - const char* test_name) { + bool AddTestName(const char *file, int line, const char *case_name, + const char *test_name) { if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); @@ -558,11 +607,11 @@ class GTEST_API_ TypedTestCasePState { return true; } - bool TestExists(const std::string& test_name) const { + bool TestExists(const std::string &test_name) const { return registered_tests_.count(test_name) > 0; } - const CodeLocation& GetCodeLocation(const std::string& test_name) const { + const CodeLocation &GetCodeLocation(const std::string &test_name) const { RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); GTEST_CHECK_(it != registered_tests_.end()); return it->second; @@ -571,8 +620,9 @@ class GTEST_API_ TypedTestCasePState { // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. - const char* VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests); + const char *VerifyRegisteredTestNames(const char *test_suite_name, + const char *file, int line, + const char *registered_tests); private: typedef ::std::map RegisteredTestsMap; @@ -581,30 +631,36 @@ class GTEST_API_ TypedTestCasePState { RegisteredTestsMap registered_tests_; }; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. -inline const char* SkipComma(const char* str) { - const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; +inline const char *SkipComma(const char *str) { + const char *comma = strchr(str, ','); + if (comma == nullptr) { + return nullptr; + } + while (IsSpace(*(++comma))) { } - while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. -inline std::string GetPrefixUntilComma(const char* str) { - const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); +inline std::string GetPrefixUntilComma(const char *str) { + const char *comma = strchr(str, ','); + return comma == nullptr ? str : std::string(str, comma); } // Splits a given string on a given delimiter, populating a given // vector with the fields. -void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest); +void SplitString(const ::std::string &str, char delimiter, + ::std::vector<::std::string> *dest); // The default argument to the template below for the case when the user does // not provide a name generator. @@ -621,10 +677,11 @@ struct NameGeneratorSelector { }; template -void GenerateNamesRecursively(Types0, std::vector*, int) {} +void GenerateNamesRecursively(internal::None, std::vector *, int) { +} template -void GenerateNamesRecursively(Types, std::vector* result, int i) { +void GenerateNamesRecursively(Types, std::vector *result, int i) { result->push_back(NameGenerator::template GetName(i)); GenerateNamesRecursively(typename Types::Tail(), result, i + 1); @@ -648,12 +705,12 @@ template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, const CodeLocation& code_location, - const char* case_name, const char* test_names, int index, - const std::vector& type_names = + static bool Register(const char *prefix, const CodeLocation &code_location, + const char *case_name, const char *test_names, int index, + const std::vector &type_names = GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; @@ -663,13 +720,17 @@ class TypeParameterizedTest { // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + - "/" + type_names[index]) + "/" + type_names[static_cast(index)]) .c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), - NULL, // No value parameter. - code_location, GetTypeId(), TestClass::SetUpTestCase, - TestClass::TearDownTestCase, new TestFactoryImpl); + nullptr, // No value parameter. + code_location, GetTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), + new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest -class TypeParameterizedTest { +class TypeParameterizedTest { public: - static bool Register(const char* /*prefix*/, const CodeLocation&, - const char* /*case_name*/, const char* /*test_names*/, + static bool Register(const char * /*prefix*/, const CodeLocation &, + const char * /*case_name*/, const char * /*test_names*/, int /*index*/, - const std::vector& = + const std::vector & = std::vector() /*type_names*/) { return true; } }; -// TypeParameterizedTestCase::Register() +GTEST_API_ void RegisterTypeParameterizedTestSuite(const char *test_suite_name, + CodeLocation code_location); +GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation( + const char *case_name); + +// TypeParameterizedTestSuite::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* prefix, CodeLocation code_location, - const TypedTestCasePState* state, const char* case_name, - const char* test_names, - const std::vector& type_names = + static bool Register(const char *prefix, CodeLocation code_location, + const TypedTestSuitePState *state, const char *case_name, + const char *test_names, + const std::vector &type_names = GenerateNames()) { - std::string test_name = StripTrailingSpaces( - GetPrefixUntilComma(test_names)); + RegisterTypeParameterizedTestSuiteInstantiation(case_name); + std::string test_name = + StripTrailingSpaces(GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { fprintf(stderr, "Failed to get code location for test %s.%s at %s.", case_name, test_name.c_str(), - FormatFileLocation(code_location.file.c_str(), - code_location.line).c_str()); + FormatFileLocation(code_location.file.c_str(), code_location.line) + .c_str()); fflush(stderr); posix::Abort(); } - const CodeLocation& test_location = state->GetCodeLocation(test_name); + const CodeLocation &test_location = state->GetCodeLocation(test_name); typedef typename Tests::Head Head; @@ -726,22 +793,22 @@ class TypeParameterizedTestCase { prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase::Register(prefix, code_location, - state, case_name, - SkipComma(test_names), - type_names); + return TypeParameterizedTestSuite::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; // The base case for the compile time recursion. template -class TypeParameterizedTestCase { +class TypeParameterizedTestSuite { public: - static bool Register(const char* /*prefix*/, const CodeLocation&, - const TypedTestCasePState* /*state*/, - const char* /*case_name*/, const char* /*test_names*/, - const std::vector& = + static bool Register(const char * /*prefix*/, const CodeLocation &, + const TypedTestSuitePState * /*state*/, + const char * /*case_name*/, const char * /*test_names*/, + const std::vector & = std::vector() /*type_names*/) { return true; } @@ -759,8 +826,8 @@ class TypeParameterizedTestCase { // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( - UnitTest* unit_test, int skip_count); +GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(UnitTest *unit_test, + int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. @@ -775,9 +842,19 @@ inline bool AlwaysFalse() { return !AlwaysTrue(); } // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { - ConstCharPtr(const char* str) : value(str) {} + ConstCharPtr(const char *str) : value(str) {} operator bool() const { return true; } - const char* value; + const char *value; +}; + +// Helper for declaring std::string within 'if' statement +// in pre C++17 build environment. +struct TrueWithString { + TrueWithString() = default; + explicit TrueWithString(const char *str) : value(str) {} + explicit TrueWithString(const std::string &str) : value(str) {} + explicit operator bool() const { return true; } + std::string value; }; // A simple Linear Congruential Generator for generating random @@ -787,135 +864,30 @@ struct GTEST_API_ ConstCharPtr { // but it's good enough for our purposes. class GTEST_API_ Random { public: - static const UInt32 kMaxRange = 1u << 31; + static const uint32_t kMaxRange = 1u << 31; - explicit Random(UInt32 seed) : state_(seed) {} + explicit Random(uint32_t seed) : state_(seed) {} - void Reseed(UInt32 seed) { state_ = seed; } + void Reseed(uint32_t seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. - UInt32 Generate(UInt32 range); + uint32_t Generate(uint32_t range); private: - UInt32 state_; + uint32_t state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static typename AddReference::type MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: -#if defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; - GTEST_DISABLE_MSC_WARNINGS_POP_() -#endif // __BORLANDC__ -}; -template -const bool ImplicitlyConvertible::value; + typename std::remove_const::type>::type // IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. +// true if and only if T is type proto2::Message or a subclass of it. template struct IsAProtocolMessage - : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; + : public std::is_convertible {}; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest @@ -942,28 +914,21 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; -#if GTEST_LANG_CXX11 template ().begin()), - class = decltype(::std::declval().end()), - class = decltype(++::std::declval()), + class Iterator = decltype(::std::declval().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), class = decltype(*::std::declval()), class = typename C::const_iterator> IsContainer IsContainerTest(int /* dummy */) { return 0; } -#else -template -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { - return 0; -} -#endif // GTEST_LANG_CXX11 typedef char IsNotContainer; template -IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } +IsNotContainer IsContainerTest(long /* dummy */) { + return '\0'; +} // Trait to detect whether a type T is a hash table. // The heuristic used is that the type contains an inner type `hasher` and does @@ -973,54 +938,37 @@ template struct IsHashTable { private: template - static char test(typename U::hasher*, typename U::reverse_iterator*); + static char test(typename U::hasher *, typename U::reverse_iterator *); template - static int test(typename U::hasher*, ...); + static int test(typename U::hasher *, ...); template static char test(...); public: - static const bool value = sizeof(test(0, 0)) == sizeof(int); + static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); }; template const bool IsHashTable::value; -template -struct VoidT { - typedef void value_type; -}; - -template -struct HasValueType : false_type {}; -template -struct HasValueType > : true_type { -}; - template (0)) == sizeof(IsContainer), - bool = HasValueType::value> + bool = sizeof(IsContainerTest(0)) == sizeof(IsContainer)> struct IsRecursiveContainerImpl; -template -struct IsRecursiveContainerImpl : public false_type {}; +template +struct IsRecursiveContainerImpl : public std::false_type {}; // Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to // obey the same inconsistencies as the IsContainerTest, namely check if // something is a container is relying on only const_iterator in C++11 and // is relying on both const_iterator and iterator otherwise template -struct IsRecursiveContainerImpl : public false_type {}; - -template -struct IsRecursiveContainerImpl { - #if GTEST_LANG_CXX11 - typedef typename IteratorTraits::value_type - value_type; -#else - typedef typename IteratorTraits::value_type value_type; -#endif - typedef is_same type; +struct IsRecursiveContainerImpl { + using value_type = decltype(*std::declval()); + using type = + std::is_same::type>::type, + C>; }; // IsRecursiveContainer is a unary compile-time predicate that @@ -1032,13 +980,6 @@ struct IsRecursiveContainerImpl { template struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; -// EnableIf::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf::type* = 0" as the last parameter. -template struct EnableIf; -template<> struct EnableIf { typedef void type; }; // NOLINT - // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the @@ -1046,15 +987,17 @@ template<> struct EnableIf { typedef void type; }; // NOLINT // 0, ArrayEq() degenerates into comparing a single pair of values. template -bool ArrayEq(const T* lhs, size_t size, const U* rhs); +bool ArrayEq(const T *lhs, size_t size, const U *rhs); // This generic version is used when k is 0. template -inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } +inline bool ArrayEq(const T &lhs, const U &rhs) { + return lhs == rhs; +} // This overload is used when k >= 1. template -inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { +inline bool ArrayEq(const T (&lhs)[N], const U (&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } @@ -1062,10 +1005,9 @@ inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template -bool ArrayEq(const T* lhs, size_t size, const U* rhs) { +bool ArrayEq(const T *lhs, size_t size, const U *rhs) { for (size_t i = 0; i != size; i++) { - if (!internal::ArrayEq(lhs[i], rhs[i])) - return false; + if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } @@ -1073,10 +1015,9 @@ bool ArrayEq(const T* lhs, size_t size, const U* rhs) { // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template -Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { +Iter ArrayAwareFind(Iter begin, Iter end, const Element &elem) { for (Iter it = begin; it != end; ++it) { - if (internal::ArrayEq(*it, elem)) - return it; + if (internal::ArrayEq(*it, elem)) return it; } return end; } @@ -1086,15 +1027,17 @@ Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { // CopyArray() degenerates into copying a single value. template -void CopyArray(const T* from, size_t size, U* to); +void CopyArray(const T *from, size_t size, U *to); // This generic version is used when k is 0. template -inline void CopyArray(const T& from, U* to) { *to = from; } +inline void CopyArray(const T &from, U *to) { + *to = from; +} // This overload is used when k >= 1. template -inline void CopyArray(const T(&from)[N], U(*to)[N]) { +inline void CopyArray(const T (&from)[N], U (*to)[N]) { internal::CopyArray(from, N, *to); } @@ -1102,7 +1045,7 @@ inline void CopyArray(const T(&from)[N], U(*to)[N]) { // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template -void CopyArray(const T* from, size_t size, U* to) { +void CopyArray(const T *from, size_t size, U *to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } @@ -1128,47 +1071,44 @@ class NativeArray { public: // STL-style container typedefs. typedef Element value_type; - typedef Element* iterator; - typedef const Element* const_iterator; + typedef Element *iterator; + typedef const Element *const_iterator; // Constructs from a native array. References the source. - NativeArray(const Element* array, size_t count, RelationToSourceReference) { + NativeArray(const Element *array, size_t count, RelationToSourceReference) { InitRef(array, count); } // Constructs from a native array. Copies the source. - NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + NativeArray(const Element *array, size_t count, RelationToSourceCopy) { InitCopy(array, count); } // Copy constructor. - NativeArray(const NativeArray& rhs) { + NativeArray(const NativeArray &rhs) { (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { - if (clone_ != &NativeArray::InitRef) - delete[] array_; + if (clone_ != &NativeArray::InitRef) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } - bool operator==(const NativeArray& rhs) const { - return size() == rhs.size() && - ArrayEq(begin(), size(), rhs.begin()); + bool operator==(const NativeArray &rhs) const { + return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: - enum { - kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< - Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value - }; + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); // Initializes this object with a copy of the input. - void InitCopy(const Element* array, size_t a_size) { - Element* const copy = new Element[a_size]; + void InitCopy(const Element *array, size_t a_size) { + Element *const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; size_ = a_size; @@ -1176,25 +1116,161 @@ class NativeArray { } // Initializes this object with a reference of the input. - void InitRef(const Element* array, size_t a_size) { + void InitRef(const Element *array, size_t a_size) { array_ = array; size_ = a_size; clone_ = &NativeArray::InitRef; } - const Element* array_; + const Element *array_; size_t size_; - void (NativeArray::*clone_)(const Element*, size_t); + void (NativeArray::*clone_)(const Element *, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; +// Backport of std::index_sequence. +template +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template +struct DoubleSequence; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template +struct MakeIndexSequence + : DoubleSequence::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequence<0> : IndexSequence<> {}; + +template +struct Ignore { + Ignore(...); // NOLINT +}; + +template +struct ElemFromListImpl; +template +struct ElemFromListImpl> { + // We make Ignore a template to solve a problem with MSVC. + // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but + // MSVC doesn't understand how to deal with that pack expansion. + // Use `0 * I` to have a single instantiation of Ignore. + template + static R Apply(Ignore<0 * I>..., R (*)(), ...); +}; + +template +struct ElemFromList { + using type = + decltype(ElemFromListImpl::type>::Apply( + static_cast(nullptr)...)); +}; + +template +class FlatTuple; + +template +struct FlatTupleElemBase; + +template +struct FlatTupleElemBase, I> { + using value_type = typename ElemFromList::type; + FlatTupleElemBase() = default; + explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} + value_type value; +}; + +template +struct FlatTupleBase; + +template +struct FlatTupleBase, IndexSequence> + : FlatTupleElemBase, Idx>... { + using Indices = IndexSequence; + FlatTupleBase() = default; + explicit FlatTupleBase(T... t) + : FlatTupleElemBase, Idx>(std::move(t))... {} +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements than std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template +class FlatTuple + : private FlatTupleBase, + typename MakeIndexSequence::type> { + using Indices = typename FlatTupleBase< + FlatTuple, typename MakeIndexSequence::type>::Indices; + + public: + FlatTuple() = default; + explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} + + template + const typename ElemFromList::type &Get() const { + return static_cast *>(this)->value; + } + + template + typename ElemFromList::type &Get() { + return static_cast *>(this)->value; + } +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + } // namespace internal } // namespace testing -#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ - ::testing::internal::AssertHelper(result_type, file, line, message) \ - = ::testing::Message() +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) = \ + ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) @@ -1208,123 +1284,158 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppress MSVC warning 4702 (unreachable code) for the code following +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ - if (::testing::internal::AlwaysTrue()) { statement; } + if (::testing::internal::AlwaysTrue()) { \ + statement; \ + } -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const &) { \ + gtest_caught_expected = true; \ + } catch (...) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value) -#define GTEST_TEST_NO_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ - fail("Expected: " #statement " doesn't throw an exception.\n" \ - " Actual: it throws.") +#if GTEST_HAS_EXCEPTIONS -#define GTEST_TEST_ANY_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - bool gtest_caught_any = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - gtest_caught_any = true; \ - } \ - if (!gtest_caught_any) { \ +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (std::exception const &e) { \ + gtest_msg.value = \ + ("it throws std::exception-derived exception with description: \""); \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (...) { \ + gtest_msg.value = "it throws."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__) \ + : fail(("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: " + \ + gtest_msg.value) \ + .c_str()) + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ - fail("Expected: " #statement " throws an exception.\n" \ - " Actual: it doesn't.") - + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__) \ + : fail("Expected: " #statement \ + " throws an exception.\n" \ + " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar_ = \ - ::testing::AssertionResult(expression)) \ - ; \ - else \ - fail(::testing::internal::GetBoolAssertionFailureMessage(\ - gtest_ar_, text, #actual, #expected).c_str()) + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage( \ + gtest_ar_, text, #actual, #expected) \ + .c_str()) -#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ - fail("Expected: " #statement " doesn't generate new fatal " \ - "failures in the current thread.\n" \ - " Actual: it does.") + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__) \ + : fail("Expected: " #statement \ + " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") // Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test // Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + GTEST_DISALLOW_MOVE_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + \ + private: \ + void TestBody() override; \ + static ::testing::TestInfo *const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + }; \ + \ + ::testing::TestInfo *const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-linked_ptr.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-linked_ptr.h deleted file mode 100644 index 082b87289a..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-linked_ptr.h +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2003 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// A "smart" pointer type with reference tracking. Every pointer to a -// particular object is kept on a circular linked list. When the last pointer -// to an object is destroyed or reassigned, the object is deleted. -// -// Used properly, this deletes the object when the last reference goes away. -// There are several caveats: -// - Like all reference counting schemes, cycles lead to leaks. -// - Each smart pointer is actually two pointers (8 bytes instead of 4). -// - Every time a pointer is assigned, the entire list of pointers to that -// object is traversed. This class is therefore NOT SUITABLE when there -// will often be more than two or three pointers to a particular object. -// - References are only tracked as long as linked_ptr<> objects are copied. -// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS -// will happen (double deletion). -// -// A good use of this class is storing object references in STL containers. -// You can safely put linked_ptr<> in a vector<>. -// Other uses may not be as good. -// -// Note: If you use an incomplete type with linked_ptr<>, the class -// *containing* linked_ptr<> must have a constructor and destructor (even -// if they do nothing!). -// -// Bill Gibbons suggested we use something like this. -// -// Thread Safety: -// Unlike other linked_ptr implementations, in this implementation -// a linked_ptr object is thread-safe in the sense that: -// - it's safe to copy linked_ptr objects concurrently, -// - it's safe to copy *from* a linked_ptr and read its underlying -// raw pointer (e.g. via get()) concurrently, and -// - it's safe to write to two linked_ptrs that point to the same -// shared object concurrently. -// FIXME: rename this to safe_linked_ptr to avoid -// confusion with normal linked_ptr. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ - -#include -#include - -#include "gtest/internal/gtest-port.h" - -namespace testing { -namespace internal { - -// Protects copying of all linked_ptr objects. -GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// This is used internally by all instances of linked_ptr<>. It needs to be -// a non-template class because different types of linked_ptr<> can refer to -// the same object (linked_ptr(obj) vs linked_ptr(obj)). -// So, it needs to be possible for different types of linked_ptr to participate -// in the same circular linked list, so we need a single class type here. -// -// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. -class linked_ptr_internal { - public: - // Create a new circle that includes only this instance. - void join_new() { - next_ = this; - } - - // Many linked_ptr operations may change p.link_ for some linked_ptr - // variable p in the same circle as this object. Therefore we need - // to prevent two such operations from occurring concurrently. - // - // Note that different types of linked_ptr objects can coexist in a - // circle (e.g. linked_ptr, linked_ptr, and - // linked_ptr). Therefore we must use a single mutex to - // protect all linked_ptr objects. This can create serious - // contention in production code, but is acceptable in a testing - // framework. - - // Join an existing circle. - void join(linked_ptr_internal const* ptr) - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) { - assert(p->next_ != this && - "Trying to join() a linked ring we are already in. " - "Is GMock thread safety enabled?"); - p = p->next_; - } - p->next_ = this; - next_ = ptr; - } - - // Leave whatever circle we're part of. Returns true if we were the - // last member of the circle. Once this is done, you can join() another. - bool depart() - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - if (next_ == this) return true; - linked_ptr_internal const* p = next_; - while (p->next_ != this) { - assert(p->next_ != next_ && - "Trying to depart() a linked ring we are not in. " - "Is GMock thread safety enabled?"); - p = p->next_; - } - p->next_ = next_; - return false; - } - - private: - mutable linked_ptr_internal const* next_; -}; - -template -class linked_ptr { - public: - typedef T element_type; - - // Take over ownership of a raw pointer. This should happen as soon as - // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } - ~linked_ptr() { depart(); } - - // Copy an existing linked_ptr<>, adding ourselves to the list of references. - template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } - linked_ptr(linked_ptr const& ptr) { // NOLINT - assert(&ptr != this); - copy(&ptr); - } - - // Assignment releases the old value and acquires the new. - template linked_ptr& operator=(linked_ptr const& ptr) { - depart(); - copy(&ptr); - return *this; - } - - linked_ptr& operator=(linked_ptr const& ptr) { - if (&ptr != this) { - depart(); - copy(&ptr); - } - return *this; - } - - // Smart pointer members. - void reset(T* ptr = NULL) { - depart(); - capture(ptr); - } - T* get() const { return value_; } - T* operator->() const { return value_; } - T& operator*() const { return *value_; } - - bool operator==(T* p) const { return value_ == p; } - bool operator!=(T* p) const { return value_ != p; } - template - bool operator==(linked_ptr const& ptr) const { - return value_ == ptr.get(); - } - template - bool operator!=(linked_ptr const& ptr) const { - return value_ != ptr.get(); - } - - private: - template - friend class linked_ptr; - - T* value_; - linked_ptr_internal link_; - - void depart() { - if (link_.depart()) delete value_; - } - - void capture(T* ptr) { - value_ = ptr; - link_.join_new(); - } - - template void copy(linked_ptr const* ptr) { - value_ = ptr->get(); - if (value_) - link_.join(&ptr->link_); - else - link_.join_new(); - } -}; - -template inline -bool operator==(T* ptr, const linked_ptr& x) { - return ptr == x.get(); -} - -template inline -bool operator!=(T* ptr, const linked_ptr& x) { - return ptr != x.get(); -} - -// A function to convert T* into linked_ptr -// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation -// for linked_ptr >(new FooBarBaz(arg)) -template -linked_ptr make_linked_ptr(T* ptr) { - return linked_ptr(ptr); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h deleted file mode 100644 index 4fac8c0270..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h +++ /dev/null @@ -1,5552 +0,0 @@ -// This file was GENERATED by command: -// pump.py gtest-param-util-generated.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Type and function utilities for implementing parameterized tests. -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently Google Test supports at most 50 arguments in Values, -// and at most 10 arguments in Combine. Please contact -// googletestframework@googlegroups.com if you need more. -// Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tuple which is -// currently set at 10. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -#include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-port.h" - -namespace testing { - -// Forward declarations of ValuesIn(), which is implemented in -// include/gtest/gtest-param-test.h. -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end); - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]); - -template -internal::ParamGenerator ValuesIn( - const Container& container); - -namespace internal { - -// Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_)}; - return ValuesIn(array); - } - - ValueArray1(const ValueArray1& other) : v1_(other.v1_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -template -class ValueArray2 { - public: - ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_)}; - return ValuesIn(array); - } - - ValueArray2(const ValueArray2& other) : v1_(other.v1_), v2_(other.v2_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray2& other); - - const T1 v1_; - const T2 v2_; -}; - -template -class ValueArray3 { - public: - ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_)}; - return ValuesIn(array); - } - - ValueArray3(const ValueArray3& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray3& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; -}; - -template -class ValueArray4 { - public: - ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_)}; - return ValuesIn(array); - } - - ValueArray4(const ValueArray4& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray4& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; -}; - -template -class ValueArray5 { - public: - ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_)}; - return ValuesIn(array); - } - - ValueArray5(const ValueArray5& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray5& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; -}; - -template -class ValueArray6 { - public: - ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_)}; - return ValuesIn(array); - } - - ValueArray6(const ValueArray6& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray6& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; -}; - -template -class ValueArray7 { - public: - ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_)}; - return ValuesIn(array); - } - - ValueArray7(const ValueArray7& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray7& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; -}; - -template -class ValueArray8 { - public: - ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_)}; - return ValuesIn(array); - } - - ValueArray8(const ValueArray8& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray8& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; -}; - -template -class ValueArray9 { - public: - ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_)}; - return ValuesIn(array); - } - - ValueArray9(const ValueArray9& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray9& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; -}; - -template -class ValueArray10 { - public: - ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_)}; - return ValuesIn(array); - } - - ValueArray10(const ValueArray10& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray10& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; -}; - -template -class ValueArray11 { - public: - ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_)}; - return ValuesIn(array); - } - - ValueArray11(const ValueArray11& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray11& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; -}; - -template -class ValueArray12 { - public: - ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_)}; - return ValuesIn(array); - } - - ValueArray12(const ValueArray12& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray12& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; -}; - -template -class ValueArray13 { - public: - ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_)}; - return ValuesIn(array); - } - - ValueArray13(const ValueArray13& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray13& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; -}; - -template -class ValueArray14 { - public: - ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_)}; - return ValuesIn(array); - } - - ValueArray14(const ValueArray14& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray14& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; -}; - -template -class ValueArray15 { - public: - ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_)}; - return ValuesIn(array); - } - - ValueArray15(const ValueArray15& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray15& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; -}; - -template -class ValueArray16 { - public: - ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_)}; - return ValuesIn(array); - } - - ValueArray16(const ValueArray16& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray16& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; -}; - -template -class ValueArray17 { - public: - ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_)}; - return ValuesIn(array); - } - - ValueArray17(const ValueArray17& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray17& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; -}; - -template -class ValueArray18 { - public: - ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_)}; - return ValuesIn(array); - } - - ValueArray18(const ValueArray18& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray18& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; -}; - -template -class ValueArray19 { - public: - ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_)}; - return ValuesIn(array); - } - - ValueArray19(const ValueArray19& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray19& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; -}; - -template -class ValueArray20 { - public: - ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_)}; - return ValuesIn(array); - } - - ValueArray20(const ValueArray20& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray20& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; -}; - -template -class ValueArray21 { - public: - ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_)}; - return ValuesIn(array); - } - - ValueArray21(const ValueArray21& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray21& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; -}; - -template -class ValueArray22 { - public: - ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_)}; - return ValuesIn(array); - } - - ValueArray22(const ValueArray22& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray22& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; -}; - -template -class ValueArray23 { - public: - ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_)}; - return ValuesIn(array); - } - - ValueArray23(const ValueArray23& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray23& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; -}; - -template -class ValueArray24 { - public: - ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_)}; - return ValuesIn(array); - } - - ValueArray24(const ValueArray24& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray24& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; -}; - -template -class ValueArray25 { - public: - ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_)}; - return ValuesIn(array); - } - - ValueArray25(const ValueArray25& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray25& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; -}; - -template -class ValueArray26 { - public: - ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_)}; - return ValuesIn(array); - } - - ValueArray26(const ValueArray26& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray26& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; -}; - -template -class ValueArray27 { - public: - ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_)}; - return ValuesIn(array); - } - - ValueArray27(const ValueArray27& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray27& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; -}; - -template -class ValueArray28 { - public: - ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_)}; - return ValuesIn(array); - } - - ValueArray28(const ValueArray28& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray28& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; -}; - -template -class ValueArray29 { - public: - ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_)}; - return ValuesIn(array); - } - - ValueArray29(const ValueArray29& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray29& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; -}; - -template -class ValueArray30 { - public: - ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_)}; - return ValuesIn(array); - } - - ValueArray30(const ValueArray30& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray30& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; -}; - -template -class ValueArray31 { - public: - ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_)}; - return ValuesIn(array); - } - - ValueArray31(const ValueArray31& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray31& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; -}; - -template -class ValueArray32 { - public: - ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_)}; - return ValuesIn(array); - } - - ValueArray32(const ValueArray32& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray32& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; -}; - -template -class ValueArray33 { - public: - ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_)}; - return ValuesIn(array); - } - - ValueArray33(const ValueArray33& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray33& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; -}; - -template -class ValueArray34 { - public: - ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_)}; - return ValuesIn(array); - } - - ValueArray34(const ValueArray34& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray34& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; -}; - -template -class ValueArray35 { - public: - ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_)}; - return ValuesIn(array); - } - - ValueArray35(const ValueArray35& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray35& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; -}; - -template -class ValueArray36 { - public: - ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_)}; - return ValuesIn(array); - } - - ValueArray36(const ValueArray36& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray36& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; -}; - -template -class ValueArray37 { - public: - ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_)}; - return ValuesIn(array); - } - - ValueArray37(const ValueArray37& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray37& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; -}; - -template -class ValueArray38 { - public: - ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_)}; - return ValuesIn(array); - } - - ValueArray38(const ValueArray38& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray38& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; -}; - -template -class ValueArray39 { - public: - ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_)}; - return ValuesIn(array); - } - - ValueArray39(const ValueArray39& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray39& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; -}; - -template -class ValueArray40 { - public: - ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_)}; - return ValuesIn(array); - } - - ValueArray40(const ValueArray40& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray40& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; -}; - -template -class ValueArray41 { - public: - ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_)}; - return ValuesIn(array); - } - - ValueArray41(const ValueArray41& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray41& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; -}; - -template -class ValueArray42 { - public: - ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_)}; - return ValuesIn(array); - } - - ValueArray42(const ValueArray42& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray42& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; -}; - -template -class ValueArray43 { - public: - ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), - v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_)}; - return ValuesIn(array); - } - - ValueArray43(const ValueArray43& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray43& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; -}; - -template -class ValueArray44 { - public: - ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), - v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), - v43_(v43), v44_(v44) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_)}; - return ValuesIn(array); - } - - ValueArray44(const ValueArray44& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray44& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; -}; - -template -class ValueArray45 { - public: - ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), - v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_)}; - return ValuesIn(array); - } - - ValueArray45(const ValueArray45& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray45& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; -}; - -template -class ValueArray46 { - public: - ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_)}; - return ValuesIn(array); - } - - ValueArray46(const ValueArray46& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray46& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; -}; - -template -class ValueArray47 { - public: - ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), - v47_(v47) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_)}; - return ValuesIn(array); - } - - ValueArray47(const ValueArray47& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), - v47_(other.v47_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray47& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; -}; - -template -class ValueArray48 { - public: - ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), - v46_(v46), v47_(v47), v48_(v48) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_)}; - return ValuesIn(array); - } - - ValueArray48(const ValueArray48& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), - v47_(other.v47_), v48_(other.v48_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray48& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; -}; - -template -class ValueArray49 { - public: - ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, - T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_)}; - return ValuesIn(array); - } - - ValueArray49(const ValueArray49& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), - v47_(other.v47_), v48_(other.v48_), v49_(other.v49_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray49& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; -}; - -template -class ValueArray50 { - public: - ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, - T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_), static_cast(v50_)}; - return ValuesIn(array); - } - - ValueArray50(const ValueArray50& other) : v1_(other.v1_), v2_(other.v2_), - v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), - v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), - v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), - v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), - v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), - v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), - v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), - v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), - v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), - v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), - v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), - v47_(other.v47_), v48_(other.v48_), v49_(other.v49_), v50_(other.v50_) {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray50& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; - const T50 v50_; -}; - -# if GTEST_HAS_COMBINE -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Generates values from the Cartesian product of values produced -// by the argument generators. -// -template -class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator2(const ParamGenerator& g1, - const ParamGenerator& g2) - : g1_(g1), g2_(g2) {} - virtual ~CartesianProductGenerator2() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current2_; - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - linked_ptr current_value_; - }; // class CartesianProductGenerator2::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator2& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; -}; // class CartesianProductGenerator2 - - -template -class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator3(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - virtual ~CartesianProductGenerator3() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current3_; - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - linked_ptr current_value_; - }; // class CartesianProductGenerator3::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator3& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; -}; // class CartesianProductGenerator3 - - -template -class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator4(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - virtual ~CartesianProductGenerator4() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current4_; - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - linked_ptr current_value_; - }; // class CartesianProductGenerator4::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator4& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; -}; // class CartesianProductGenerator4 - - -template -class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator5(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - virtual ~CartesianProductGenerator5() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current5_; - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - linked_ptr current_value_; - }; // class CartesianProductGenerator5::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator5& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; -}; // class CartesianProductGenerator5 - - -template -class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator6(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - virtual ~CartesianProductGenerator6() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current6_; - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - linked_ptr current_value_; - }; // class CartesianProductGenerator6::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator6& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; -}; // class CartesianProductGenerator6 - - -template -class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator7(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - virtual ~CartesianProductGenerator7() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current7_; - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - linked_ptr current_value_; - }; // class CartesianProductGenerator7::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator7& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; -}; // class CartesianProductGenerator7 - - -template -class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator8(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - virtual ~CartesianProductGenerator8() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current8_; - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - linked_ptr current_value_; - }; // class CartesianProductGenerator8::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator8& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; -}; // class CartesianProductGenerator8 - - -template -class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator9(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - virtual ~CartesianProductGenerator9() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current9_; - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - linked_ptr current_value_; - }; // class CartesianProductGenerator9::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator9& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; -}; // class CartesianProductGenerator9 - - -template -class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::testing::tuple > { - public: - typedef ::testing::tuple ParamType; - - CartesianProductGenerator10(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9, - const ParamGenerator& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - virtual ~CartesianProductGenerator10() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end(), g10_, g10_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9, - const ParamGenerator& g10, - const typename ParamGenerator::iterator& current10) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9), - begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current10_; - if (current10_ == end10_) { - current10_ = begin10_; - ++current9_; - } - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_ && - current10_ == typed_other->current10_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_), - begin10_(other.begin10_), - end10_(other.end10_), - current10_(other.current10_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_)); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_ || - current10_ == end10_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - const typename ParamGenerator::iterator begin10_; - const typename ParamGenerator::iterator end10_; - typename ParamGenerator::iterator current10_; - linked_ptr current_value_; - }; // class CartesianProductGenerator10::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator10& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; - const ParamGenerator g10_; -}; // class CartesianProductGenerator10 - - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Helper classes providing Combine() with polymorphic features. They allow -// casting CartesianProductGeneratorN to ParamGenerator if T is -// convertible to U. -// -template -class CartesianProductHolder2 { - public: -CartesianProductHolder2(const Generator1& g1, const Generator2& g2) - : g1_(g1), g2_(g2) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator2( - static_cast >(g1_), - static_cast >(g2_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder2& other); - - const Generator1 g1_; - const Generator2 g2_; -}; // class CartesianProductHolder2 - -template -class CartesianProductHolder3 { - public: -CartesianProductHolder3(const Generator1& g1, const Generator2& g2, - const Generator3& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator3( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder3& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; -}; // class CartesianProductHolder3 - -template -class CartesianProductHolder4 { - public: -CartesianProductHolder4(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator4( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder4& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; -}; // class CartesianProductHolder4 - -template -class CartesianProductHolder5 { - public: -CartesianProductHolder5(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator5( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder5& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; -}; // class CartesianProductHolder5 - -template -class CartesianProductHolder6 { - public: -CartesianProductHolder6(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator6( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder6& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; -}; // class CartesianProductHolder6 - -template -class CartesianProductHolder7 { - public: -CartesianProductHolder7(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator7( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder7& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; -}; // class CartesianProductHolder7 - -template -class CartesianProductHolder8 { - public: -CartesianProductHolder8(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator8( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder8& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; -}; // class CartesianProductHolder8 - -template -class CartesianProductHolder9 { - public: -CartesianProductHolder9(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator9( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder9& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; -}; // class CartesianProductHolder9 - -template -class CartesianProductHolder10 { - public: -CartesianProductHolder10(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9, const Generator10& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - template - operator ParamGenerator< ::testing::tuple >() const { - return ParamGenerator< ::testing::tuple >( - new CartesianProductGenerator10( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_), - static_cast >(g10_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder10& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; - const Generator10 g10_; -}; // class CartesianProductHolder10 - -# endif // GTEST_HAS_COMBINE - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h.pump b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h.pump deleted file mode 100644 index 30dffe43c3..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util-generated.h.pump +++ /dev/null @@ -1,282 +0,0 @@ -$$ -*- mode: c++; -*- -$var n = 50 $$ Maximum length of Values arguments we want to support. -$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Type and function utilities for implementing parameterized tests. -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently Google Test supports at most $n arguments in Values, -// and at most $maxtuple arguments in Combine. Please contact -// googletestframework@googlegroups.com if you need more. -// Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tuple which is -// currently set at $maxtuple. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -#include "gtest/internal/gtest-param-util.h" -#include "gtest/internal/gtest-port.h" - -namespace testing { - -// Forward declarations of ValuesIn(), which is implemented in -// include/gtest/gtest-param-test.h. -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end); - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]); - -template -internal::ParamGenerator ValuesIn( - const Container& container); - -namespace internal { - -// Used in the Values() function to provide polymorphic capabilities. -$range i 1..n -$for i [[ -$range j 1..i - -template <$for j, [[typename T$j]]> -class ValueArray$i { - public: - $if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} - - template - operator ParamGenerator() const { - const T array[] = {$for j, [[static_cast(v$(j)_)]]}; - return ValuesIn(array); - } - - ValueArray$i(const ValueArray$i& other) : $for j, [[v$(j)_(other.v$(j)_)]] {} - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray$i& other); - -$for j [[ - - const T$j v$(j)_; -]] - -}; - -]] - -# if GTEST_HAS_COMBINE -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Generates values from the Cartesian product of values produced -// by the argument generators. -// -$range i 2..maxtuple -$for i [[ -$range j 1..i -$range k 2..i - -template <$for j, [[typename T$j]]> -class CartesianProductGenerator$i - : public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > { - public: - typedef ::testing::tuple<$for j, [[T$j]]> ParamType; - - CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) - : $for j, [[g$(j)_(g$j)]] {} - virtual ~CartesianProductGenerator$i() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, $for j, [[ - - const ParamGenerator& g$j, - const typename ParamGenerator::iterator& current$(j)]]) - : base_(base), -$for j, [[ - - begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j) -]] { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current$(i)_; - -$for k [[ - if (current$(i+2-k)_ == end$(i+2-k)_) { - current$(i+2-k)_ = begin$(i+2-k)_; - ++current$(i+2-k-1)_; - } - -]] - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return current_value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ($for j && [[ - - current$(j)_ == typed_other->current$(j)_ -]]); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), $for j, [[ - - begin$(j)_(other.begin$(j)_), - end$(j)_(other.end$(j)_), - current$(j)_(other.current$(j)_) -]] { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_.reset(new ParamType($for j, [[*current$(j)_]])); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return -$for j || [[ - - current$(j)_ == end$(j)_ -]]; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. -$for j [[ - - const typename ParamGenerator::iterator begin$(j)_; - const typename ParamGenerator::iterator end$(j)_; - typename ParamGenerator::iterator current$(j)_; -]] - - linked_ptr current_value_; - }; // class CartesianProductGenerator$i::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator$i& other); - - -$for j [[ - const ParamGenerator g$(j)_; - -]] -}; // class CartesianProductGenerator$i - - -]] - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Helper classes providing Combine() with polymorphic features. They allow -// casting CartesianProductGeneratorN to ParamGenerator if T is -// convertible to U. -// -$range i 2..maxtuple -$for i [[ -$range j 1..i - -template <$for j, [[class Generator$j]]> -class CartesianProductHolder$i { - public: -CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) - : $for j, [[g$(j)_(g$j)]] {} - template <$for j, [[typename T$j]]> - operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const { - return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( - new CartesianProductGenerator$i<$for j, [[T$j]]>( -$for j,[[ - - static_cast >(g$(j)_) -]])); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder$i& other); - - -$for j [[ - const Generator$j g$(j)_; - -]] -}; // class CartesianProductHolder$i - -]] - -# endif // GTEST_HAS_COMBINE - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util.h index d64f620c4c..0d8fc71ce2 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-param-util.h @@ -27,7 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Type and function utilities for implementing parameterized tests. // GOOGLETEST_CM0001 DO NOT DELETE @@ -37,25 +36,27 @@ #include +#include #include +#include #include +#include +#include #include #include #include "gtest/internal/gtest-internal.h" -#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" +#include "gtest/gtest-test-part.h" namespace testing { - // Input to a parameterized test name generator, describing a test parameter. // Consists of the parameter value and the integer parameter index. template struct TestParamInfo { - TestParamInfo(const ParamType& a_param, size_t an_index) : - param(a_param), - index(an_index) {} + TestParamInfo(const ParamType &a_param, size_t an_index) + : param(a_param), index(an_index) {} ParamType param; size_t index; }; @@ -64,7 +65,7 @@ struct TestParamInfo { // testing::PrintToString. struct PrintToStringParamName { template - std::string operator()(const TestParamInfo& info) const { + std::string operator()(const TestParamInfo &info) const { return PrintToString(info.param); } }; @@ -72,16 +73,19 @@ struct PrintToStringParamName { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// +// Utility Functions + // Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when +// fixture class for the same test suite. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - CodeLocation code_location); +GTEST_API_ void ReportInvalidTestSuiteType(const char *test_suite_name, + CodeLocation code_location); -template class ParamGeneratorInterface; -template class ParamGenerator; +template +class ParamGeneratorInterface; +template +class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. @@ -92,7 +96,7 @@ class ParamIteratorInterface { // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. - virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + virtual const ParamGeneratorInterface *BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to @@ -100,16 +104,16 @@ class ParamIteratorInterface { virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. - virtual ParamIteratorInterface* Clone() const = 0; + virtual ParamIteratorInterface *Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). - virtual const T* Current() const = 0; + virtual const T *Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). - virtual bool Equals(const ParamIteratorInterface& other) const = 0; + virtual bool Equals(const ParamIteratorInterface &other) const = 0; }; // Class iterating over elements provided by an implementation of @@ -119,41 +123,40 @@ template class ParamIterator { public: typedef T value_type; - typedef const T& reference; + typedef const T &reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. - ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} - ParamIterator& operator=(const ParamIterator& other) { - if (this != &other) - impl_.reset(other.impl_->Clone()); + ParamIterator(const ParamIterator &other) : impl_(other.impl_->Clone()) {} + ParamIterator &operator=(const ParamIterator &other) { + if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } - const T& operator*() const { return *impl_->Current(); } - const T* operator->() const { return impl_->Current(); } + const T &operator*() const { return *impl_->Current(); } + const T *operator->() const { return impl_->Current(); } // Prefix version of operator++. - ParamIterator& operator++() { + ParamIterator &operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { - ParamIteratorInterface* clone = impl_->Clone(); + ParamIteratorInterface *clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } - bool operator==(const ParamIterator& other) const { + bool operator==(const ParamIterator &other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } - bool operator!=(const ParamIterator& other) const { + bool operator!=(const ParamIterator &other) const { return !(*this == other); } private: friend class ParamGenerator; - explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; + explicit ParamIterator(ParamIteratorInterface *impl) : impl_(impl) {} + std::unique_ptr> impl_; }; // ParamGeneratorInterface is the binary interface to access generators @@ -166,8 +169,8 @@ class ParamGeneratorInterface { virtual ~ParamGeneratorInterface() {} // Generator interface definition - virtual ParamIteratorInterface* Begin() const = 0; - virtual ParamIteratorInterface* End() const = 0; + virtual ParamIteratorInterface *Begin() const = 0; + virtual ParamIteratorInterface *End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax @@ -175,15 +178,15 @@ class ParamGeneratorInterface { // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. -template +template class ParamGenerator { public: typedef ParamIterator iterator; - explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} - ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + explicit ParamGenerator(ParamGeneratorInterface *impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator &other) : impl_(other.impl_) {} - ParamGenerator& operator=(const ParamGenerator& other) { + ParamGenerator &operator=(const ParamGenerator &other) { impl_ = other.impl_; return *this; } @@ -192,7 +195,7 @@ class ParamGenerator { iterator end() const { return iterator(impl_->End()); } private: - linked_ptr > impl_; + std::shared_ptr> impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -203,37 +206,37 @@ template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) - : begin_(begin), end_(end), - step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} + : begin_(begin), end_(end), step_(step), + end_index_(CalculateEndIndex(begin, end, step)) {} + ~RangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface *Begin() const override { return new Iterator(this, begin_, 0, step_); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface *End() const override { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: - Iterator(const ParamGeneratorInterface* base, T value, int index, + Iterator(const ParamGeneratorInterface *base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface *BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { value_ = static_cast(value_ + step_); index_++; } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface *Clone() const override { return new Iterator(*this); } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { + const T *Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface &other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -245,31 +248,28 @@ class RangeGenerator : public ParamGeneratorInterface { } private: - Iterator(const Iterator& other) - : ParamIteratorInterface(), - base_(other.base_), value_(other.value_), index_(other.index_), - step_(other.step_) {} + Iterator(const Iterator &other) + : ParamIteratorInterface(), base_(other.base_), value_(other.value_), + index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. - void operator=(const Iterator& other); + void operator=(const Iterator &other); - const ParamGeneratorInterface* const base_; + const ParamGeneratorInterface *const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator - static int CalculateEndIndex(const T& begin, - const T& end, - const IncrementT& step) { + static int CalculateEndIndex(const T &begin, const T &end, + const IncrementT &step) { int end_index = 0; - for (T i = begin; i < end; i = static_cast(i + step)) - end_index++; + for (T i = begin; i < end; i = static_cast(i + step)) end_index++; return end_index; } // No implementation - assignment is unsupported. - void operator=(const RangeGenerator& other); + void operator=(const RangeGenerator &other); const T begin_; const T end_; @@ -279,7 +279,6 @@ class RangeGenerator : public ParamGeneratorInterface { const int end_index_; }; // class RangeGenerator - // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator @@ -290,12 +289,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} + ~ValuesInIteratorRangeGenerator() override {} - virtual ParamIteratorInterface* Begin() const { + ParamIteratorInterface *Begin() const override { return new Iterator(this, container_.begin()); } - virtual ParamIteratorInterface* End() const { + ParamIteratorInterface *End() const override { return new Iterator(this, container_.end()); } @@ -304,19 +303,19 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { class Iterator : public ParamIteratorInterface { public: - Iterator(const ParamGeneratorInterface* base, + Iterator(const ParamGeneratorInterface *base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface* BaseGenerator() const { + const ParamGeneratorInterface *BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { ++iterator_; value_.reset(); } - virtual ParamIteratorInterface* Clone() const { + ParamIteratorInterface *Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ @@ -326,41 +325,39 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); + const T *Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); return value_.get(); } - virtual bool Equals(const ParamIteratorInterface& other) const { + bool Equals(const ParamIteratorInterface &other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == - CheckedDowncastToActualType(&other)->iterator_; + CheckedDowncastToActualType(&other)->iterator_; } private: - Iterator(const Iterator& other) - // The explicit constructor call suppresses a false warning - // emitted by gcc when supplied with the -Wextra option. - : ParamIteratorInterface(), - base_(other.base_), + Iterator(const Iterator &other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} - const ParamGeneratorInterface* const base_; + const ParamGeneratorInterface *const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, + // Use of std::unique_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; + mutable std::unique_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. - void operator=(const ValuesInIteratorRangeGenerator& other); + void operator=(const ValuesInIteratorRangeGenerator &other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator @@ -370,31 +367,18 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { // Default parameterized test name generator, returns a string containing the // integer test parameter index. template -std::string DefaultParamName(const TestParamInfo& info) { +std::string DefaultParamName(const TestParamInfo &info) { Message name_stream; name_stream << info.index; return name_stream.GetString(); } -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Parameterized test name overload helpers, which help the -// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized -// test name generator and user param name generator. -template -ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) { - return func; -} - -template -struct ParamNameGenFunc { - typedef std::string Type(const TestParamInfo&); -}; - -template -typename ParamNameGenFunc::Type *GetParamNameGen() { - return DefaultParamName; +template +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); } +template +void TestNotEmpty(const T &) {} // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // @@ -404,9 +388,9 @@ template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; - explicit ParameterizedTestFactory(ParamType parameter) : - parameter_(parameter) {} - virtual Test* CreateTest() { + explicit ParameterizedTestFactory(ParamType parameter) + : parameter_(parameter) {} + Test *CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } @@ -426,7 +410,7 @@ class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; + virtual TestFactoryBase *CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -434,19 +418,19 @@ class TestMetaFactoryBase { // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call +// into that method twice. But ParameterizedTestSuiteInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. -template +template class TestMetaFactory - : public TestMetaFactoryBase { + : public TestMetaFactoryBase { public: - typedef typename TestCase::ParamType ParamType; + using ParamType = typename TestSuite::ParamType; TestMetaFactory() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); + TestFactoryBase *CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory(parameter); } private: @@ -455,267 +439,481 @@ class TestMetaFactory // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase // accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations // and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects // and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { +class ParameterizedTestSuiteInfoBase { public: - virtual ~ParameterizedTestCaseInfoBase() {} + virtual ~ParameterizedTestSuiteInfoBase() {} - // Base part of test case name for display purposes. - virtual const std::string& GetTestCaseName() const = 0; + // Base part of test suite name for display purposes. + virtual const std::string &GetTestSuiteName() const = 0; // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; + virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. virtual void RegisterTests() = 0; protected: - ParameterizedTestCaseInfoBase() {} + ParameterizedTestSuiteInfoBase() {} private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all +// Report a the name of a test_suit as safe to ignore +// as the side effect of construction of this type. +struct MarkAsIgnored { + explicit MarkAsIgnored(const char *test_suite); +}; + +GTEST_API_ void InsertSyntheticTestCase(const std::string &name, + CodeLocation location, bool has_test_p); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all // generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { +template +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); - typedef typename ParamNameGenFunc::Type ParamNameGeneratorFunc; + using ParamNameGeneratorFunc = std::string(const TestParamInfo &); - explicit ParameterizedTestCaseInfo( - const char* name, CodeLocation code_location) - : test_case_name_(name), code_location_(code_location) {} + explicit ParameterizedTestSuiteInfo(const char *name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const std::string& GetTestCaseName() const { return test_case_name_; } + const std::string &GetTestSuiteName() const override { + return test_suite_name_; + } // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation + // test_suite_name is the base name of the test suite (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, - TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); + // test suite base name and DoBar is test base name. + void AddTestPattern(const char *test_suite_name, const char *test_base_name, + TestMetaFactoryBase *meta_factory) { + tests_.push_back(std::shared_ptr( + new TestInfo(test_suite_name, test_base_name, meta_factory))); } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const std::string& instantiation_name, - GeneratorCreationFunc* func, - ParamNameGeneratorFunc* name_func, - const char* file, int line) { + int AddTestSuiteInstantiation(const std::string &instantiation_name, + GeneratorCreationFunc *func, + ParamNameGeneratorFunc *name_func, + const char *file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { + // UnitTest class invokes this method to register tests in this test suite + // right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { + bool generated_instantiations = false; + for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; + std::shared_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = - instantiations_.begin(); gen_it != instantiations_.end(); - ++gen_it) { - const std::string& instantiation_name = gen_it->name; + instantiations_.begin(); + gen_it != instantiations_.end(); ++gen_it) { + const std::string &instantiation_name = gen_it->name; ParamGenerator generator((*gen_it->generator)()); - ParamNameGeneratorFunc* name_func = gen_it->name_func; - const char* file = gen_it->file; + ParamNameGeneratorFunc *name_func = gen_it->name_func; + const char *file = gen_it->file; int line = gen_it->line; - std::string test_case_name; - if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; + std::string test_suite_name; + if (!instantiation_name.empty()) + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; size_t i = 0; std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { + generated_instantiations = true; + Message test_name_stream; - std::string param_name = name_func( - TestParamInfo(*param_it, i)); + std::string param_name = + name_func(TestParamInfo(*param_it, i)); GTEST_CHECK_(IsValidParamName(param_name)) << "Parameterized test name '" << param_name - << "' is invalid, in " << file - << " line " << line << std::endl; + << "' is invalid, in " << file << " line " << line << std::endl; GTEST_CHECK_(test_param_names.count(param_name) == 0) - << "Duplicate parameterized test name '" << param_name - << "', in " << file << " line " << line << std::endl; + << "Duplicate parameterized test name '" << param_name << "', in " + << file << " line " << line << std::endl; test_param_names.insert(param_name); - test_name_stream << test_info->test_base_name << "/" << param_name; + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - code_location_, - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), code_location_, + GetTestSuiteTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver::GetTearDownCaseOrSuite(file, line), test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it - } // for gen_it - } // for test_it + } // for gen_it + } // for test_it + + if (!generated_instantiations) { + // There are no generaotrs, or they all generate nothing ... + InsertSyntheticTestCase(GetTestSuiteName(), code_location_, + !tests_.empty()); + } } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} + TestInfo(const char *a_test_suite_base_name, const char *a_test_base_name, + TestMetaFactoryBase *a_test_meta_factory) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} - const std::string test_case_base_name; + const std::string test_suite_base_name; const std::string test_base_name; - const scoped_ptr > test_meta_factory; + const std::unique_ptr> test_meta_factory; }; - typedef ::std::vector > TestInfoContainer; - // Records data received from INSTANTIATE_TEST_CASE_P macros: + using TestInfoContainer = ::std::vector>; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: // struct InstantiationInfo { - InstantiationInfo(const std::string &name_in, - GeneratorCreationFunc* generator_in, - ParamNameGeneratorFunc* name_func_in, - const char* file_in, - int line_in) - : name(name_in), - generator(generator_in), - name_func(name_func_in), - file(file_in), - line(line_in) {} + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc *generator_in, + ParamNameGeneratorFunc *name_func_in, const char *file_in, + int line_in) + : name(name_in), generator(generator_in), name_func(name_func_in), + file(file_in), line(line_in) {} - std::string name; - GeneratorCreationFunc* generator; - ParamNameGeneratorFunc* name_func; - const char* file; - int line; + std::string name; + GeneratorCreationFunc *generator; + ParamNameGeneratorFunc *name_func; + const char *file; + int line; }; typedef ::std::vector InstantiationContainer; - static bool IsValidParamName(const std::string& name) { + static bool IsValidParamName(const std::string &name) { // Check for empty string - if (name.empty()) - return false; + if (name.empty()) return false; // Check for invalid characters for (std::string::size_type index = 0; index < name.size(); ++index) { - if (!isalnum(name[index]) && name[index] != '_') - return false; + if (!isalnum(name[index]) && name[index] != '_') return false; } return true; } - const std::string test_case_name_; + const std::string test_suite_name_; CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto &test_suite_info : test_suite_infos_) { + delete test_suite_info; } } // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - CodeLocation code_location) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // tests and instantiations of a particular test suite. + template + ParameterizedTestSuiteInfo *GetTestSuitePatternHolder( + const char *test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo *typed_test_info = nullptr; + for (auto &test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, code_location); + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); + ParameterizedTestSuiteInfo>(test_suite_info); } break; } } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo( - test_case_name, code_location); - test_case_infos_.push_back(typed_test_info); + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); + for (auto &test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); } } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template + ParameterizedTestCaseInfo *GetTestCasePatternHolder( + const char *test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + private: + using TestSuiteInfoContainer = + ::std::vector; + + TestSuiteInfoContainer test_suite_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); +}; + +// Keep track of what type-parameterized test suite are defined and +// where as well as which are intatiated. This allows susequently +// identifying suits that are defined but never used. +class TypeParameterizedTestSuiteRegistry { + public: + // Add a suite definition + void RegisterTestSuite(const char *test_suite_name, + CodeLocation code_location); + + // Add an instantiation of a suit. + void RegisterInstantiation(const char *test_suite_name); + + // For each suit repored as defined but not reported as instantiation, + // emit a test that reports that fact (configurably, as an error). + void CheckForInstantiations(); + + private: + struct TypeParameterizedTestSuiteInfo { + explicit TypeParameterizedTestSuiteInfo(CodeLocation c) + : code_location(c), instantiated(false) {} + + CodeLocation code_location; + bool instantiated; + }; + + std::map suites_; +}; + +} // namespace internal + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator ValuesIn( + const Container &container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +template +class ValueArray { + public: + ValueArray(Ts... v) : v_{ std::move(v)... } {} + + template + operator ParamGenerator() const { // NOLINT + return ValuesIn(MakeVector(MakeIndexSequence())); + } private: - typedef ::std::vector TestCaseInfoContainer; + template + std::vector MakeVector(IndexSequence) const { + return std::vector{ static_cast(v_.template Get())... }; + } - TestCaseInfoContainer test_case_infos_; + FlatTuple v_; +}; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +template +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple> { + public: + typedef ::std::tuple ParamType; + + CartesianProductGenerator(const std::tuple...> &g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface *Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface *End() const override { + return new Iterator(this, generators_, true); + } + + private: + template + class IteratorImpl; + template + class IteratorImpl> + : public ParamIteratorInterface { + public: + IteratorImpl(const ParamGeneratorInterface *base, + const std::tuple...> &generators, + bool is_end) + : base_(base), begin_(std::get(generators).begin()...), + end_(std::get(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface *BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd(); + ComputeCurrentValue(); + } + ParamIteratorInterface *Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType *Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface &other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl *typed_other = + CheckedDowncastToActualType(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { (same = same && + std::get(current_) == + std::get(typed_other->current_))... }; + (void)dummy; + return same; + } + + private: + template + void AdvanceIfEnd() { + if (std::get(current_) != std::get(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get(current_) = std::get(begin_); + ++std::get(current_); + AdvanceIfEnd(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared(*std::get(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { (at_end = at_end || std::get(current_) == + std::get(end_))... }; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface *const base_; + std::tuple::iterator...> begin_; + std::tuple::iterator...> end_; + std::tuple::iterator...> current_; + std::shared_ptr current_value_; + }; + + using Iterator = IteratorImpl::type>; + + std::tuple...> generators_; +}; + +template +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen &... g) : generators_(g...) {} + template + operator ParamGenerator<::std::tuple>() const { + return ParamGenerator<::std::tuple>( + new CartesianProductGenerator(generators_)); + } + + private: + std::tuple generators_; }; } // namespace internal diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port-arch.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port-arch.h index f83700e06d..f803a19be3 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port-arch.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port-arch.h @@ -37,64 +37,75 @@ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 +#define GTEST_OS_CYGWIN 1 +#elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +#define GTEST_OS_WINDOWS_MINGW 1 +#define GTEST_OS_WINDOWS 1 #elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# elif defined(WINAPI_FAMILY) -# include -# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -# define GTEST_OS_WINDOWS_DESKTOP 1 -# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) -# define GTEST_OS_WINDOWS_PHONE 1 -# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) -# define GTEST_OS_WINDOWS_RT 1 -# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) -# define GTEST_OS_WINDOWS_PHONE 1 -# define GTEST_OS_WINDOWS_TV_TITLE 1 -# else - // WINAPI_FAMILY defined but no known partition matched. - // Default to desktop. -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE +#define GTEST_OS_WINDOWS 1 +#ifdef _WIN32_WCE +#define GTEST_OS_WINDOWS_MOBILE 1 +#elif defined(WINAPI_FAMILY) +#include +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define GTEST_OS_WINDOWS_DESKTOP 1 +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +#define GTEST_OS_WINDOWS_PHONE 1 +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define GTEST_OS_WINDOWS_RT 1 +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +#define GTEST_OS_WINDOWS_PHONE 1 +#define GTEST_OS_WINDOWS_TV_TITLE 1 +#else +// WINAPI_FAMILY defined but no known partition matched. +// Default to desktop. +#define GTEST_OS_WINDOWS_DESKTOP 1 +#endif +#else +#define GTEST_OS_WINDOWS_DESKTOP 1 +#endif // _WIN32_WCE +#elif defined __OS2__ +#define GTEST_OS_OS2 1 #elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# endif +#define GTEST_OS_MAC 1 +#if TARGET_OS_IPHONE +#define GTEST_OS_IOS 1 +#endif +#elif defined __DragonFly__ +#define GTEST_OS_DRAGONFLY 1 #elif defined __FreeBSD__ -# define GTEST_OS_FREEBSD 1 +#define GTEST_OS_FREEBSD 1 #elif defined __Fuchsia__ -# define GTEST_OS_FUCHSIA 1 +#define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +#define GTEST_OS_GNU_KFREEBSD 1 #elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif +#define GTEST_OS_LINUX 1 +#if defined __ANDROID__ +#define GTEST_OS_LINUX_ANDROID 1 +#endif #elif defined __MVS__ -# define GTEST_OS_ZOS 1 +#define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 +#define GTEST_OS_SOLARIS 1 #elif defined(_AIX) -# define GTEST_OS_AIX 1 +#define GTEST_OS_AIX 1 #elif defined(__hpux) -# define GTEST_OS_HPUX 1 +#define GTEST_OS_HPUX 1 #elif defined __native_client__ -# define GTEST_OS_NACL 1 +#define GTEST_OS_NACL 1 #elif defined __NetBSD__ -# define GTEST_OS_NETBSD 1 +#define GTEST_OS_NETBSD 1 #elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 +#define GTEST_OS_OPENBSD 1 #elif defined __QNX__ -# define GTEST_OS_QNX 1 +#define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 +#elif defined ESP8266 +#define GTEST_OS_ESP8266 1 +#elif defined ESP32 +#define GTEST_OS_ESP32 1 #endif // __CYGWIN__ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port.h index 786497d854..083da569fe 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-port.h @@ -72,10 +72,6 @@ // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring -// is/isn't available // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that @@ -85,8 +81,6 @@ // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". @@ -94,12 +88,6 @@ // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as @@ -125,8 +113,11 @@ // // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD // GTEST_OS_FREEBSD - FreeBSD // GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android @@ -135,9 +126,9 @@ // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW @@ -146,7 +137,7 @@ // GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify @@ -172,8 +163,6 @@ // EXPECT_DEATH(DoSomethingDeadly()); // #endif // -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests @@ -184,7 +173,6 @@ // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above RE\b(s) are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // Misc public macros // ------------------ @@ -202,31 +190,23 @@ // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. -// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_ASSIGN_ - disables copy operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_DISALLOW_MOVE_ASSIGN_ - disables move operator=. +// GTEST_DISALLOW_MOVE_AND_ASSIGN_ - disables move ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. -// -// C++11 feature wrappers: -// -// testing::internal::forward - portability wrapper for std::forward. -// testing::internal::move - portability wrapper for std::move. +// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or +// Matcher +// specializations. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. -// // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like platforms @@ -248,8 +228,7 @@ // // Integer types: // TypeWithSize - maps an integer to a int type. -// Int32, UInt32, Int64, UInt64, TimeInMillis -// - integers of known sizes. +// TimeInMillis - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: @@ -260,54 +239,60 @@ // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. -// Int32FromGTestEnv() - parses an Int32 environment variable. +// Int32FromGTestEnv() - parses an int32_t environment variable. // StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning #include // for isspace, etc #include // for ptrdiff_t -#include #include +#include #include +#include +#include +#include + #ifndef _WIN32_WCE -# include -# include +#include +#include #endif // !_WIN32_WCE #if defined __APPLE__ -# include -# include +#include +#include #endif -// Brings in the definition of HAS_GLOBAL_STRING. This must be done -// BEFORE we test HAS_GLOBAL_STRING. -#include // NOLINT -#include // NOLINT #include // NOLINT -#include // NOLINT -#include +#include +#include // NOLINT +#include #include // NOLINT -#include "gtest/internal/gtest-port-arch.h" #include "gtest/internal/custom/gtest-port.h" +#include "gtest/internal/gtest-port-arch.h" #if !defined(GTEST_DEV_EMAIL_) -# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -# define GTEST_FLAG_PREFIX_ "gtest_" -# define GTEST_FLAG_PREFIX_DASH_ "gtest-" -# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -# define GTEST_NAME_ "Google Test" -# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" #endif // !defined(GTEST_DEV_EMAIL_) #if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) -# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" #endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. -# define GTEST_GCC_VER_ \ - (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#define GTEST_GCC_VER_ \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Macros for disabling Microsoft Visual C++ warnings. @@ -315,116 +300,38 @@ // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() -#if _MSC_VER >= 1400 -# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ - __pragma(warning(push)) \ - __pragma(warning(disable: warnings)) -# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ - __pragma(warning(pop)) +#if defined(_MSC_VER) +#define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) __pragma(warning(disable : warnings)) +#define GTEST_DISABLE_MSC_WARNINGS_POP_() __pragma(warning(pop)) #else -// Older versions of MSVC don't have __pragma. -# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) -# define GTEST_DISABLE_MSC_WARNINGS_POP_() +// Not all compilers are MSVC +#define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +#define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Clang on Windows does not understand MSVC's pragma warning. // We need clang-specific way to disable function deprecation warning. #ifdef __clang__ -# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") -#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ - _Pragma("clang diagnostic pop") +#define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() _Pragma("clang diagnostic pop") #else -# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) -# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ - GTEST_DISABLE_MSC_WARNINGS_POP_() -#endif - -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L || _MSC_VER >= 1900 -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif -#endif - -// Distinct from C++11 language support, some environments don't provide -// proper C++11 library support. Notably, it's possible to build in -// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++ -// with no C++11 support. -// -// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__ -// 20110325, but maintenance releases in the 4.4 and 4.5 series followed -// this date, so check for those versions by their date stamps. -// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning -#if GTEST_LANG_CXX11 && \ - (!defined(__GLIBCXX__) || ( \ - __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \ - /* Blacklist of patch releases of older branches: */ \ - __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \ - __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \ - __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \ - __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */ -# define GTEST_STDLIB_CXX11 1 -#endif - -// Only use C++11 library features if the library provides them. -#if GTEST_STDLIB_CXX11 -# define GTEST_HAS_STD_BEGIN_AND_END_ 1 -# define GTEST_HAS_STD_FORWARD_LIST_ 1 -# if !defined(_MSC_VER) || (_MSC_FULL_VER >= 190023824) -// works only with VS2015U2 and better -# define GTEST_HAS_STD_FUNCTION_ 1 -# endif -# define GTEST_HAS_STD_INITIALIZER_LIST_ 1 -# define GTEST_HAS_STD_MOVE_ 1 -# define GTEST_HAS_STD_UNIQUE_PTR_ 1 -# define GTEST_HAS_STD_SHARED_PTR_ 1 -# define GTEST_HAS_UNORDERED_MAP_ 1 -# define GTEST_HAS_UNORDERED_SET_ 1 -#endif - -// C++11 specifies that provides std::tuple. -// Some platforms still might not have it, however. -#if GTEST_LANG_CXX11 -# define GTEST_HAS_STD_TUPLE_ 1 -# if defined(__clang__) -// Inspired by -// https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros -# if defined(__has_include) && !__has_include() -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(_MSC_VER) -// Inspired by boost/config/stdlib/dinkumware.hpp -# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520 -# undef GTEST_HAS_STD_TUPLE_ -# endif -# elif defined(__GLIBCXX__) -// Inspired by boost/config/stdlib/libstdcpp3.hpp, -// http://gcc.gnu.org/gcc-4.2/changes.html and -// https://web.archive.org/web/20140227044429/gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x -# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) -# undef GTEST_HAS_STD_TUPLE_ -# endif -# endif +#define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if GTEST_OS_WINDOWS -# if !GTEST_OS_WINDOWS_MOBILE -# include -# include -# endif +#if !GTEST_OS_WINDOWS_MOBILE +#include +#include +#endif // In order to avoid having to include , use forward declaration #if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) // MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two @@ -440,23 +347,24 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. -# include -# include +#include +#include #endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. -# include // NOLINT +#include // NOLINT #endif -// Defines this to true iff Google Test can use POSIX regular expressions. +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. #ifndef GTEST_HAS_POSIX_RE -# if GTEST_OS_LINUX_ANDROID +#if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. -# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) -# else -# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) -# endif +#define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) +#else +#define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +#endif #endif #if GTEST_USES_PCRE @@ -468,164 +376,143 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . -# include // NOLINT +#include // NOLINT -# define GTEST_USES_POSIX_RE 1 +#define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. -# define GTEST_USES_SIMPLE_RE 1 +#define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. -# define GTEST_USES_SIMPLE_RE 1 +#define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_USES_PCRE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) && defined(_CPPUNWIND) -// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__BORLANDC__) +#if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__BORLANDC__) // C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. -# ifndef _HAS_EXCEPTIONS -# define _HAS_EXCEPTIONS 1 -# endif // _HAS_EXCEPTIONS -# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS -# elif defined(__clang__) -// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714, -// but iff cleanups are enabled after that. In Obj-C++ files, there can be -// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions -// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++ -// exceptions starting at clang r206352, but which checked for cleanups prior to -// that. To reliably check for C++ exception availability with clang, check for +#ifndef _HAS_EXCEPTIONS +#define _HAS_EXCEPTIONS 1 +#endif // _HAS_EXCEPTIONS +#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +#elif defined(__clang__) +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for // __EXCEPTIONS && __has_feature(cxx_exceptions). -# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) -# elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__SUNPRO_CC) +#define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) +#elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__HP_aCC) +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. -# define GTEST_HAS_EXCEPTIONS 1 -# else +#define GTEST_HAS_EXCEPTIONS 1 +#else // For other compilers, we assume exceptions are disabled to be // conservative. -# define GTEST_HAS_EXCEPTIONS 0 -# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#define GTEST_HAS_EXCEPTIONS 0 +#endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS -#if !defined(GTEST_HAS_STD_STRING) -// Even though we don't use this macro any longer, we keep it in case -// some clients still depend on it. -# define GTEST_HAS_STD_STRING 1 -#elif !GTEST_HAS_STD_STRING -// The user told us that ::std::string isn't available. -# error "::std::string isn't available." -#endif // !defined(GTEST_HAS_STD_STRING) - -#ifndef GTEST_HAS_GLOBAL_STRING -# define GTEST_HAS_GLOBAL_STRING 0 -#endif // GTEST_HAS_GLOBAL_STRING - #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// FIXME: uses autoconf to detect whether ::std::wstring -// is available. - // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266)) #endif // GTEST_HAS_STD_WSTRING -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. -# ifdef _MSC_VER +#ifdef _MSC_VER -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +#elif defined(__GNUC__) -# ifdef __GXX_RTTI +#ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ - !defined(__EXCEPTIONS) -# define GTEST_HAS_RTTI 0 -# else -# define GTEST_HAS_RTTI 1 -# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS -# else -# define GTEST_HAS_RTTI 0 -# endif // __GXX_RTTI +#if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && !defined(__EXCEPTIONS) +#define GTEST_HAS_RTTI 0 +#else +#define GTEST_HAS_RTTI 1 +#endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS +#else +#define GTEST_HAS_RTTI 0 +#endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. -# elif defined(__clang__) +#elif defined(__clang__) -# define GTEST_HAS_RTTI __has_feature(cxx_rtti) +#define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. -# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) -# ifdef __RTTI_ALL__ -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif +#ifdef __RTTI_ALL__ +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif -# else +#else // For all other compilers, we assume RTTI is enabled. -# define GTEST_HAS_RTTI 1 +#define GTEST_HAS_RTTI 1 -# endif // _MSC_VER +#endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI -# include +#include #endif // Determines whether Google Test can use the pthreads library. @@ -635,150 +522,22 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -#define GTEST_HAS_PTHREAD \ - (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ - GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. -# include // NOLINT +#include // NOLINT // For timespec and nanosleep, used below. -# include // NOLINT +#include // NOLINT #endif -// Determines if hash_map/hash_set are available. -// Only used for testing against those containers. -#if !defined(GTEST_HAS_HASH_MAP_) -# if defined(_MSC_VER) && (_MSC_VER < 1900) -# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. -# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. -# endif // _MSC_VER -#endif // !defined(GTEST_HAS_HASH_MAP_) - -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither or . -# define GTEST_HAS_TR1_TUPLE 0 -# elif defined(_MSC_VER) && (_MSC_VER >= 1910) -// Prevent `warning C4996: 'std::tr1': warning STL4002: -// The non-Standard std::tr1 namespace and TR1-only machinery -// are deprecated and will be REMOVED.` -# define GTEST_HAS_TR1_TUPLE 0 -# elif GTEST_LANG_CXX11 && defined(_LIBCPP_VERSION) -// libc++ doesn't support TR1. -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// We use our own tuple implementation on Symbian. -# if GTEST_OS_SYMBIAN -# define GTEST_USE_OWN_TR1_TUPLE 1 -# else -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) \ - || (_MSC_VER >= 1600 && _MSC_VER < 1900) -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif -# endif // GTEST_OS_SYMBIAN -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation we make it gtest-port.h's responsibility -// to #include the header implementing tuple. -#if GTEST_HAS_STD_TUPLE_ -# include // IWYU pragma: export -# define GTEST_TUPLE_NAMESPACE_ ::std -#endif // GTEST_HAS_STD_TUPLE_ - -// We include tr1::tuple even if std::tuple is available to define printers for -// them. -#if GTEST_HAS_TR1_TUPLE -# ifndef GTEST_TUPLE_NAMESPACE_ -# define GTEST_TUPLE_NAMESPACE_ ::std::tr1 -# endif // GTEST_TUPLE_NAMESPACE_ - -# if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include // IWYU pragma: export // NOLINT - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is used to prevent -// from being included. -# define _TR1_FUNCTIONAL 1 -# include -# undef _TR1_FUNCTIONAL // Allows the user to #include - // if they choose to. -# else -# include // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -// VS 2010 now has tr1 support. -# elif _MSC_VER >= 1600 -# include // IWYU pragma: export // NOLINT - -# else // GTEST_USE_OWN_TR1_TUPLE -# include // IWYU pragma: export // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. @@ -786,24 +545,23 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. -# if GTEST_OS_LINUX && !defined(__ia64__) -# if GTEST_OS_LINUX_ANDROID +#if GTEST_OS_LINUX && !defined(__ia64__) +#if GTEST_OS_LINUX_ANDROID // On Android, clone() became available at different API levels for each 32-bit // architecture. -# if defined(__LP64__) || \ - (defined(__arm__) && __ANDROID_API__ >= 9) || \ - (defined(__mips__) && __ANDROID_API__ >= 12) || \ - (defined(__i386__) && __ANDROID_API__ >= 17) -# define GTEST_HAS_CLONE 1 -# else -# define GTEST_HAS_CLONE 0 -# endif -# else -# define GTEST_HAS_CLONE 1 -# endif -# else -# define GTEST_HAS_CLONE 0 -# endif // GTEST_OS_LINUX && !defined(__ia64__) +#if defined(__LP64__) || (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) +#define GTEST_HAS_CLONE 1 +#else +#define GTEST_HAS_CLONE 0 +#endif +#else +#define GTEST_HAS_CLONE 1 +#endif +#else +#define GTEST_HAS_CLONE 0 +#endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE @@ -812,52 +570,43 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ - GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT -# define GTEST_HAS_STREAM_REDIRECTION 0 -# else -# define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 +#define GTEST_HAS_STREAM_REDIRECTION 0 +#else +#define GTEST_HAS_STREAM_REDIRECTION 1 +#endif // !GTEST_OS_WINDOWS_MOBILE #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \ - GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) -# define GTEST_HAS_DEATH_TEST 1 +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) +#define GTEST_HAS_DEATH_TEST 1 #endif // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) -# define GTEST_HAS_TYPED_TEST 1 -# define GTEST_HAS_TYPED_TEST_P 1 -#endif - -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if (GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_) && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 +#define GTEST_HAS_TYPED_TEST 1 +#define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) // Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX -# define GTEST_CAN_STREAM_RESULTS_ 1 +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD +#define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. @@ -871,9 +620,12 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + switch (0) \ + case 0: \ + default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to @@ -888,61 +640,64 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) -# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused)) #elif defined(__clang__) -# if __has_attribute(unused) -# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -# endif +#if __has_attribute(unused) +#define GTEST_ATTRIBUTE_UNUSED_ __attribute__((unused)) +#endif #endif #ifndef GTEST_ATTRIBUTE_UNUSED_ -# define GTEST_ATTRIBUTE_UNUSED_ +#define GTEST_ATTRIBUTE_UNUSED_ #endif -#if GTEST_LANG_CXX11 -# define GTEST_CXX11_EQUALS_DELETE_ = delete -#else // GTEST_LANG_CXX11 -# define GTEST_CXX11_EQUALS_DELETE_ -#endif // GTEST_LANG_CXX11 - // Use this annotation before a function that takes a printf format string. #if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) -# if defined(__MINGW_PRINTF_FORMAT) +#if defined(__MINGW_PRINTF_FORMAT) // MinGW has two different printf implementations. Ensure the format macro // matches the selected implementation. See // https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. -# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ - __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ - first_to_check))) -# else -# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ - __attribute__((__format__(__printf__, string_index, first_to_check))) -# endif +#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__( \ + (__format__(__MINGW_PRINTF_FORMAT, string_index, first_to_check))) #else -# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +#endif +#else +#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) #endif - -// A macro to disallow operator= +// A macro to disallow copy operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type) \ - void operator=(type const &) GTEST_CXX11_EQUALS_DELETE_ +#define GTEST_DISALLOW_ASSIGN_(type) type &operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ - type(type const &) GTEST_CXX11_EQUALS_DELETE_; \ + type(type const &) = delete; \ GTEST_DISALLOW_ASSIGN_(type) +// A macro to disallow move operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_ASSIGN_(type) \ + type &operator=(type &&) noexcept = delete + +// A macro to disallow move constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_AND_ASSIGN_(type) \ + type(type &&) noexcept = delete; \ + GTEST_DISALLOW_MOVE_ASSIGN_(type) + // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) -# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#if defined(__GNUC__) && !defined(COMPILER_ICC) +#define GTEST_MUST_USE_RESULT_ __attribute__((warn_unused_result)) #else -# define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC +#define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && !COMPILER_ICC // MS C++ compiler emits warning when a conditional expression is compile time // constant. In some contexts this warning is false positive and needs to be @@ -952,10 +707,9 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; // while (true) { // GTEST_INTENTIONAL_CONST_COND_POP_() // } -# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) -# define GTEST_INTENTIONAL_CONST_COND_POP_() \ - GTEST_DISABLE_MSC_WARNINGS_POP_() +#define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +#define GTEST_INTENTIONAL_CONST_COND_POP_() GTEST_DISABLE_MSC_WARNINGS_POP_() // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally @@ -963,113 +717,124 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) +#if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. -# define GTEST_HAS_SEH 1 -# else +#define GTEST_HAS_SEH 1 +#else // Assume no SEH. -# define GTEST_HAS_SEH 0 -# endif - -#define GTEST_IS_THREADSAFE \ - (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \ - || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ - || GTEST_HAS_PTHREAD) +#define GTEST_HAS_SEH 0 +#endif #endif // GTEST_HAS_SEH +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) + +#endif // GTEST_IS_THREADSAFE + // GTEST_API_ qualifies all symbols that must be exported. The definitions below // are guarded by #ifndef to give embedders a chance to define GTEST_API_ in // gtest/internal/custom/gtest-port.h #ifndef GTEST_API_ #ifdef _MSC_VER -# if GTEST_LINKED_AS_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllimport) -# elif GTEST_CREATE_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllexport) -# endif +#if GTEST_LINKED_AS_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllimport) +#elif GTEST_CREATE_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllexport) +#endif #elif __GNUC__ >= 4 || defined(__clang__) -# define GTEST_API_ __attribute__((visibility ("default"))) +#define GTEST_API_ __attribute__((visibility("default"))) #endif // _MSC_VER #endif // GTEST_API_ #ifndef GTEST_API_ -# define GTEST_API_ +#define GTEST_API_ #endif // GTEST_API_ #ifndef GTEST_DEFAULT_DEATH_TEST_STYLE -# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" #endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. -# define GTEST_NO_INLINE_ __attribute__((noinline)) +#define GTEST_NO_INLINE_ __attribute__((noinline)) #else -# define GTEST_NO_INLINE_ +#define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if !defined(GTEST_HAS_CXXABI_H_) -# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) -# define GTEST_HAS_CXXABI_H_ 1 -# else -# define GTEST_HAS_CXXABI_H_ 0 -# endif +#if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +#define GTEST_HAS_CXXABI_H_ 1 +#else +#define GTEST_HAS_CXXABI_H_ 0 +#endif #endif // A function level attribute to disable checking for use of uninitialized // memory when built with MemorySanitizer. #if defined(__clang__) -# if __has_feature(memory_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ - __attribute__((no_sanitize_memory)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -# endif // __has_feature(memory_sanitizer) +#if __has_feature(memory_sanitizer) +#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ __attribute__((no_sanitize_memory)) #else -# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __has_feature(memory_sanitizer) +#else +#define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ #endif // __clang__ // A function level attribute to disable AddressSanitizer instrumentation. #if defined(__clang__) -# if __has_feature(address_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ - __attribute__((no_sanitize_address)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -# endif // __has_feature(address_sanitizer) +#if __has_feature(address_sanitizer) +#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) #else -# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __has_feature(address_sanitizer) +#else +#define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +#if __has_feature(hwaddress_sanitizer) +#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +#else +#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __has_feature(hwaddress_sanitizer) +#else +#define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ #endif // __clang__ // A function level attribute to disable ThreadSanitizer instrumentation. #if defined(__clang__) -# if __has_feature(thread_sanitizer) -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ - __attribute__((no_sanitize_thread)) -# else -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -# endif // __has_feature(thread_sanitizer) +#if __has_feature(thread_sanitizer) +#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ __attribute__((no_sanitize_thread)) #else -# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __has_feature(thread_sanitizer) +#else +#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ #endif // __clang__ namespace testing { class Message; -#if defined(GTEST_TUPLE_NAMESPACE_) -// Import tuple and friends into the ::testing namespace. -// It is part of our interface, having them in ::testing allows us to change -// their types as needed. -using GTEST_TUPLE_NAMESPACE_::get; -using GTEST_TUPLE_NAMESPACE_::make_tuple; -using GTEST_TUPLE_NAMESPACE_::tuple; -using GTEST_TUPLE_NAMESPACE_::tuple_size; -using GTEST_TUPLE_NAMESPACE_::tuple_element; -#endif // defined(GTEST_TUPLE_NAMESPACE_) +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; namespace internal { @@ -1078,158 +843,21 @@ namespace internal { // Secret object, which is what we want. class Secret; -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: // // GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, // names_incorrect_size); // -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -#if GTEST_LANG_CXX11 -# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) -#else // !GTEST_LANG_CXX11 -template - struct CompileAssert { -}; - -# define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ - msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ -#endif // !GTEST_LANG_CXX11 - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// (In C++11, we simply use static_assert instead of the following) -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper { - enum { value = true }; -}; - -// Same as std::is_same<>. -template -struct IsSame { - enum { value = false }; -}; -template -struct IsSame { - enum { value = true }; -}; - -// Evaluates to the number of elements in 'array'. -#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - friend void swap(scoped_ptr& a, scoped_ptr& b) { - using std::swap; - swap(a.ptr_, b.ptr_); - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - // Defines RE. #if GTEST_USES_PCRE @@ -1242,70 +870,46 @@ class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. - RE(const RE& other) { Init(other.pattern()); } + RE(const RE &other) { Init(other.pattern()); } // Constructs an RE from a string. - RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + RE(const ::std::string ®ex) { Init(regex.c_str()); } // NOLINT -# if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -# endif // GTEST_HAS_GLOBAL_STRING - - RE(const char* regex) { Init(regex); } // NOLINT + RE(const char *regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. - const char* pattern() const { return pattern_; } + const char *pattern() const { return pattern_; } - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re // matches a substring of str (including str itself). - // - // FIXME: make FullMatch() and PartialMatch() work - // when str contains NUL characters. - static bool FullMatch(const ::std::string& str, const RE& re) { + static bool FullMatch(const ::std::string &str, const RE &re) { return FullMatch(str.c_str(), re); } - static bool PartialMatch(const ::std::string& str, const RE& re) { + static bool PartialMatch(const ::std::string &str, const RE &re) { return PartialMatch(str.c_str(), re); } -# if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -# endif // GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const char* str, const RE& re); - static bool PartialMatch(const char* str, const RE& re); + static bool FullMatch(const char *str, const RE &re); + static bool PartialMatch(const char *str, const RE &re); private: - void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. FIXME: change to - // std::string. - const char* pattern_; + void Init(const char *regex); + const char *pattern_; bool is_valid_; -# if GTEST_USES_POSIX_RE +#if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -# else // GTEST_USES_SIMPLE_RE +#else // GTEST_USES_SIMPLE_RE - const char* full_pattern_; // For FullMatch(); + const char *full_pattern_; // For FullMatch(); -# endif +#endif GTEST_DISALLOW_ASSIGN_(RE); }; @@ -1314,12 +918,12 @@ class GTEST_API_ RE { // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); +GTEST_API_ ::std::string FormatFileLocation(const char *file, int line); // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char *file, int line); // Defines logging utilities: @@ -1328,24 +932,19 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. -enum GTestLogSeverity { - GTEST_INFO, - GTEST_WARNING, - GTEST_ERROR, - GTEST_FATAL -}; +enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: - GTestLog(GTestLogSeverity severity, const char* file, int line); + GTestLog(GTestLogSeverity severity, const char *file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); - ::std::ostream& GetStream() { return ::std::cerr; } + ::std::ostream &GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; @@ -1355,12 +954,13 @@ class GTEST_API_ GTestLog { #if !defined(GTEST_LOG_) -# define GTEST_LOG_(severity) \ - ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ - __FILE__, __LINE__).GetStream() +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__) \ + .GetStream() inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } +inline void FlushInfoLog() { fflush(nullptr); } #endif // !defined(GTEST_LOG_) @@ -1379,12 +979,12 @@ inline void FlushInfoLog() { fflush(NULL); } // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. -# define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " #endif // !defined(GTEST_CHECK_) // An all-mode assert to verify that the given POSIX-style function @@ -1393,22 +993,8 @@ inline void FlushInfoLog() { fflush(NULL); } // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ - if (const int gtest_error = (posix_call)) \ - GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ - << gtest_error - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " << gtest_error // Transforms "T" into "const T&" according to standard reference collapsing // rules (this is only needed as a backport for C++98 compilers that do not @@ -1422,36 +1008,18 @@ struct AddReference { typedef T& type; }; // NOLINT // Note that the non-const reference will not have "const" added. This is // standard, and necessary so that "T" can always bind to "const T&". template -struct ConstRef { typedef const T& type; }; +struct ConstRef { + typedef const T &type; +}; template -struct ConstRef { typedef T& type; }; +struct ConstRef { + typedef T &type; +}; // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ typename ::testing::internal::ConstRef::type -#if GTEST_HAS_STD_MOVE_ -using std::forward; -using std::move; - -template -struct RvalueRef { - typedef T&& type; -}; -#else // GTEST_HAS_STD_MOVE_ -template -const T& move(const T& t) { - return t; -} -template -GTEST_ADD_REFERENCE_(T) forward(GTEST_ADD_REFERENCE_(T) t) { return t; } - -template -struct RvalueRef { - typedef const T& type; -}; -#endif // GTEST_HAS_STD_MOVE_ - // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in @@ -1472,8 +1040,10 @@ struct RvalueRef { // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. -template -inline To ImplicitCast_(To x) { return x; } +template +inline To ImplicitCast_(To x) { + return x; +} // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts @@ -1496,22 +1066,22 @@ inline To ImplicitCast_(To x) { return x; } // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. -template // use like this: DownCast_(foo); -inline To DownCast_(From* f) { // so we only accept pointers +template // use like this: DownCast_(foo); +inline To DownCast_(From *f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { - GTEST_INTENTIONAL_CONST_COND_POP_() - const To to = NULL; - ::testing::internal::ImplicitCast_(to); + GTEST_INTENTIONAL_CONST_COND_POP_() + const To to = nullptr; + ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); + GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); #endif return static_cast(f); } @@ -1522,17 +1092,17 @@ inline To DownCast_(From* f) { // so we only accept pointers // When RTTI is available, the function performs a runtime // check to enforce this. template -Derived* CheckedDowncastToActualType(Base* base) { +Derived *CheckedDowncastToActualType(Base *base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); #endif #if GTEST_HAS_DOWNCAST_ - return ::down_cast(base); + return ::down_cast(base); #elif GTEST_HAS_RTTI - return dynamic_cast(base); // NOLINT + return dynamic_cast(base); // NOLINT #else - return static_cast(base); // Poor man's downcast. + return static_cast(base); // Poor man's downcast. #endif } @@ -1551,10 +1121,10 @@ GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION // Returns the size (in bytes) of a file. -GTEST_API_ size_t GetFileSize(FILE* file); +GTEST_API_ size_t GetFileSize(FILE *file); // Reads the entire content of a file as a string. -GTEST_API_ std::string ReadEntireFile(FILE* file); +GTEST_API_ std::string ReadEntireFile(FILE *file); // All command line arguments. GTEST_API_ std::vector GetArgvs(); @@ -1563,18 +1133,15 @@ GTEST_API_ std::vector GetArgvs(); std::vector GetInjectableArgvs(); // Deprecated: pass the args vector by value instead. -void SetInjectableArgvs(const std::vector* new_argvs); -void SetInjectableArgvs(const std::vector& new_argvs); -#if GTEST_HAS_GLOBAL_STRING -void SetInjectableArgvs(const std::vector< ::string>& new_argvs); -#endif // GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector *new_argvs); +void SetInjectableArgvs(const std::vector &new_argvs); void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_IS_THREADSAFE -# if GTEST_HAS_PTHREAD +#if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milliseconds. This function is only for testing // Google Test's own constructs. Don't use it in user tests, either // directly or indirectly. @@ -1583,15 +1150,15 @@ inline void SleepMilliseconds(int n) { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; - nanosleep(&time, NULL); + nanosleep(&time, nullptr); } -# endif // GTEST_HAS_PTHREAD +#endif // GTEST_HAS_PTHREAD -# if GTEST_HAS_NOTIFICATION_ +#if GTEST_HAS_NOTIFICATION_ // Notification has already been imported into the namespace. // Nothing to do here. -# elif GTEST_HAS_PTHREAD +#elif GTEST_HAS_PTHREAD // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. @@ -1601,11 +1168,9 @@ inline void SleepMilliseconds(int n) { class Notification { public: Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - } - ~Notification() { - pthread_mutex_destroy(&mutex_); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); } + ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. @@ -1622,8 +1187,7 @@ class Notification { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); - if (notified) - break; + if (notified) break; SleepMilliseconds(10); } } @@ -1635,7 +1199,7 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; -# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT +#elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT GTEST_API_ void SleepMilliseconds(int n); @@ -1648,7 +1212,7 @@ class GTEST_API_ AutoHandle { // undesirable because it defines a lot of symbols and macros that tend to // conflict with client code. This assumption is verified by // WindowsTypesTest.HANDLEIsVoidStar. - typedef void* Handle; + typedef void *Handle; AutoHandle(); explicit AutoHandle(Handle handle); @@ -1659,7 +1223,8 @@ class GTEST_API_ AutoHandle { void Reset(Handle handle); private: - // Returns true iff the handle is a valid handle object that can be closed. + // Returns true if and only if the handle is a valid handle object that can be + // closed. bool IsCloseable() const; Handle handle_; @@ -1684,12 +1249,12 @@ class GTEST_API_ Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; -# endif // GTEST_HAS_NOTIFICATION_ +#endif // GTEST_HAS_NOTIFICATION_ // On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD // defined, but we don't want to use MinGW's pthreads implementation, which // has conformance problems with some versions of the POSIX standard. -# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW +#if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam @@ -1708,9 +1273,9 @@ class ThreadWithParamBase { // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). -extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { - static_cast(thread)->Run(); - return NULL; +extern "C" inline void *ThreadFuncWithCLinkage(void *thread) { + static_cast(thread)->Run(); + return nullptr; } // Helper class for testing Google Test's multi-threading constructs. @@ -1730,51 +1295,49 @@ class ThreadWithParam : public ThreadWithParamBase { public: typedef void UserThreadFunc(T); - ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) - : func_(func), - param_(param), - thread_can_start_(thread_can_start), + ThreadWithParam(UserThreadFunc *func, T param, Notification *thread_can_start) + : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { - ThreadWithParamBase* const base = this; + ThreadWithParamBase *const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); } - ~ThreadWithParam() { Join(); } + ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); finished_ = true; } } - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); func_(param_); } private: - UserThreadFunc* const func_; // User-supplied thread function. + UserThreadFunc *const func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. - Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. + Notification *const thread_can_start_; + bool finished_; // true if and only if we know that the thread function has + // finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; -# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || - // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +#endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ -# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +#if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ // Mutex and ThreadLocal have already been imported into the namespace. // Nothing to do here. -# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT +#elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Mutex implements mutex on Windows platforms. It is used in conjunction // with class MutexLock: @@ -1826,16 +1389,16 @@ class GTEST_API_ Mutex { // by the linker. MutexType type_; long critical_section_init_phase_; // NOLINT - GTEST_CRITICAL_SECTION* critical_section_; + GTEST_CRITICAL_SECTION *critical_section_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::Mutex mutex +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some @@ -1844,13 +1407,12 @@ class GTEST_API_ Mutex { // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: - explicit GTestMutexLock(Mutex* mutex) - : mutex_(mutex) { mutex_->Lock(); } + explicit GTestMutexLock(Mutex *mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: - Mutex* const mutex_; + Mutex *const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; @@ -1872,7 +1434,7 @@ class ThreadLocalBase { // this ThreadLocal's constructor and returns it. It is the caller's // responsibility not to call this when the ThreadLocal instance already // has a value on the current thread. - virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + virtual ThreadLocalValueHolderBase *NewValueForCurrentThread() const = 0; protected: ThreadLocalBase() {} @@ -1889,12 +1451,12 @@ class GTEST_API_ ThreadLocalRegistry { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. - static ThreadLocalValueHolderBase* GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance); + static ThreadLocalValueHolderBase *GetValueOnCurrentThread( + const ThreadLocalBase *thread_local_instance); // Invoked when a ThreadLocal instance is destroyed. static void OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance); + const ThreadLocalBase *thread_local_instance); }; class GTEST_API_ ThreadWithParamBase { @@ -1908,7 +1470,7 @@ class GTEST_API_ ThreadWithParamBase { virtual void Run() = 0; }; - ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + ThreadWithParamBase(Runnable *runnable, Notification *thread_can_start); virtual ~ThreadWithParamBase(); private: @@ -1921,25 +1483,19 @@ class ThreadWithParam : public ThreadWithParamBase { public: typedef void UserThreadFunc(T); - ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) - : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { - } + ThreadWithParam(UserThreadFunc *func, T param, Notification *thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {} virtual ~ThreadWithParam() {} private: class RunnableImpl : public Runnable { public: - RunnableImpl(UserThreadFunc* func, T param) - : func_(func), - param_(param) { - } + RunnableImpl(UserThreadFunc *func, T param) : func_(func), param_(param) {} virtual ~RunnableImpl() {} - virtual void Run() { - func_(param_); - } + virtual void Run() { func_(param_); } private: - UserThreadFunc* const func_; + UserThreadFunc *const func_; const T param_; GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); @@ -1979,15 +1535,15 @@ template class ThreadLocal : public ThreadLocalBase { public: ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} - explicit ThreadLocal(const T& value) + explicit ThreadLocal(const T &value) : default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } + T *pointer() { return GetOrCreateValue(); } + const T *pointer() const { return GetOrCreateValue(); } + const T &get() const { return *pointer(); } + void set(const T &value) { *pointer() = value; } private: // Holds a value of T. Can be deleted via its base class without the caller @@ -1995,22 +1551,22 @@ class ThreadLocal : public ThreadLocalBase { class ValueHolder : public ThreadLocalValueHolderBase { public: ValueHolder() : value_() {} - explicit ValueHolder(const T& value) : value_(value) {} + explicit ValueHolder(const T &value) : value_(value) {} - T* pointer() { return &value_; } + T *pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; - - T* GetOrCreateValue() const { - return static_cast( - ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + T *GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this)) + ->pointer(); } - virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + virtual ThreadLocalValueHolderBase *NewValueForCurrentThread() const { return default_factory_->MakeNewHolder(); } @@ -2018,7 +1574,7 @@ class ThreadLocal : public ThreadLocalBase { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const = 0; + virtual ValueHolder *MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); @@ -2027,7 +1583,7 @@ class ThreadLocal : public ThreadLocalBase { class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + ValueHolder *MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); @@ -2035,8 +1591,8 @@ class ThreadLocal : public ThreadLocalBase { class InstanceValueHolderFactory : public ValueHolderFactory { public: - explicit InstanceValueHolderFactory(const T& value) : value_(value) {} - virtual ValueHolder* MakeNewHolder() const { + explicit InstanceValueHolderFactory(const T &value) : value_(value) {} + ValueHolder *MakeNewHolder() const override { return new ValueHolder(value_); } @@ -2046,12 +1602,12 @@ class ThreadLocal : public ThreadLocalBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; - scoped_ptr default_factory_; + std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# elif GTEST_HAS_PTHREAD +#elif GTEST_HAS_PTHREAD // MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { @@ -2098,8 +1654,8 @@ class MutexBase { }; // Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, @@ -2108,19 +1664,17 @@ class MutexBase { // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. #define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, 0 } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); has_owner_ = false; } - ~Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); - } + ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); @@ -2133,13 +1687,12 @@ class Mutex : public MutexBase { // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: - explicit GTestMutexLock(MutexBase* mutex) - : mutex_(mutex) { mutex_->Lock(); } + explicit GTestMutexLock(MutexBase *mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: - MutexBase* const mutex_; + MutexBase *const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; @@ -2159,8 +1712,8 @@ class ThreadLocalValueHolderBase { // Called by pthread to delete thread-local data stored by // pthread_setspecific(). -extern "C" inline void DeleteThreadLocalValue(void* value_holder) { - delete static_cast(value_holder); +extern "C" inline void DeleteThreadLocalValue(void *value_holder) { + delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. @@ -2169,7 +1722,7 @@ class GTEST_API_ ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} - explicit ThreadLocal(const T& value) + explicit ThreadLocal(const T &value) : key_(CreateKey()), default_factory_(new InstanceValueHolderFactory(value)) {} @@ -2182,19 +1735,19 @@ class GTEST_API_ ThreadLocal { GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } + T *pointer() { return GetOrCreateValue(); } + const T *pointer() const { return GetOrCreateValue(); } + const T &get() const { return *pointer(); } + void set(const T &value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: ValueHolder() : value_() {} - explicit ValueHolder(const T& value) : value_(value) {} + explicit ValueHolder(const T &value) : value_(value) {} - T* pointer() { return &value_; } + T *pointer() { return &value_; } private: T value_; @@ -2210,15 +1763,15 @@ class GTEST_API_ ThreadLocal { return key; } - T* GetOrCreateValue() const { - ThreadLocalValueHolderBase* const holder = - static_cast(pthread_getspecific(key_)); - if (holder != NULL) { + T *GetOrCreateValue() const { + ThreadLocalValueHolderBase *const holder = + static_cast(pthread_getspecific(key_)); + if (holder != nullptr) { return CheckedDowncastToActualType(holder)->pointer(); } - ValueHolder* const new_holder = default_factory_->MakeNewHolder(); - ThreadLocalValueHolderBase* const holder_base = new_holder; + ValueHolder *const new_holder = default_factory_->MakeNewHolder(); + ThreadLocalValueHolderBase *const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } @@ -2227,7 +1780,7 @@ class GTEST_API_ ThreadLocal { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const = 0; + virtual ValueHolder *MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); @@ -2236,7 +1789,7 @@ class GTEST_API_ ThreadLocal { class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} - virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + ValueHolder *MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); @@ -2244,8 +1797,8 @@ class GTEST_API_ ThreadLocal { class InstanceValueHolderFactory : public ValueHolderFactory { public: - explicit InstanceValueHolderFactory(const T& value) : value_(value) {} - virtual ValueHolder* MakeNewHolder() const { + explicit InstanceValueHolderFactory(const T &value) : value_(value) {} + ValueHolder *MakeNewHolder() const override { return new ValueHolder(value_); } @@ -2257,12 +1810,12 @@ class GTEST_API_ ThreadLocal { // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; - scoped_ptr default_factory_; + std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +#endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ #else // GTEST_IS_THREADSAFE @@ -2279,10 +1832,10 @@ class Mutex { void AssertHeld() const {} }; -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some @@ -2291,7 +1844,7 @@ class Mutex { // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: - explicit GTestMutexLock(Mutex*) {} // NOLINT + explicit GTestMutexLock(Mutex *) {} // NOLINT }; typedef GTestMutexLock MutexLock; @@ -2300,11 +1853,12 @@ template class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} - explicit ThreadLocal(const T& value) : value_(value) {} - T* pointer() { return &value_; } - const T* pointer() const { return &value_; } - const T& get() const { return value_; } - void set(const T& value) { value_ = value; } + explicit ThreadLocal(const T &value) : value_(value) {} + T *pointer() { return &value_; } + const T *pointer() const { return &value_; } + const T &get() const { return value_; } + void set(const T &value) { value_ = value; } + private: T value_; }; @@ -2315,77 +1869,12 @@ class GTEST_API_ ThreadLocal { // we cannot detect it. GTEST_API_ size_t GetThreadCount(); -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio before 12u4. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || \ - (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x5130) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_same : public false_type {}; - -template -struct is_same : public true_type {}; - - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -template -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - - -template -struct IteratorTraits { - typedef T value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - #if GTEST_OS_WINDOWS -# define GTEST_PATH_SEP_ "\\" -# define GTEST_HAS_ALT_PATH_SEP_ 1 -// The biggest signed integer type the compiler supports. -typedef __int64 BiggestInt; +#define GTEST_PATH_SEP_ "\\" +#define GTEST_HAS_ALT_PATH_SEP_ 1 #else -# define GTEST_PATH_SEP_ "/" -# define GTEST_HAS_ALT_PATH_SEP_ 0 -typedef long long BiggestInt; // NOLINT +#define GTEST_PATH_SEP_ "/" +#define GTEST_HAS_ALT_PATH_SEP_ 0 #endif // GTEST_OS_WINDOWS // Utilities for char. @@ -2430,8 +1919,7 @@ inline char ToUpper(char ch) { inline std::string StripTrailingSpaces(std::string str) { std::string::iterator it = str.end(); - while (it != str.begin() && IsSpace(*--it)) - it = str.erase(it); + while (it != str.begin() && IsSpace(*--it)) it = str.erase(it); return str; } @@ -2449,50 +1937,64 @@ namespace posix { typedef struct _stat StatStruct; -# ifdef __BORLANDC__ +#ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } -inline int StrCaseCmp(const char* s1, const char* s2) { +inline int StrCaseCmp(const char *s1, const char *s2) { return stricmp(s1, s2); } -inline char* StrDup(const char* src) { return strdup(src); } -# else // !__BORLANDC__ -# if GTEST_OS_WINDOWS_MOBILE +inline char *StrDup(const char *src) { return strdup(src); } +#else // !__BORLANDC__ +#if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } -# else +#else inline int IsATTY(int fd) { return _isatty(fd); } -# endif // GTEST_OS_WINDOWS_MOBILE -inline int StrCaseCmp(const char* s1, const char* s2) { +#endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char *s1, const char *s2) { return _stricmp(s1, s2); } -inline char* StrDup(const char* src) { return _strdup(src); } -# endif // __BORLANDC__ +inline char *StrDup(const char *src) { return _strdup(src); } +#endif // __BORLANDC__ -# if GTEST_OS_WINDOWS_MOBILE -inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +#if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE *file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. -# else -inline int FileNo(FILE* file) { return _fileno(file); } -inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } -inline int RmDir(const char* dir) { return _rmdir(dir); } -inline bool IsDir(const StatStruct& st) { - return (_S_IFDIR & st.st_mode) != 0; +#else +inline int FileNo(FILE *file) { return _fileno(file); } +inline int Stat(const char *path, StatStruct *buf) { return _stat(path, buf); } +inline int RmDir(const char *dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct &st) { return (_S_IFDIR & st.st_mode) != 0; } +#endif // GTEST_OS_WINDOWS_MOBILE + +#elif GTEST_OS_ESP8266 +typedef struct stat StatStruct; + +inline int FileNo(FILE *file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char *path, StatStruct *buf) { + // stat function not implemented on ESP8266 + return 0; } -# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char *s1, const char *s2) { + return strcasecmp(s1, s2); +} +inline char *StrDup(const char *src) { return strdup(src); } +inline int RmDir(const char *dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct &st) { return S_ISDIR(st.st_mode); } #else typedef struct stat StatStruct; -inline int FileNo(FILE* file) { return fileno(file); } +inline int FileNo(FILE *file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } -inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } -inline int StrCaseCmp(const char* s1, const char* s2) { +inline int Stat(const char *path, StatStruct *buf) { return stat(path, buf); } +inline int StrCaseCmp(const char *s1, const char *s2) { return strcasecmp(s1, s2); } -inline char* StrDup(const char* src) { return strdup(src); } -inline int RmDir(const char* dir) { return rmdir(dir); } -inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } +inline char *StrDup(const char *src) { return strdup(src); } +inline int RmDir(const char *dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct &st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS @@ -2500,47 +2002,44 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } GTEST_DISABLE_MSC_DEPRECATED_PUSH_() -inline const char* StrNCpy(char* dest, const char* src, size_t n) { - return strncpy(dest, src, n); -} - // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT -inline int ChDir(const char* dir) { return chdir(dir); } +inline int ChDir(const char *dir) { return chdir(dir); } #endif -inline FILE* FOpen(const char* path, const char* mode) { +inline FILE *FOpen(const char *path, const char *mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE -inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { +inline FILE *FReopen(const char *path, const char *mode, FILE *stream) { return freopen(path, mode, stream); } -inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +inline FILE *FDOpen(int fd, const char *mode) { return fdopen(fd, mode); } #endif -inline int FClose(FILE* fp) { return fclose(fp); } +inline int FClose(FILE *fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE -inline int Read(int fd, void* buf, unsigned int count) { +inline int Read(int fd, void *buf, unsigned int count) { return static_cast(read(fd, buf, count)); } -inline int Write(int fd, const void* buf, unsigned int count) { +inline int Write(int fd, const void *buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } -inline const char* StrError(int errnum) { return strerror(errnum); } +inline const char *StrError(int errnum) { return strerror(errnum); } #endif -inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - // We are on Windows CE, which has no environment variables. +inline const char *GetEnv(const char *name) { +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 + // We are on an embedded platform, which has no environment variables. static_cast(name); // To prevent 'unused argument' warning. - return NULL; + return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. - const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; + const char *const env = getenv(name); + return (env != nullptr && env[0] != '\0') ? env : nullptr; #else return getenv(name); #endif @@ -2552,9 +2051,11 @@ GTEST_DISABLE_MSC_DEPRECATED_POP_() // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. -void Abort(); +[[noreturn]] void Abort(); #else -inline void Abort() { abort(); } +[[noreturn]] inline void Abort() { + abort(); +} #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix @@ -2564,27 +2065,24 @@ inline void Abort() { abort(); } // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. -# define GTEST_SNPRINTF_(buffer, size, format, ...) \ - _snprintf_s(buffer, size, size, format, __VA_ARGS__) +#define GTEST_SNPRINTF_(buffer, size, format, ...) \ + _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. -# define GTEST_SNPRINTF_ _snprintf +// Windows CE does not define _snprintf_s +#define GTEST_SNPRINTF_ _snprintf #else -# define GTEST_SNPRINTF_ snprintf +#define GTEST_SNPRINTF_ snprintf #endif -// The maximum number a BiggestInt can represent. This definition -// works no matter BiggestInt is represented in one's complement or -// two's complement. +// The biggest signed integer type the compiler supports. // -// We cannot rely on numeric_limits in STL, as __int64 and long long -// are not part of standard C++ and numeric_limits doesn't need to be -// defined for them. -const BiggestInt kMaxBiggestInt = - ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); +// long long is guaranteed to be at least 64-bits in C++11. +using BiggestInt = long long; // NOLINT + +// The maximum number a BiggestInt can represent. +constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits::max)(); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that @@ -2609,94 +2107,126 @@ class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. - typedef void UInt; + using UInt = void; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: - // unsigned int has size 4 in both gcc and MSVC. - // - // As base/basictypes.h doesn't compile on Windows, we cannot use - // uint32, uint64, and etc here. - typedef int Int; - typedef unsigned int UInt; + using Int = std::int32_t; + using UInt = std::uint32_t; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: -#if GTEST_OS_WINDOWS - typedef __int64 Int; - typedef unsigned __int64 UInt; -#else - typedef long long Int; // NOLINT - typedef unsigned long long UInt; // NOLINT -#endif // GTEST_OS_WINDOWS + using Int = std::int64_t; + using UInt = std::uint64_t; }; // Integer types of known sizes. -typedef TypeWithSize<4>::Int Int32; -typedef TypeWithSize<4>::UInt UInt32; -typedef TypeWithSize<8>::Int Int64; -typedef TypeWithSize<8>::UInt UInt64; -typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. +using TimeInMillis = int64_t; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #if !defined(GTEST_FLAG) -# define GTEST_FLAG(name) FLAGS_gtest_##name +#define GTEST_FLAG(name) FLAGS_gtest_##name #endif // !defined(GTEST_FLAG) #if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) -# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 #endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) #if !defined(GTEST_DECLARE_bool_) -# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver +#define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // Macros for declaring flags. -# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -# define GTEST_DECLARE_int32_(name) \ - GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -# define GTEST_DECLARE_string_(name) \ - GTEST_API_ extern ::std::string GTEST_FLAG(name) +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern std::int32_t GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -# define GTEST_DEFINE_bool_(name, default_val, doc) \ - GTEST_API_ bool GTEST_FLAG(name) = (default_val) -# define GTEST_DEFINE_int32_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -# define GTEST_DEFINE_string_(name, default_val, doc) \ - GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) #endif // !defined(GTEST_DECLARE_bool_) // Thread annotations #if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) -# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -# define GTEST_LOCK_EXCLUDED_(locks) +#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +#define GTEST_LOCK_EXCLUDED_(locks) #endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// FIXME: Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. -bool ParseInt32(const Message& src_text, const char* str, Int32* value); +bool ParseInt32(const Message &src_text, const char *str, int32_t *value); -// Parses a bool/Int32/string from the environment variable +// Parses a bool/int32_t/string from the environment variable // corresponding to the given Google Test flag. -bool BoolFromGTestEnv(const char* flag, bool default_val); -GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +bool BoolFromGTestEnv(const char *flag, bool default_val); +GTEST_API_ int32_t Int32FromGTestEnv(const char *flag, int32_t default_val); std::string OutputFlagAlsoCheckEnvVar(); -const char* StringFromGTestEnv(const char* flag, const char* default_val); +const char *StringFromGTestEnv(const char *flag, const char *default_val); } // namespace internal } // namespace testing +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + +#if GTEST_HAS_ABSL +// Always use absl::string_view for Matcher<> specializations if googletest +// is built with absl support. +#define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include "absl/strings/string_view.h" +namespace testing { +namespace internal { +using StringView = ::absl::string_view; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::string_view for Matcher<> +// specializations. +#define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include +namespace testing { +namespace internal { +using StringView = ::std::string_view; +} // namespace internal +} // namespace testing + // The case where absl is configured NOT to alias std::string_view is not + // supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-string.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-string.h index 4c9b6262c3..f1f933097d 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-string.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-string.h @@ -43,10 +43,11 @@ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. -# include +#include #endif #include +#include #include #include "gtest/internal/gtest-port.h" @@ -66,7 +67,7 @@ class GTEST_API_ String { // // This is different from strdup() in string.h, which allocates // memory using malloc(). - static const char* CloneCString(const char* c_str); + static const char *CloneCString(const char *c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be @@ -81,7 +82,7 @@ class GTEST_API_ String { // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. - static LPCWSTR AnsiToUtf16(const char* c_str); + static LPCWSTR AnsiToUtf16(const char *c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return @@ -91,41 +92,41 @@ class GTEST_API_ String { // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. - static const char* Utf16ToAnsi(LPCWSTR utf16_str); + static const char *Utf16ToAnsi(LPCWSTR utf16_str); #endif - // Compares two C strings. Returns true iff they have the same content. + // Compares two C strings. Returns true if and only if they have the same + // content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. - static bool CStringEquals(const char* lhs, const char* rhs); + static bool CStringEquals(const char *lhs, const char *rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. - static std::string ShowWideCString(const wchar_t* wide_c_str); + static std::string ShowWideCString(const wchar_t *wide_c_str); - // Compares two wide C strings. Returns true iff they have the same - // content. + // Compares two wide C strings. Returns true if and only if they have the + // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. - static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + static bool WideCStringEquals(const wchar_t *lhs, const wchar_t *rhs); - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. - static bool CaseInsensitiveCStringEquals(const char* lhs, - const char* rhs); + static bool CaseInsensitiveCStringEquals(const char *lhs, const char *rhs); - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, @@ -136,13 +137,13 @@ class GTEST_API_ String { // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. - static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs); + static bool CaseInsensitiveWideCStringEquals(const wchar_t *lhs, + const wchar_t *rhs); - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. - static bool EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix); + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. + static bool EndsWithCaseInsensitive(const std::string &str, + const std::string &suffix); // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 @@ -150,16 +151,19 @@ class GTEST_API_ String { // Formats an int value as "%X". static std::string FormatHexInt(int value); + // Formats an int value as "%X". + static std::string FormatHexUInt32(uint32_t value); + // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); private: String(); // Not meant to be instantiated. -}; // class String +}; // class String // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". -GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); +GTEST_API_ std::string StringStreamToString(::std::stringstream *stream); } // namespace internal } // namespace testing diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h deleted file mode 100644 index 78a3a6a01f..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h +++ /dev/null @@ -1,1021 +0,0 @@ -// This file was GENERATED by command: -// pump.py gtest-tuple.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2009 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Implements a subset of TR1 tuple needed by Google Test and Google Mock. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ - -#include // For ::std::pair. - -// The compiler used in Symbian has a bug that prevents us from declaring the -// tuple template as a friend (it complains that tuple is redefined). This -// bypasses the bug by declaring the members that should otherwise be -// private as public. -// Sun Studio versions < 12 also have the above bug. -#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: -#else -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ - template friend class tuple; \ - private: -#endif - -// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict -// with our own definitions. Therefore using our own tuple does not work on -// those compilers. -#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ -# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ -GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." -#endif - -// GTEST_n_TUPLE_(T) is the type of an n-tuple. -#define GTEST_0_TUPLE_(T) tuple<> -#define GTEST_1_TUPLE_(T) tuple -#define GTEST_2_TUPLE_(T) tuple -#define GTEST_3_TUPLE_(T) tuple -#define GTEST_4_TUPLE_(T) tuple -#define GTEST_5_TUPLE_(T) tuple -#define GTEST_6_TUPLE_(T) tuple -#define GTEST_7_TUPLE_(T) tuple -#define GTEST_8_TUPLE_(T) tuple -#define GTEST_9_TUPLE_(T) tuple -#define GTEST_10_TUPLE_(T) tuple - -// GTEST_n_TYPENAMES_(T) declares a list of n typenames. -#define GTEST_0_TYPENAMES_(T) -#define GTEST_1_TYPENAMES_(T) typename T##0 -#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 -#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 -#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3 -#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4 -#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5 -#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6 -#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 -#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8 -#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8, typename T##9 - -// In theory, defining stuff in the ::std namespace is undefined -// behavior. We can do this as we are playing the role of a standard -// library vendor. -namespace std { -namespace tr1 { - -template -class tuple; - -// Anything in namespace gtest_internal is Google Test's INTERNAL -// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. -namespace gtest_internal { - -// ByRef::type is T if T is a reference; otherwise it's const T&. -template -struct ByRef { typedef const T& type; }; // NOLINT -template -struct ByRef { typedef T& type; }; // NOLINT - -// A handy wrapper for ByRef. -#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type - -// AddRef::type is T if T is a reference; otherwise it's T&. This -// is the same as tr1::add_reference::type. -template -struct AddRef { typedef T& type; }; // NOLINT -template -struct AddRef { typedef T& type; }; // NOLINT - -// A handy wrapper for AddRef. -#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type - -// A helper for implementing get(). -template class Get; - -// A helper for implementing tuple_element. kIndexValid is true -// iff k < the number of fields in tuple type T. -template -struct TupleElement; - -template -struct TupleElement { - typedef T0 type; -}; - -template -struct TupleElement { - typedef T1 type; -}; - -template -struct TupleElement { - typedef T2 type; -}; - -template -struct TupleElement { - typedef T3 type; -}; - -template -struct TupleElement { - typedef T4 type; -}; - -template -struct TupleElement { - typedef T5 type; -}; - -template -struct TupleElement { - typedef T6 type; -}; - -template -struct TupleElement { - typedef T7 type; -}; - -template -struct TupleElement { - typedef T8 type; -}; - -template -struct TupleElement { - typedef T9 type; -}; - -} // namespace gtest_internal - -template <> -class tuple<> { - public: - tuple() {} - tuple(const tuple& /* t */) {} - tuple& operator=(const tuple& /* t */) { return *this; } -}; - -template -class GTEST_1_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} - - tuple(const tuple& t) : f0_(t.f0_) {} - - template - tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_1_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { - f0_ = t.f0_; - return *this; - } - - T0 f0_; -}; - -template -class GTEST_2_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), - f1_(f1) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} - - template - tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} - template - tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_2_TUPLE_(U)& t) { - return CopyFrom(t); - } - template - tuple& operator=(const ::std::pair& p) { - f0_ = p.first; - f1_ = p.second; - return *this; - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - return *this; - } - - T0 f0_; - T1 f1_; -}; - -template -class GTEST_3_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - template - tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_3_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; -}; - -template -class GTEST_4_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} - - template - tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_4_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; -}; - -template -class GTEST_5_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, - GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_) {} - - template - tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_5_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; -}; - -template -class GTEST_6_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_) {} - - template - tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_6_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; -}; - -template -class GTEST_7_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - template - tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_7_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; -}; - -template -class GTEST_8_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, - GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - template - tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_8_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; -}; - -template -class GTEST_9_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - template - tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_9_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; -}; - -template -class tuple { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), - f9_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} - - template - tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), - f9_(t.f9_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_10_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - f9_ = t.f9_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; - T9 f9_; -}; - -// 6.1.3.2 Tuple creation functions. - -// Known limitations: we don't support passing an -// std::tr1::reference_wrapper to make_tuple(). And we don't -// implement tie(). - -inline tuple<> make_tuple() { return tuple<>(); } - -template -inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { - return GTEST_1_TUPLE_(T)(f0); -} - -template -inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { - return GTEST_2_TUPLE_(T)(f0, f1); -} - -template -inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { - return GTEST_3_TUPLE_(T)(f0, f1, f2); -} - -template -inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3) { - return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); -} - -template -inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4) { - return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); -} - -template -inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5) { - return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); -} - -template -inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6) { - return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); -} - -template -inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { - return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); -} - -template -inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8) { - return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); -} - -template -inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8, const T9& f9) { - return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); -} - -// 6.1.3.3 Tuple helper classes. - -template struct tuple_size; - -template -struct tuple_size { - static const int value = 0; -}; - -template -struct tuple_size { - static const int value = 1; -}; - -template -struct tuple_size { - static const int value = 2; -}; - -template -struct tuple_size { - static const int value = 3; -}; - -template -struct tuple_size { - static const int value = 4; -}; - -template -struct tuple_size { - static const int value = 5; -}; - -template -struct tuple_size { - static const int value = 6; -}; - -template -struct tuple_size { - static const int value = 7; -}; - -template -struct tuple_size { - static const int value = 8; -}; - -template -struct tuple_size { - static const int value = 9; -}; - -template -struct tuple_size { - static const int value = 10; -}; - -template -struct tuple_element { - typedef typename gtest_internal::TupleElement< - k < (tuple_size::value), k, Tuple>::type type; -}; - -#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type - -// 6.1.3.4 Element access. - -namespace gtest_internal { - -template <> -class Get<0> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - Field(Tuple& t) { return t.f0_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - ConstField(const Tuple& t) { return t.f0_; } -}; - -template <> -class Get<1> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - Field(Tuple& t) { return t.f1_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - ConstField(const Tuple& t) { return t.f1_; } -}; - -template <> -class Get<2> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - Field(Tuple& t) { return t.f2_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - ConstField(const Tuple& t) { return t.f2_; } -}; - -template <> -class Get<3> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - Field(Tuple& t) { return t.f3_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - ConstField(const Tuple& t) { return t.f3_; } -}; - -template <> -class Get<4> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - Field(Tuple& t) { return t.f4_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - ConstField(const Tuple& t) { return t.f4_; } -}; - -template <> -class Get<5> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - Field(Tuple& t) { return t.f5_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - ConstField(const Tuple& t) { return t.f5_; } -}; - -template <> -class Get<6> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - Field(Tuple& t) { return t.f6_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - ConstField(const Tuple& t) { return t.f6_; } -}; - -template <> -class Get<7> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - Field(Tuple& t) { return t.f7_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - ConstField(const Tuple& t) { return t.f7_; } -}; - -template <> -class Get<8> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - Field(Tuple& t) { return t.f8_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - ConstField(const Tuple& t) { return t.f8_; } -}; - -template <> -class Get<9> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - Field(Tuple& t) { return t.f9_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - ConstField(const Tuple& t) { return t.f9_; } -}; - -} // namespace gtest_internal - -template -GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::Field(t); -} - -template -GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(const GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::ConstField(t); -} - -// 6.1.3.5 Relational operators - -// We only implement == and !=, as we don't have a need for the rest yet. - -namespace gtest_internal { - -// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the -// first k fields of t1 equals the first k fields of t2. -// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if -// k1 != k2. -template -struct SameSizeTuplePrefixComparator; - -template <> -struct SameSizeTuplePrefixComparator<0, 0> { - template - static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { - return true; - } -}; - -template -struct SameSizeTuplePrefixComparator { - template - static bool Eq(const Tuple1& t1, const Tuple2& t2) { - return SameSizeTuplePrefixComparator::Eq(t1, t2) && - ::std::tr1::get(t1) == ::std::tr1::get(t2); - } -}; - -} // namespace gtest_internal - -template -inline bool operator==(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { - return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); -} - -template -inline bool operator!=(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { return !(t == u); } - -// 6.1.4 Pairs. -// Unimplemented. - -} // namespace tr1 -} // namespace std - -#undef GTEST_0_TUPLE_ -#undef GTEST_1_TUPLE_ -#undef GTEST_2_TUPLE_ -#undef GTEST_3_TUPLE_ -#undef GTEST_4_TUPLE_ -#undef GTEST_5_TUPLE_ -#undef GTEST_6_TUPLE_ -#undef GTEST_7_TUPLE_ -#undef GTEST_8_TUPLE_ -#undef GTEST_9_TUPLE_ -#undef GTEST_10_TUPLE_ - -#undef GTEST_0_TYPENAMES_ -#undef GTEST_1_TYPENAMES_ -#undef GTEST_2_TYPENAMES_ -#undef GTEST_3_TYPENAMES_ -#undef GTEST_4_TYPENAMES_ -#undef GTEST_5_TYPENAMES_ -#undef GTEST_6_TYPENAMES_ -#undef GTEST_7_TYPENAMES_ -#undef GTEST_8_TYPENAMES_ -#undef GTEST_9_TYPENAMES_ -#undef GTEST_10_TYPENAMES_ - -#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ -#undef GTEST_BY_REF_ -#undef GTEST_ADD_REF_ -#undef GTEST_TUPLE_ELEMENT_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h.pump b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h.pump deleted file mode 100644 index bb626e049f..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-tuple.h.pump +++ /dev/null @@ -1,348 +0,0 @@ -$$ -*- mode: c++; -*- -$var n = 10 $$ Maximum number of tuple fields we want to support. -$$ This meta comment fixes auto-indentation in Emacs. }} -// Copyright 2009 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Implements a subset of TR1 tuple needed by Google Test and Google Mock. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ - -#include // For ::std::pair. - -// The compiler used in Symbian has a bug that prevents us from declaring the -// tuple template as a friend (it complains that tuple is redefined). This -// bypasses the bug by declaring the members that should otherwise be -// private as public. -// Sun Studio versions < 12 also have the above bug. -#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: -#else -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ - template friend class tuple; \ - private: -#endif - -// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict -// with our own definitions. Therefore using our own tuple does not work on -// those compilers. -#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ -# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ -GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." -#endif - - -$range i 0..n-1 -$range j 0..n -$range k 1..n -// GTEST_n_TUPLE_(T) is the type of an n-tuple. -#define GTEST_0_TUPLE_(T) tuple<> - -$for k [[ -$range m 0..k-1 -$range m2 k..n-1 -#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]> - -]] - -// GTEST_n_TYPENAMES_(T) declares a list of n typenames. - -$for j [[ -$range m 0..j-1 -#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]] - - -]] - -// In theory, defining stuff in the ::std namespace is undefined -// behavior. We can do this as we are playing the role of a standard -// library vendor. -namespace std { -namespace tr1 { - -template <$for i, [[typename T$i = void]]> -class tuple; - -// Anything in namespace gtest_internal is Google Test's INTERNAL -// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. -namespace gtest_internal { - -// ByRef::type is T if T is a reference; otherwise it's const T&. -template -struct ByRef { typedef const T& type; }; // NOLINT -template -struct ByRef { typedef T& type; }; // NOLINT - -// A handy wrapper for ByRef. -#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type - -// AddRef::type is T if T is a reference; otherwise it's T&. This -// is the same as tr1::add_reference::type. -template -struct AddRef { typedef T& type; }; // NOLINT -template -struct AddRef { typedef T& type; }; // NOLINT - -// A handy wrapper for AddRef. -#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type - -// A helper for implementing get(). -template class Get; - -// A helper for implementing tuple_element. kIndexValid is true -// iff k < the number of fields in tuple type T. -template -struct TupleElement; - - -$for i [[ -template -struct TupleElement { - typedef T$i type; -}; - - -]] -} // namespace gtest_internal - -template <> -class tuple<> { - public: - tuple() {} - tuple(const tuple& /* t */) {} - tuple& operator=(const tuple& /* t */) { return *this; } -}; - - -$for k [[ -$range m 0..k-1 -template -class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { - public: - template friend class gtest_internal::Get; - - tuple() : $for m, [[f$(m)_()]] {} - - explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]] -$for m, [[f$(m)_(f$m)]] {} - - tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} - - template - tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} - -$if k == 2 [[ - template - tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} - -]] - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { - return CopyFrom(t); - } - -$if k == 2 [[ - template - tuple& operator=(const ::std::pair& p) { - f0_ = p.first; - f1_ = p.second; - return *this; - } - -]] - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) { - -$for m [[ - f$(m)_ = t.f$(m)_; - -]] - return *this; - } - - -$for m [[ - T$m f$(m)_; - -]] -}; - - -]] -// 6.1.3.2 Tuple creation functions. - -// Known limitations: we don't support passing an -// std::tr1::reference_wrapper to make_tuple(). And we don't -// implement tie(). - -inline tuple<> make_tuple() { return tuple<>(); } - -$for k [[ -$range m 0..k-1 - -template -inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) { - return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]); -} - -]] - -// 6.1.3.3 Tuple helper classes. - -template struct tuple_size; - - -$for j [[ -template -struct tuple_size { - static const int value = $j; -}; - - -]] -template -struct tuple_element { - typedef typename gtest_internal::TupleElement< - k < (tuple_size::value), k, Tuple>::type type; -}; - -#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type - -// 6.1.3.4 Element access. - -namespace gtest_internal { - - -$for i [[ -template <> -class Get<$i> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) - Field(Tuple& t) { return t.f$(i)_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) - ConstField(const Tuple& t) { return t.f$(i)_; } -}; - - -]] -} // namespace gtest_internal - -template -GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) -get(GTEST_$(n)_TUPLE_(T)& t) { - return gtest_internal::Get::Field(t); -} - -template -GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) -get(const GTEST_$(n)_TUPLE_(T)& t) { - return gtest_internal::Get::ConstField(t); -} - -// 6.1.3.5 Relational operators - -// We only implement == and !=, as we don't have a need for the rest yet. - -namespace gtest_internal { - -// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the -// first k fields of t1 equals the first k fields of t2. -// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if -// k1 != k2. -template -struct SameSizeTuplePrefixComparator; - -template <> -struct SameSizeTuplePrefixComparator<0, 0> { - template - static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { - return true; - } -}; - -template -struct SameSizeTuplePrefixComparator { - template - static bool Eq(const Tuple1& t1, const Tuple2& t2) { - return SameSizeTuplePrefixComparator::Eq(t1, t2) && - ::std::tr1::get(t1) == ::std::tr1::get(t2); - } -}; - -} // namespace gtest_internal - -template -inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, - const GTEST_$(n)_TUPLE_(U)& u) { - return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); -} - -template -inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t, - const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); } - -// 6.1.4 Pairs. -// Unimplemented. - -} // namespace tr1 -} // namespace std - - -$for j [[ -#undef GTEST_$(j)_TUPLE_ - -]] - - -$for j [[ -#undef GTEST_$(j)_TYPENAMES_ - -]] - -#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ -#undef GTEST_BY_REF_ -#undef GTEST_ADD_REF_ -#undef GTEST_TUPLE_ELEMENT_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h index 28e4112453..3b3a651dc0 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h +++ b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h @@ -1,7 +1,3 @@ -// This file was GENERATED by command: -// pump.py gtest-type-util.h.pump -// DO NOT EDIT BY HAND!!! - // Copyright 2008 Google Inc. // All Rights Reserved. // @@ -31,14 +27,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. -// Please contact googletestframework@googlegroups.com if you need -// more. +// tests. // GOOGLETEST_CM0001 DO NOT DELETE @@ -49,11 +39,11 @@ // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). -# if GTEST_HAS_CXXABI_H_ -# include -# elif defined(__HP_aCC) -# include -# endif // GTEST_HASH_CXXABI_H_ +#if GTEST_HAS_CXXABI_H_ +#include +#elif defined(__HP_aCC) +#include +#endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { @@ -79,1564 +69,39 @@ inline std::string CanonicalizeForStdLibVersioning(std::string s) { // the typed-test-only section below. template std::string GetTypeName() { -# if GTEST_HAS_RTTI +#if GTEST_HAS_RTTI - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + const char *const name = typeid(T).name(); +#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ +#if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); +#endif // GTEST_HAS_CXXABI_H_ + char *const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return CanonicalizeForStdLibVersioning(name_str); -# else +#else return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC +#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC -# else +#else return ""; -# endif // GTEST_HAS_RTTI +#endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. +// A unique type indicating an empty node struct None {}; -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; -template -struct Types2 { - typedef T1 Head; - typedef Types1 Tail; -}; - -template -struct Types3 { - typedef T1 Head; - typedef Types2 Tail; -}; - -template -struct Types4 { - typedef T1 Head; - typedef Types3 Tail; -}; - -template -struct Types5 { - typedef T1 Head; - typedef Types4 Tail; -}; - -template -struct Types6 { - typedef T1 Head; - typedef Types5 Tail; -}; - -template -struct Types7 { - typedef T1 Head; - typedef Types6 Tail; -}; - -template -struct Types8 { - typedef T1 Head; - typedef Types7 Tail; -}; - -template -struct Types9 { - typedef T1 Head; - typedef Types8 Tail; -}; - -template -struct Types10 { - typedef T1 Head; - typedef Types9 Tail; -}; - -template -struct Types11 { - typedef T1 Head; - typedef Types10 Tail; -}; - -template -struct Types12 { - typedef T1 Head; - typedef Types11 Tail; -}; - -template -struct Types13 { - typedef T1 Head; - typedef Types12 Tail; -}; - -template -struct Types14 { - typedef T1 Head; - typedef Types13 Tail; -}; - -template -struct Types15 { - typedef T1 Head; - typedef Types14 Tail; -}; - -template -struct Types16 { - typedef T1 Head; - typedef Types15 Tail; -}; - -template -struct Types17 { - typedef T1 Head; - typedef Types16 Tail; -}; - -template -struct Types18 { - typedef T1 Head; - typedef Types17 Tail; -}; - -template -struct Types19 { - typedef T1 Head; - typedef Types18 Tail; -}; - -template -struct Types20 { - typedef T1 Head; - typedef Types19 Tail; -}; - -template -struct Types21 { - typedef T1 Head; - typedef Types20 Tail; -}; - -template -struct Types22 { - typedef T1 Head; - typedef Types21 Tail; -}; - -template -struct Types23 { - typedef T1 Head; - typedef Types22 Tail; -}; - -template -struct Types24 { - typedef T1 Head; - typedef Types23 Tail; -}; - -template -struct Types25 { - typedef T1 Head; - typedef Types24 Tail; -}; - -template -struct Types26 { - typedef T1 Head; - typedef Types25 Tail; -}; - -template -struct Types27 { - typedef T1 Head; - typedef Types26 Tail; -}; - -template -struct Types28 { - typedef T1 Head; - typedef Types27 Tail; -}; - -template -struct Types29 { - typedef T1 Head; - typedef Types28 Tail; -}; - -template -struct Types30 { - typedef T1 Head; - typedef Types29 Tail; -}; - -template -struct Types31 { - typedef T1 Head; - typedef Types30 Tail; -}; - -template -struct Types32 { - typedef T1 Head; - typedef Types31 Tail; -}; - -template -struct Types33 { - typedef T1 Head; - typedef Types32 Tail; -}; - -template -struct Types34 { - typedef T1 Head; - typedef Types33 Tail; -}; - -template -struct Types35 { - typedef T1 Head; - typedef Types34 Tail; -}; - -template -struct Types36 { - typedef T1 Head; - typedef Types35 Tail; -}; - -template -struct Types37 { - typedef T1 Head; - typedef Types36 Tail; -}; - -template -struct Types38 { - typedef T1 Head; - typedef Types37 Tail; -}; - -template -struct Types39 { - typedef T1 Head; - typedef Types38 Tail; -}; - -template -struct Types40 { - typedef T1 Head; - typedef Types39 Tail; -}; - -template -struct Types41 { - typedef T1 Head; - typedef Types40 Tail; -}; - -template -struct Types42 { - typedef T1 Head; - typedef Types41 Tail; -}; - -template -struct Types43 { - typedef T1 Head; - typedef Types42 Tail; -}; - -template -struct Types44 { - typedef T1 Head; - typedef Types43 Tail; -}; - -template -struct Types45 { - typedef T1 Head; - typedef Types44 Tail; -}; - -template -struct Types46 { - typedef T1 Head; - typedef Types45 Tail; -}; - -template -struct Types47 { - typedef T1 Head; - typedef Types46 Tail; -}; - -template -struct Types48 { - typedef T1 Head; - typedef Types47 Tail; -}; - -template -struct Types49 { - typedef T1 Head; - typedef Types48 Tail; -}; - -template -struct Types50 { - typedef T1 Head; - typedef Types49 Tail; -}; - - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. -template -struct Types { - typedef internal::Types50 type; -}; - -template <> -struct Types { - typedef internal::Types0 type; -}; -template -struct Types { - typedef internal::Types1 type; -}; -template -struct Types { - typedef internal::Types2 type; -}; -template -struct Types { - typedef internal::Types3 type; -}; -template -struct Types { - typedef internal::Types4 type; -}; -template -struct Types { - typedef internal::Types5 type; -}; -template -struct Types { - typedef internal::Types6 type; -}; -template -struct Types { - typedef internal::Types7 type; -}; -template -struct Types { - typedef internal::Types8 type; -}; -template -struct Types { - typedef internal::Types9 type; -}; -template -struct Types { - typedef internal::Types10 type; -}; -template -struct Types { - typedef internal::Types11 type; -}; -template -struct Types { - typedef internal::Types12 type; -}; -template -struct Types { - typedef internal::Types13 type; -}; -template -struct Types { - typedef internal::Types14 type; -}; -template -struct Types { - typedef internal::Types15 type; -}; -template -struct Types { - typedef internal::Types16 type; -}; -template -struct Types { - typedef internal::Types17 type; -}; -template -struct Types { - typedef internal::Types18 type; -}; -template -struct Types { - typedef internal::Types19 type; -}; -template -struct Types { - typedef internal::Types20 type; -}; -template -struct Types { - typedef internal::Types21 type; -}; -template -struct Types { - typedef internal::Types22 type; -}; -template -struct Types { - typedef internal::Types23 type; -}; -template -struct Types { - typedef internal::Types24 type; -}; -template -struct Types { - typedef internal::Types25 type; -}; -template -struct Types { - typedef internal::Types26 type; -}; -template -struct Types { - typedef internal::Types27 type; -}; -template -struct Types { - typedef internal::Types28 type; -}; -template -struct Types { - typedef internal::Types29 type; -}; -template -struct Types { - typedef internal::Types30 type; -}; -template -struct Types { - typedef internal::Types31 type; -}; -template -struct Types { - typedef internal::Types32 type; -}; -template -struct Types { - typedef internal::Types33 type; -}; -template -struct Types { - typedef internal::Types34 type; -}; -template -struct Types { - typedef internal::Types35 type; -}; -template -struct Types { - typedef internal::Types36 type; -}; -template -struct Types { - typedef internal::Types37 type; -}; -template -struct Types { - typedef internal::Types38 type; -}; -template -struct Types { - typedef internal::Types39 type; -}; -template -struct Types { - typedef internal::Types40 type; -}; -template -struct Types { - typedef internal::Types41 type; -}; -template -struct Types { - typedef internal::Types42 type; -}; -template -struct Types { - typedef internal::Types43 type; -}; -template -struct Types { - typedef internal::Types44 type; -}; -template -struct Types { - typedef internal::Types45 type; -}; -template -struct Types { - typedef internal::Types46 type; -}; -template -struct Types { - typedef internal::Types47 type; -}; -template -struct Types { - typedef internal::Types48 type; -}; -template -struct Types { - typedef internal::Types49 type; -}; - -namespace internal { - -# define GTEST_TEMPLATE_ template class +#define GTEST_TEMPLATE_ \ + template \ + class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type @@ -1654,1695 +119,66 @@ struct TemplateSel { }; }; -# define GTEST_BIND_(TmplSel, T) \ - TmplSel::template Bind::type +#define GTEST_BIND_(TmplSel, T) TmplSel::template Bind::type -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; - -// Template lists of length 1, 2, 3, and so on. - -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; -}; -template -struct Templates2 { - typedef TemplateSel Head; - typedef Templates1 Tail; -}; - -template -struct Templates3 { - typedef TemplateSel Head; - typedef Templates2 Tail; -}; - -template -struct Templates4 { - typedef TemplateSel Head; - typedef Templates3 Tail; -}; - -template -struct Templates5 { - typedef TemplateSel Head; - typedef Templates4 Tail; -}; - -template -struct Templates6 { - typedef TemplateSel Head; - typedef Templates5 Tail; -}; - -template -struct Templates7 { - typedef TemplateSel Head; - typedef Templates6 Tail; -}; - -template -struct Templates8 { - typedef TemplateSel Head; - typedef Templates7 Tail; -}; - -template -struct Templates9 { - typedef TemplateSel Head; - typedef Templates8 Tail; -}; - -template -struct Templates10 { - typedef TemplateSel Head; - typedef Templates9 Tail; -}; - -template -struct Templates11 { - typedef TemplateSel Head; - typedef Templates10 Tail; -}; - -template -struct Templates12 { - typedef TemplateSel Head; - typedef Templates11 Tail; -}; - -template -struct Templates13 { - typedef TemplateSel Head; - typedef Templates12 Tail; -}; - -template -struct Templates14 { - typedef TemplateSel Head; - typedef Templates13 Tail; -}; - -template -struct Templates15 { - typedef TemplateSel Head; - typedef Templates14 Tail; -}; - -template -struct Templates16 { - typedef TemplateSel Head; - typedef Templates15 Tail; -}; - -template -struct Templates17 { - typedef TemplateSel Head; - typedef Templates16 Tail; -}; - -template -struct Templates18 { - typedef TemplateSel Head; - typedef Templates17 Tail; -}; - -template -struct Templates19 { - typedef TemplateSel Head; - typedef Templates18 Tail; -}; - -template -struct Templates20 { - typedef TemplateSel Head; - typedef Templates19 Tail; -}; - -template -struct Templates21 { - typedef TemplateSel Head; - typedef Templates20 Tail; -}; - -template -struct Templates22 { - typedef TemplateSel Head; - typedef Templates21 Tail; -}; - -template -struct Templates23 { - typedef TemplateSel Head; - typedef Templates22 Tail; -}; - -template -struct Templates24 { - typedef TemplateSel Head; - typedef Templates23 Tail; -}; - -template -struct Templates25 { - typedef TemplateSel Head; - typedef Templates24 Tail; -}; - -template -struct Templates26 { - typedef TemplateSel Head; - typedef Templates25 Tail; -}; - -template -struct Templates27 { - typedef TemplateSel Head; - typedef Templates26 Tail; -}; - -template -struct Templates28 { - typedef TemplateSel Head; - typedef Templates27 Tail; -}; - -template -struct Templates29 { - typedef TemplateSel Head; - typedef Templates28 Tail; -}; - -template -struct Templates30 { - typedef TemplateSel Head; - typedef Templates29 Tail; -}; - -template -struct Templates31 { - typedef TemplateSel Head; - typedef Templates30 Tail; -}; - -template -struct Templates32 { - typedef TemplateSel Head; - typedef Templates31 Tail; -}; - -template -struct Templates33 { - typedef TemplateSel Head; - typedef Templates32 Tail; -}; - -template -struct Templates34 { - typedef TemplateSel Head; - typedef Templates33 Tail; -}; - -template -struct Templates35 { - typedef TemplateSel Head; - typedef Templates34 Tail; -}; - -template -struct Templates36 { - typedef TemplateSel Head; - typedef Templates35 Tail; -}; - -template -struct Templates37 { - typedef TemplateSel Head; - typedef Templates36 Tail; -}; - -template -struct Templates38 { - typedef TemplateSel Head; - typedef Templates37 Tail; -}; - -template -struct Templates39 { - typedef TemplateSel Head; - typedef Templates38 Tail; -}; - -template -struct Templates40 { - typedef TemplateSel Head; - typedef Templates39 Tail; -}; - -template -struct Templates41 { - typedef TemplateSel Head; - typedef Templates40 Tail; -}; - -template -struct Templates42 { - typedef TemplateSel Head; - typedef Templates41 Tail; -}; - -template -struct Templates43 { - typedef TemplateSel Head; - typedef Templates42 Tail; -}; - -template -struct Templates44 { - typedef TemplateSel Head; - typedef Templates43 Tail; -}; - -template -struct Templates45 { - typedef TemplateSel Head; - typedef Templates44 Tail; -}; - -template -struct Templates46 { - typedef TemplateSel Head; - typedef Templates45 Tail; -}; - -template -struct Templates47 { - typedef TemplateSel Head; - typedef Templates46 Tail; -}; - -template -struct Templates48 { - typedef TemplateSel Head; - typedef Templates47 Tail; -}; - -template -struct Templates49 { - typedef TemplateSel Head; - typedef Templates48 Tail; -}; - -template -struct Templates50 { - typedef TemplateSel Head; - typedef Templates49 Tail; -}; - - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. -template +template struct Templates { - typedef Templates50 type; + using Head = TemplateSel; + using Tail = Templates; }; -template <> -struct Templates { - typedef Templates0 type; -}; -template -struct Templates { - typedef Templates1 type; -}; -template -struct Templates { - typedef Templates2 type; -}; -template -struct Templates { - typedef Templates3 type; -}; -template -struct Templates { - typedef Templates4 type; -}; -template -struct Templates { - typedef Templates5 type; -}; -template -struct Templates { - typedef Templates6 type; -}; -template -struct Templates { - typedef Templates7 type; -}; -template -struct Templates { - typedef Templates8 type; -}; -template -struct Templates { - typedef Templates9 type; -}; -template -struct Templates { - typedef Templates10 type; -}; -template -struct Templates { - typedef Templates11 type; -}; -template -struct Templates { - typedef Templates12 type; -}; -template -struct Templates { - typedef Templates13 type; -}; -template -struct Templates { - typedef Templates14 type; -}; -template -struct Templates { - typedef Templates15 type; -}; -template -struct Templates { - typedef Templates16 type; -}; -template -struct Templates { - typedef Templates17 type; -}; -template -struct Templates { - typedef Templates18 type; -}; -template -struct Templates { - typedef Templates19 type; -}; -template -struct Templates { - typedef Templates20 type; -}; -template -struct Templates { - typedef Templates21 type; -}; -template -struct Templates { - typedef Templates22 type; -}; -template -struct Templates { - typedef Templates23 type; -}; -template -struct Templates { - typedef Templates24 type; -}; -template -struct Templates { - typedef Templates25 type; -}; -template -struct Templates { - typedef Templates26 type; -}; -template -struct Templates { - typedef Templates27 type; -}; -template -struct Templates { - typedef Templates28 type; -}; -template -struct Templates { - typedef Templates29 type; -}; -template -struct Templates { - typedef Templates30 type; -}; -template -struct Templates { - typedef Templates31 type; -}; -template -struct Templates { - typedef Templates32 type; -}; -template -struct Templates { - typedef Templates33 type; -}; -template -struct Templates { - typedef Templates34 type; -}; -template -struct Templates { - typedef Templates35 type; -}; -template -struct Templates { - typedef Templates36 type; -}; -template -struct Templates { - typedef Templates37 type; -}; -template -struct Templates { - typedef Templates38 type; -}; -template -struct Templates { - typedef Templates39 type; -}; -template -struct Templates { - typedef Templates40 type; -}; -template -struct Templates { - typedef Templates41 type; -}; -template -struct Templates { - typedef Templates42 type; -}; -template -struct Templates { - typedef Templates43 type; -}; -template -struct Templates { - typedef Templates44 type; -}; -template -struct Templates { - typedef Templates45 type; -}; -template -struct Templates { - typedef Templates46 type; -}; -template -struct Templates { - typedef Templates47 type; -}; -template -struct Templates { - typedef Templates48 type; -}; -template -struct Templates { - typedef Templates49 type; +template +struct Templates { + using Head = TemplateSel; + using Tail = None; }; -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). +// Tuple-like type lists +template +struct Types { + using Head = Head_; + using Tail = Types; +}; +template +struct Types { + using Head = Head_; + using Tail = None; +}; + +// Helper metafunctions to tell apart a single type from types +// generated by ::testing::Types +template +struct ProxyTypeList { + using type = Types; +}; + +template +struct is_proxy_type_list : std::false_type {}; + +template +struct is_proxy_type_list> : std::true_type {}; + +// Generator which conditionally creates type lists. +// It recognizes if a requested type list should be created +// and prevents creating a new type list nested within another one. template -struct TypeList { - typedef Types1 type; -}; +struct GenerateTypeList { + private: + using proxy = typename std::conditional::value, T, + ProxyTypeList>::type; -template -struct TypeList > { - typedef typename Types::type type; + public: + using type = typename proxy::type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal + +template +using Types = internal::ProxyTypeList; + } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.pump b/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.pump deleted file mode 100644 index 0001a5d39d..0000000000 --- a/media/libaom/src/third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.pump +++ /dev/null @@ -1,314 +0,0 @@ -$$ -*- mode: c++; -*- -$var n = 50 $$ Maximum length of type lists we want to support. -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most $n types in a list, and at most $n -// type-parameterized tests in one type-parameterized test case. -// Please contact googletestframework@googlegroups.com if you need -// more. - -// GOOGLETEST_CM0001 DO NOT DELETE - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - -#include "gtest/internal/gtest-port.h" - -// #ifdef __GNUC__ is too general here. It is possible to use gcc without using -// libstdc++ (which is where cxxabi.h comes from). -# if GTEST_HAS_CXXABI_H_ -# include -# elif defined(__HP_aCC) -# include -# endif // GTEST_HASH_CXXABI_H_ - -namespace testing { -namespace internal { - -// Canonicalizes a given name with respect to the Standard C++ Library. -// This handles removing the inline namespace within `std` that is -// used by various standard libraries (e.g., `std::__1`). Names outside -// of namespace std are returned unmodified. -inline std::string CanonicalizeForStdLibVersioning(std::string s) { - static const char prefix[] = "std::__"; - if (s.compare(0, strlen(prefix), prefix) == 0) { - std::string::size_type end = s.find("::", strlen(prefix)); - if (end != s.npos) { - // Erase everything between the initial `std` and the second `::`. - s.erase(strlen("std"), end - strlen("std")); - } - } - return s; -} - -// GetTypeName() returns a human-readable name of type T. -// NB: This function is also used in Google Mock, so don't move it inside of -// the typed-test-only section below. -template -std::string GetTypeName() { -# if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) - int status = 0; - // gcc's implementation of typeid(T).name() mangles the type name, - // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ - using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); - const std::string name_str(status == 0 ? readable_name : name); - free(readable_name); - return CanonicalizeForStdLibVersioning(name_str); -# else - return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC - -# else - - return ""; - -# endif // GTEST_HAS_RTTI -} - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. -struct None {}; - -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; - -$range i 2..n - -$for i [[ -$range j 1..i -$range k 2..i -template <$for j, [[typename T$j]]> -struct Types$i { - typedef T1 Head; - typedef Types$(i-1)<$for k, [[T$k]]> Tail; -}; - - -]] - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. - -$range i 1..n -template <$for i, [[typename T$i = internal::None]]> -struct Types { - typedef internal::Types$n<$for i, [[T$i]]> type; -}; - -template <> -struct Types<$for i, [[internal::None]]> { - typedef internal::Types0 type; -}; - -$range i 1..n-1 -$for i [[ -$range j 1..i -$range k i+1..n -template <$for j, [[typename T$j]]> -struct Types<$for j, [[T$j]]$for k[[, internal::None]]> { - typedef internal::Types$i<$for j, [[T$j]]> type; -}; - -]] - -namespace internal { - -# define GTEST_TEMPLATE_ template class - -// The template "selector" struct TemplateSel is used to -// represent Tmpl, which must be a class template with one type -// parameter, as a type. TemplateSel::Bind::type is defined -// as the type Tmpl. This allows us to actually instantiate the -// template "selected" by TemplateSel. -// -// This trick is necessary for simulating typedef for class templates, -// which C++ doesn't support directly. -template -struct TemplateSel { - template - struct Bind { - typedef Tmpl type; - }; -}; - -# define GTEST_BIND_(TmplSel, T) \ - TmplSel::template Bind::type - -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; - -// Template lists of length 1, 2, 3, and so on. - -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; -}; - -$range i 2..n - -$for i [[ -$range j 1..i -$range k 2..i -template <$for j, [[GTEST_TEMPLATE_ T$j]]> -struct Templates$i { - typedef TemplateSel Head; - typedef Templates$(i-1)<$for k, [[T$k]]> Tail; -}; - - -]] - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. - -$range i 1..n -template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]> -struct Templates { - typedef Templates$n<$for i, [[T$i]]> type; -}; - -template <> -struct Templates<$for i, [[NoneT]]> { - typedef Templates0 type; -}; - -$range i 1..n-1 -$for i [[ -$range j 1..i -$range k i+1..n -template <$for j, [[GTEST_TEMPLATE_ T$j]]> -struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> { - typedef Templates$i<$for j, [[T$j]]> type; -}; - -]] - -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). - -template -struct TypeList { - typedef Types1 type; -}; - - -$range i 1..n -template <$for i, [[typename T$i]]> -struct TypeList > { - typedef typename Types<$for i, [[T$i]]>::type type; -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-all.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-all.cc index b217a18006..ad292905cf 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-all.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-all.cc @@ -41,6 +41,7 @@ #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" +#include "src/gtest-matchers.cc" #include "src/gtest-port.cc" #include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-death-test.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-death-test.cc index 0908355161..c38551cda1 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-death-test.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-death-test.cc @@ -31,43 +31,52 @@ // This file implements death tests. #include "gtest/gtest-death-test.h" + +#include + #include "gtest/internal/gtest-port.h" #include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST -# if GTEST_OS_MAC -# include -# endif // GTEST_OS_MAC +#if GTEST_OS_MAC +#include +#endif // GTEST_OS_MAC -# include -# include -# include +#include +#include +#include -# if GTEST_OS_LINUX -# include -# endif // GTEST_OS_LINUX +#if GTEST_OS_LINUX +#include +#endif // GTEST_OS_LINUX -# include +#include -# if GTEST_OS_WINDOWS -# include -# else -# include -# include -# endif // GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +#include +#else +#include +#include +#endif // GTEST_OS_WINDOWS -# if GTEST_OS_QNX -# include -# endif // GTEST_OS_QNX +#if GTEST_OS_QNX +#include +#endif // GTEST_OS_QNX -# if GTEST_OS_FUCHSIA -# include -# include -# include -# include -# include -# endif // GTEST_OS_FUCHSIA +#if GTEST_OS_FUCHSIA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // GTEST_OS_FUCHSIA #endif // GTEST_HAS_DEATH_TEST @@ -113,8 +122,8 @@ GTEST_DEFINE_string_( "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " + "the '|' characters. This flag is specified if and only if the " + "current process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal @@ -124,9 +133,9 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. -# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; -# endif +#endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as @@ -134,13 +143,13 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +#if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA // On Windows and Fuchsia, death tests are thread-safe regardless of the value // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); -# else +#else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); @@ -152,40 +161,38 @@ bool InDeathTestChild() { } // namespace internal // ExitedWithCode constructor. -ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { -} +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {} // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +#if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; -# else +#else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +#endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. -KilledBySignal::KilledBySignal(int signum) : signum_(signum) { -} +KilledBySignal::KilledBySignal(int signum) : signum_(signum) {} // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { -# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) +#if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) { bool result; if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { return result; } } -# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) +#endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -196,23 +203,23 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +#if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; -# else +#else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } -# ifdef WCOREDUMP +#ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } -# endif -# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA +#endif +#endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -223,7 +230,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -244,7 +251,7 @@ static std::string DeathTestThreadWarning(size_t thread_count) { << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +#endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -266,8 +273,6 @@ static const int kFuchsiaReadPipeFd = 3; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// FIXME: Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an @@ -275,14 +280,14 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -static void DeathTestAbort(const std::string& message) { +static void DeathTestAbort(const std::string &message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. - const InternalRunDeathTestFlag* const flag = + const InternalRunDeathTestFlag *const flag = GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { - FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + if (flag != nullptr) { + FILE *parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); @@ -296,14 +301,14 @@ static void DeathTestAbort(const std::string& message) { // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. -# define GTEST_DEATH_TEST_CHECK_(expression) \ - do { \ - if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression); \ - } \ +#define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::std::string("CHECK failed: File ") + __FILE__ + \ + ", line " + \ + ::testing::internal::StreamableToString(__LINE__) + \ + ": " + #expression); \ + } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for @@ -313,23 +318,23 @@ static void DeathTestAbort(const std::string& message) { // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. -# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ - do { \ - int gtest_retval; \ - do { \ - gtest_retval = (expression); \ - } while (gtest_retval == -1 && errno == EINTR); \ - if (gtest_retval == -1) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression + " != -1"); \ - } \ +#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::std::string("CHECK failed: File ") + __FILE__ + \ + ", line " + \ + ::testing::internal::StreamableToString(__LINE__) + \ + ": " + #expression + " != -1"); \ + } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { - return errno == 0 ? "" : posix::StrError(errno); + return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure @@ -360,26 +365,28 @@ static void FailFromInternalError(int fd) { // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { - TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { - DeathTestAbort("Cannot run a death test outside of a TEST or " - "TEST_F construct"); + TestInfo *const info = GetUnitTestImpl()->current_test_info(); + if (info == nullptr) { + DeathTestAbort( + "Cannot run a death test outside of a TEST or " + "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { +bool DeathTest::Create(const char *statement, + Matcher matcher, const char *file, + int line, DeathTest **test) { return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); + statement, std::move(matcher), file, line, test); } -const char* DeathTest::LastMessage() { +const char *DeathTest::LastMessage() { return last_death_test_message_.c_str(); } -void DeathTest::set_last_death_test_message(const std::string& message) { +void DeathTest::set_last_death_test_message(const std::string &message) { last_death_test_message_ = message; } @@ -388,23 +395,17 @@ std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) - : statement_(a_statement), - regex_(a_regex), - spawned_(false), - status_(-1), - outcome_(IN_PROGRESS), - read_fd_(-1), - write_fd_(-1) {} + DeathTestImpl(const char *a_statement, Matcher matcher) + : statement_(a_statement), matcher_(std::move(matcher)), spawned_(false), + status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; - const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } + const char *statement() const { return statement_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } @@ -422,13 +423,15 @@ class DeathTestImpl : public DeathTest { // case of unexpected codes. void ReadAndInterpretStatusByte(); + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. - const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; + const char *const statement_; + // A matcher that's expected to match the stderr output by the child process. + Matcher matcher_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. @@ -465,15 +468,9 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestThrew: - set_outcome(THREW); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; + case kDeathTestReturned: set_outcome(RETURNED); break; + case kDeathTestThrew: set_outcome(THREW); break; + case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; @@ -490,6 +487,8 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_read_fd(-1); } +std::string DeathTestImpl::GetErrorLogs() { return GetCapturedStderr(); } + // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then @@ -498,9 +497,11 @@ void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : - reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + const char status_ch = reason == TEST_DID_NOT_DIE + ? kDeathTestLived + : reason == TEST_THREW_EXCEPTION + ? kDeathTestThrew + : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., @@ -517,9 +518,9 @@ void DeathTestImpl::Abort(AbortReason reason) { // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. -static ::std::string FormatDeathTestOutput(const ::std::string& output) { +static ::std::string FormatDeathTestOutput(const ::std::string &output) { ::std::string ret; - for (size_t at = 0; ; ) { + for (size_t at = 0;;) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { @@ -543,22 +544,20 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) { // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. +// matcher_: A matcher that's expected to match the stderr output by the child +// process. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is +// Returns true if and only if all of the above conditions are met. Otherwise, +// the first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; + if (!spawned()) return false; - const std::string error_message = GetCapturedStderr(); + const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; @@ -567,35 +566,36 @@ bool DeathTestImpl::Passed(bool status_ok) { switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); + << " Error msg:\n" + << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); + << " Error msg:\n" + << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); + << " Error msg:\n" + << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { -# if GTEST_USES_PCRE - // PCRE regexes support embedded NULs. - const bool matched = RE::PartialMatch(error_message, *regex()); -# else - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); -# endif // GTEST_USES_PCRE - if (matched) { + if (matcher_.Matches(error_message)) { success = true; } else { + std::ostringstream stream; + matcher_.DescribeTo(&stream); buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); + << " Expected: " << stream.str() << "\n" + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); + << "Actual msg:\n" + << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: @@ -608,7 +608,7 @@ bool DeathTestImpl::Passed(bool status_ok) { return success; } -# if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the @@ -639,11 +639,11 @@ bool DeathTestImpl::Passed(bool status_ok) { // class WindowsDeathTest : public DeathTestImpl { public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, + WindowsDeathTest(const char *a_statement, + Matcher matcher, const char *file, int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + : DeathTestImpl(a_statement, std::move(matcher)), file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -651,7 +651,7 @@ class WindowsDeathTest : public DeathTestImpl { private: // The name of the file in which the death test is located. - const char* const file_; + const char *const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. @@ -669,21 +669,17 @@ class WindowsDeathTest : public DeathTestImpl { // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { - if (!spawned()) - return 0; + if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; - switch (::WaitForMultipleObjects(2, - wait_handles, + switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: - case WAIT_OBJECT_0 + 1: - break; - default: - GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + case WAIT_OBJECT_0 + 1: break; + default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. @@ -697,9 +693,8 @@ int WindowsDeathTest::Wait() { // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. - GTEST_DEATH_TEST_CHECK_( - WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), - INFINITE)); + GTEST_DEATH_TEST_CHECK_(WAIT_OBJECT_0 == + ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); @@ -714,13 +709,13 @@ int WindowsDeathTest::Wait() { // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = + const UnitTestImpl *const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag *const flag = impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); + const TestInfo *const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); @@ -729,45 +724,43 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), + nullptr, TRUE }; HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_( - ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, - 0) // Default buffer size. - != FALSE); - set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), - O_RDONLY)); + GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, + &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd( + ::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + nullptr)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + - "=" + file_ + "|" + StreamableToString(line_) + "|" + + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - "|" + StreamableToString(reinterpret_cast(write_handle)) + - "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); + "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); + GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, + executable_path, + _MAX_PATH)); - std::string command_line = - std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + - internal_flag + "\""; + std::string command_line = std::string(::GetCommandLineA()) + " " + + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); @@ -784,139 +777,165 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); + GTEST_DEATH_TEST_CHECK_( + ::CreateProcessA( + executable_path, const_cast(command_line.c_str()), + nullptr, // Retuned process handle is not inheritable. + nullptr, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + nullptr, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), &startup_info, + &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } -# elif GTEST_OS_FUCHSIA +#elif GTEST_OS_FUCHSIA class FuchsiaDeathTest : public DeathTestImpl { public: - FuchsiaDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, + FuchsiaDeathTest(const char *a_statement, + Matcher matcher, const char *file, int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - virtual ~FuchsiaDeathTest() { - zx_status_t status = zx_handle_close(child_process_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_handle_close(port_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - } + : DeathTestImpl(a_statement, std::move(matcher)), file_(file), + line_(line) {} // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); + int Wait() override; + TestRole AssumeRole() override; + std::string GetErrorLogs() override; private: // The name of the file in which the death test is located. - const char* const file_; + const char *const file_; // The line number on which the death test is located. const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; - zx_handle_t child_process_ = ZX_HANDLE_INVALID; - zx_handle_t port_ = ZX_HANDLE_INVALID; + zx::process child_process_; + zx::channel exception_channel_; + zx::socket stderr_socket_; }; // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); + for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } - void AddArgument(const char* argument) { + void AddArgument(const char *argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template - void AddArguments(const ::std::vector& arguments) { + void AddArguments(const ::std::vector &arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { + i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } - char* const* Argv() { - return &args_[0]; - } + char *const *Argv() { return &args_[0]; } - int size() { - return args_.size() - 1; - } + int size() { return args_.size() - 1; } private: - std::vector args_; + std::vector args_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int FuchsiaDeathTest::Wait() { - if (!spawned()) - return 0; + const int kProcessKey = 0; + const int kSocketKey = 1; + const int kExceptionKey = 2; + + if (!spawned()) return 0; + + // Create a port to wait for socket/task/exception events. + zx_status_t status_zx; + zx::port port; + status_zx = zx::port::create(0, &port); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for the child process to terminate. - zx_status_t status_zx; - status_zx = zx_object_wait_async(child_process_, - port_, - 0 /* key */, - ZX_PROCESS_TERMINATED, - ZX_WAIT_ASYNC_ONCE); + status_zx = child_process_.wait_async( + port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Wait for it to terminate, or an exception to be received. - zx_port_packet_t packet; - status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - if (ZX_PKT_IS_EXCEPTION(packet.type)) { - // Process encountered an exception. Kill it directly rather than letting - // other handlers process the event. - status_zx = zx_task_kill(child_process_); + // Register to wait for an exception. + status_zx = exception_channel_.wait_async( + port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port.wait(zx::time::infinite(), &packet); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Now wait for |child_process_| to terminate. - zx_signals_t signals = 0; - status_zx = zx_object_wait_one( - child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); - GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); - } else { - // Process terminated. - GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); - GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); - } + if (packet.key == kExceptionKey) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a kProcessKey + // event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else if (packet.key == kProcessKey) { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = + stderr_socket_.read(0, &captured_stderr_.front() + old_length, + kBufferSize, &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + status_zx = stderr_socket_.wait_async( + port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); ReadAndInterpretStatusByte(); zx_info_process_t buffer; - status_zx = zx_object_get_info( - child_process_, - ZX_INFO_PROCESS, - &buffer, - sizeof(buffer), - nullptr, - nullptr); + status_zx = child_process_.get_info(ZX_INFO_PROCESS, &buffer, sizeof(buffer), + nullptr, nullptr); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); GTEST_DEATH_TEST_CHECK_(buffer.exited); @@ -930,32 +949,30 @@ int FuchsiaDeathTest::Wait() { // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = + const UnitTestImpl *const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag *const flag = impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); + const TestInfo *const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(kFuchsiaReadPipeFd); return EXECUTE_TEST; } - CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // Build the child process command line. - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" - + file_ + "|" - + StreamableToString(line_) + "|" - + StreamableToString(death_test_index); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kInternalRunDeathTestFlag + "=" + file_ + + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); Arguments args; args.AddArguments(GetInjectableArgvs()); args.AddArgument(filter_flag.c_str()); @@ -964,35 +981,64 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { // Build the pipe for communication with the child. zx_status_t status; zx_handle_t child_pipe_handle; - uint32_t type; - status = fdio_pipe_half(&child_pipe_handle, &type); - GTEST_DEATH_TEST_CHECK_(status >= 0); - set_read_fd(status); + int child_pipe_fd; + status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + set_read_fd(child_pipe_fd); // Set the pipe handle for the child. - fdio_spawn_action_t add_handle_action = {}; - add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; - add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); - add_handle_action.h.handle = child_pipe_handle; + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t *add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + status = + fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); + + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t *add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; + + // Create a child job. + zx_handle_t child_job = ZX_HANDLE_INVALID; + status = zx_job_create(zx_job_default(), 0, &child_job); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + zx_policy_basic_t policy; + policy.condition = ZX_POL_NEW_ANY; + policy.policy = ZX_POL_ACTION_ALLOW; + status = zx_job_set_policy(child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, + &policy, 1); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception channel attached to the |child_job|, to allow + // us to suppress the system default exception handler from firing. + status = zx_task_create_exception_channel( + child_job, 0, exception_channel_.reset_and_get_address()); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); // Spawn the child process. - status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, - args.Argv()[0], args.Argv(), nullptr, 1, - &add_handle_action, &child_process_, nullptr); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - - // Create an exception port and attach it to the |child_process_|, to allow - // us to suppress the system default exception handler from firing. - status = zx_port_create(0, &port_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_task_bind_exception_port( - child_process_, port_, 0 /* key */, 0 /*options */); + status = fdio_spawn_etc(child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], + args.Argv(), nullptr, 2, spawn_actions, + child_process_.reset_and_get_address(), nullptr); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); set_spawned(true); return OVERSEE_TEST; } +std::string FuchsiaDeathTest::GetErrorLogs() { return captured_stderr_; } + #else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract @@ -1000,10 +1046,10 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { // left undefined. class ForkingDeathTest : public DeathTestImpl { public: - ForkingDeathTest(const char* statement, const RE* regex); + ForkingDeathTest(const char *statement, Matcher matcher); // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); + int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } @@ -1014,16 +1060,15 @@ class ForkingDeathTest : public DeathTestImpl { }; // Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} +ForkingDeathTest::ForkingDeathTest(const char *a_statement, + Matcher matcher) + : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { - if (!spawned()) - return 0; + if (!spawned()) return 0; ReadAndInterpretStatusByte(); @@ -1037,9 +1082,9 @@ int ForkingDeathTest::Wait() { // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); + NoExecDeathTest(const char *a_statement, Matcher matcher) + : ForkingDeathTest(a_statement, std::move(matcher)) {} + TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a @@ -1092,22 +1137,24 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); + ExecDeathTest(const char *a_statement, Matcher matcher, + const char *file, int line) + : ForkingDeathTest(a_statement, std::move(matcher)), file_(file), + line_(line) {} + TestRole AssumeRole() override; + private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); -# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) +#if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) ::std::vector extra_args = GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); args.insert(args.end(), extra_args.begin(), extra_args.end()); -# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) +#endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. - const char* const file_; + const char *const file_; // The line number on which the death test is located. const int line_; }; @@ -1115,74 +1162,69 @@ class ExecDeathTest : public ForkingDeathTest { // Utility class for accumulating command-line arguments. class Arguments { public: - Arguments() { - args_.push_back(NULL); - } + Arguments() { args_.push_back(nullptr); } ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); + for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } - void AddArgument(const char* argument) { + void AddArgument(const char *argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template - void AddArguments(const ::std::vector& arguments) { + void AddArguments(const ::std::vector &arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { + i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } - char* const* Argv() { - return &args_[0]; - } + char *const *Argv() { return &args_[0]; } private: - std::vector args_; + std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { - char* const* argv; // Command-line arguments for the child's call to exec + char *const *argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; -# if GTEST_OS_MAC -inline char** GetEnviron() { +#if GTEST_OS_MAC +inline char **GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } -# else +#else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. -extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC +extern "C" char **environ; +inline char **GetEnviron() { return environ; } +#endif // GTEST_OS_MAC -# if !GTEST_OS_QNX +#if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. -static int ExecDeathTestChildMain(void* child_arg) { - ExecDeathTestArgs* const args = static_cast(child_arg); +static int ExecDeathTestChildMain(void *child_arg) { + ExecDeathTestArgs *const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. - const char* const original_dir = + const char *const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); + DeathTestAbort(std::string("chdir(\"") + original_dir + + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } @@ -1193,13 +1235,12 @@ static int ExecDeathTestChildMain(void* child_arg) { // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + - original_dir + " failed: " + - GetLastErrnoDescription()); + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } -# endif // !GTEST_OS_QNX +#endif // !GTEST_OS_QNX -# if GTEST_HAS_CLONE +#if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -1209,22 +1250,26 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -static void StackLowerThanAddress(const void* ptr, - bool* result) GTEST_NO_INLINE_; -static void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void *ptr, + bool *result) GTEST_NO_INLINE_; +// HWAddressSanitizer add a random tag to the MSB of the local variable address, +// making comparison result unpredictable. +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +static void StackLowerThanAddress(const void *ptr, bool *result) { int dummy; *result = (&dummy < ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } -# endif // GTEST_HAS_CLONE +#endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -1233,11 +1278,11 @@ static bool StackGrowsDown() { // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. -static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { +static pid_t ExecDeathTestSpawnChild(char *const *argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; -# if GTEST_OS_QNX +#if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); @@ -1246,29 +1291,30 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. - const char* const original_dir = + const char *const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); + DeathTestAbort(std::string("chdir(\"") + original_dir + + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, - fd_flags | FD_CLOEXEC)); - struct inheritance inherit = {0}; + GTEST_DEATH_TEST_CHECK_SYSCALL_( + fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); + struct inheritance inherit = { 0 }; // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + child_pid = + spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); -# else // GTEST_OS_QNX -# if GTEST_OS_LINUX +#else // GTEST_OS_QNX +#if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. @@ -1277,18 +1323,18 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; - GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( - SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); -# endif // GTEST_OS_LINUX + GTEST_DEATH_TEST_CHECK_SYSCALL_( + sigaction(SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); +#endif // GTEST_OS_LINUX -# if GTEST_HAS_CLONE +#if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); + const auto stack_size = static_cast(getpagesize() * 2); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + void *const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); @@ -1299,29 +1345,30 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; - void* const stack_top = - static_cast(stack) + - (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + void *const stack_top = + static_cast(stack) + + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); + GTEST_DEATH_TEST_CHECK_( + static_cast(stack_size) > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } -# else +#else const bool use_fork = true; -# endif // GTEST_HAS_CLONE +#endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { - ExecDeathTestChildMain(&args); - _exit(0); + ExecDeathTestChildMain(&args); + _exit(0); } -# endif // GTEST_OS_QNX -# if GTEST_OS_LINUX +#endif // GTEST_OS_QNX +#if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); -# endif // GTEST_OS_LINUX + sigaction(SIGPROF, &saved_sigprof_action, nullptr)); +#endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; @@ -1332,13 +1379,13 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = + const UnitTestImpl *const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag *const flag = impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); + const TestInfo *const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } @@ -1349,14 +1396,14 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" - + file_ + "|" + StreamableToString(line_) + "|" - + StreamableToString(death_test_index) + "|" - + StreamableToString(pipe_fd[1]); + const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kFilterFlag + "=" + info->test_suite_name() + + "." + info->name(); + const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + + kInternalRunDeathTestFlag + "=" + file_ + + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); @@ -1377,93 +1424,91 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { return OVERSEE_TEST; } -# endif // !GTEST_OS_WINDOWS +#endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, - const char* file, int line, - DeathTest** test) { - UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = +bool DefaultDeathTestFactory::Create(const char *statement, + Matcher matcher, + const char *file, int line, + DeathTest **test) { + UnitTestImpl *const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag *const flag = impl->internal_run_death_test_flag(); - const int death_test_index = impl->current_test_info() - ->increment_death_test_count(); + const int death_test_index = + impl->current_test_info()->increment_death_test_count(); - if (flag != NULL) { + if (flag != nullptr) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( - "Death test count (" + StreamableToString(death_test_index) - + ") somehow exceeded expected maximum (" - + StreamableToString(flag->index()) + ")"); + "Death test count (" + StreamableToString(death_test_index) + + ") somehow exceeded expected maximum (" + + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { - *test = NULL; + *test = nullptr; return true; } } -# if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); + *test = new WindowsDeathTest(statement, std::move(matcher), file, line); } -# elif GTEST_OS_FUCHSIA +#elif GTEST_OS_FUCHSIA if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { - *test = new FuchsiaDeathTest(statement, regex, file, line); + *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); } -# else +#else if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); + *test = new ExecDeathTest(statement, std::move(matcher), file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); + *test = new NoExecDeathTest(statement, std::move(matcher)); } -# endif // GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message( - "Unknown death test style \"" + GTEST_FLAG(death_test_style) - + "\" encountered"); + DeathTest::set_last_death_test_message("Unknown death test style \"" + + GTEST_FLAG(death_test_style) + + "\" encountered"); return false; } return true; } -# if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. static int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t write_handle_as_size_t, - size_t event_handle_as_size_t) { + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, - FALSE, // Non-inheritable. - parent_process_id)); + FALSE, // Non-inheritable. + parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } - // FIXME: Replace the following check with a - // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - const HANDLE write_handle = - reinterpret_cast(write_handle_as_size_t); + const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in the parent @@ -1485,9 +1530,7 @@ static int GetStatusFileDescriptor(unsigned int parent_process_id, HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, - ::GetCurrentProcess(), &dup_event_handle, - 0x0, - FALSE, + ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + @@ -1509,13 +1552,13 @@ static int GetStatusFileDescriptor(unsigned int parent_process_id, return write_fd; } -# endif // GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; +InternalRunDeathTestFlag *ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. @@ -1525,45 +1568,41 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; -# if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; - if (fields.size() != 6 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) - || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || + !ParseNaturalNumber(fields[2], &index) || + !ParseNaturalNumber(fields[3], &parent_process_id) || + !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || + !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } - write_fd = GetStatusFileDescriptor(parent_process_id, - write_handle_as_size_t, + write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); -# elif GTEST_OS_FUCHSIA +#elif GTEST_OS_FUCHSIA - if (fields.size() != 3 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " - + GTEST_FLAG(internal_run_death_test)); + if (fields.size() != 3 || !ParseNaturalNumber(fields[1], &line) || + !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); } -# else +#else - if (fields.size() != 4 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " - + GTEST_FLAG(internal_run_death_test)); + if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || + !ParseNaturalNumber(fields[2], &index) || + !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); } -# endif // GTEST_OS_WINDOWS +#endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-filepath.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-filepath.cc index a7e65c082a..f9427e0f18 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-filepath.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-filepath.cc @@ -34,28 +34,25 @@ #include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE -# include +#include #elif GTEST_OS_WINDOWS -# include -# include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include +#include +#include #else -# include -# include // Some Linux distributions define PATH_MAX here. -#endif // GTEST_OS_WINDOWS_MOBILE +#include +#include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE #include "gtest/internal/gtest-string.h" #if GTEST_OS_WINDOWS -# define GTEST_PATH_MAX_ _MAX_PATH +#define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) -# define GTEST_PATH_MAX_ PATH_MAX +#define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) -# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else -# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { @@ -69,16 +66,16 @@ namespace internal { const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kAlternatePathSeparatorString[] = "/"; -# if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; -# else +#else const char kCurrentDirectoryString[] = ".\\"; -# endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kCurrentDirectoryString[] = "./"; @@ -95,23 +92,24 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT - // Windows CE doesn't have a current directory, so we just return +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 + // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - char* result = getcwd(cwd, sizeof(cwd)); -# if GTEST_OS_NACL + char *result = getcwd(cwd, sizeof(cwd)); +#if GTEST_OS_NACL // getcwd will likely fail in NaCl due to the sandbox, so return something // reasonable. The user may have provided a shim implementation for getcwd, // however, so fallback only when failure is detected. - return FilePath(result == NULL ? kCurrentDirectoryString : cwd); -# endif // GTEST_OS_NACL - return FilePath(result == NULL ? "" : cwd); + return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); +#endif // GTEST_OS_NACL + return FilePath(result == nullptr ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } @@ -119,11 +117,11 @@ FilePath FilePath::GetCurrentDir() { // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. -FilePath FilePath::RemoveExtension(const char* extension) const { +FilePath FilePath::RemoveExtension(const char *extension) const { const std::string dot_extension = std::string(".") + extension; if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { - return FilePath(pathname_.substr( - 0, pathname_.length() - dot_extension.length())); + return FilePath( + pathname_.substr(0, pathname_.length() - dot_extension.length())); } return *this; } @@ -131,13 +129,13 @@ FilePath FilePath::RemoveExtension(const char* extension) const { // Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. -const char* FilePath::FindLastPathSeparator() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); +const char *FilePath::FindLastPathSeparator() const { + const char *const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ - const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + const char *const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { + if (last_alt_sep != nullptr && + (last_sep == nullptr || last_alt_sep > last_sep)) { return last_alt_sep; } #endif @@ -151,7 +149,7 @@ const char* FilePath::FindLastPathSeparator() const { // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = FindLastPathSeparator(); + const char *const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(last_sep + 1) : *this; } @@ -162,10 +160,10 @@ FilePath FilePath::RemoveDirectoryName() const { // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { - const char* const last_sep = FindLastPathSeparator(); + const char *const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); + dir = std::string(c_str(), static_cast(last_sep + 1 - c_str())); } else { dir = kCurrentDirectoryString; } @@ -178,26 +176,24 @@ FilePath FilePath::RemoveFileName() const { // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. -FilePath FilePath::MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension) { +FilePath FilePath::MakeFileName(const FilePath &directory, + const FilePath &base_name, int number, + const char *extension) { std::string file; if (number == 0) { file = base_name.string() + "." + extension; } else { - file = base_name.string() + "_" + StreamableToString(number) - + "." + extension; + file = + base_name.string() + "_" + StreamableToString(number) + "." + extension; } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. -FilePath FilePath::ConcatPaths(const FilePath& directory, - const FilePath& relative_path) { - if (directory.IsEmpty()) - return relative_path; +FilePath FilePath::ConcatPaths(const FilePath &directory, + const FilePath &relative_path) { + if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(dir.string() + kPathSeparator + relative_path.string()); } @@ -208,7 +204,7 @@ bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; + delete[] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; @@ -223,24 +219,24 @@ bool FilePath::DirectoryExists() const { #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). - const FilePath& path(IsRootDirectory() ? *this : - RemoveTrailingPathSeparator()); + const FilePath &path(IsRootDirectory() ? *this + : RemoveTrailingPathSeparator()); #else - const FilePath& path(*this); + const FilePath &path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; + delete[] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; - result = posix::Stat(path.c_str(), &file_stat) == 0 && - posix::IsDir(file_stat); + result = + posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; @@ -250,9 +246,6 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // FIXME: on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); @@ -261,13 +254,12 @@ bool FilePath::IsRootDirectory() const { // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { - const char* const name = pathname_.c_str(); + const char *const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && - ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && - name[1] == ':' && - IsPathSeparator(name[2]); + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif @@ -281,9 +273,9 @@ bool FilePath::IsAbsolutePath() const { // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. -FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension) { +FilePath FilePath::GenerateUniqueFileName(const FilePath &directory, + const FilePath &base_name, + const char *extension) { FilePath full_pathname; int number = 0; do { @@ -324,10 +316,13 @@ bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; - delete [] unicode; + int result = CreateDirectory(unicode, nullptr) ? 0 : -1; + delete[] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); +#elif GTEST_OS_ESP8266 + // do nothing + int result = 0; #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE @@ -342,23 +337,21 @@ bool FilePath::CreateFolder() const { // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { - return IsDirectory() - ? FilePath(pathname_.substr(0, pathname_.length() - 1)) - : *this; + return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1)) + : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// FIXME: handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { + if (pathname_.c_str() == nullptr) { pathname_ = ""; return; } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; + const char *src = pathname_.c_str(); + char *const dest = new char[pathname_.length() + 1]; + char *dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { @@ -371,8 +364,7 @@ void FilePath::Normalize() { *dest_ptr = kPathSeparator; } #endif - while (IsPathSeparator(*src)) - src++; + while (IsPathSeparator(*src)) src++; } dest_ptr++; } diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-internal-inl.h b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-internal-inl.h index 479004149b..16d8cde669 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-internal-inl.h +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-internal-inl.h @@ -35,26 +35,28 @@ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ #ifndef _WIN32_WCE -# include +#include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include +#include +#include #include #include #include "gtest/internal/gtest-port.h" #if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT +#include // NOLINT +#include // NOLINT #endif #if GTEST_OS_WINDOWS -# include // NOLINT -#endif // GTEST_OS_WINDOWS +#include // NOLINT +#endif // GTEST_OS_WINDOWS #include "gtest/gtest.h" #include "gtest/gtest-spi.h" @@ -98,14 +100,14 @@ const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. @@ -121,21 +123,22 @@ GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); +GTEST_API_ bool ParseInt32Flag(const char *str, const char *flag, + int32_t *value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { - const unsigned int raw_seed = (random_seed_flag == 0) ? - static_cast(GetTimeInMillis()) : - static_cast(random_seed_flag); +inline int GetRandomSeedFromFlag(int32_t random_seed_flag) { + const unsigned int raw_seed = + (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) + : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % - static_cast(kMaxRandomSeed)) + 1; + static_cast(kMaxRandomSeed)) + + 1; return normalized_seed; } @@ -212,10 +215,10 @@ class GTestFlagSaver { std::string output_; bool print_time_; bool print_utf8_; - internal::Int32 random_seed_; - internal::Int32 repeat_; + int32_t random_seed_; + int32_t repeat_; bool shuffle_; - internal::Int32 stack_trace_depth_; + int32_t stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; @@ -226,11 +229,11 @@ class GTestFlagSaver { // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". -GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); +GTEST_API_ std::string CodePointToUtf8(uint32_t code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -241,7 +244,7 @@ GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); +GTEST_API_ std::string WideStringToUtf8(const wchar_t *str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this @@ -255,49 +258,49 @@ void WriteToShardStatusFileIfNeeded(); // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. -GTEST_API_ bool ShouldShard(const char* total_shards_str, - const char* shard_index_str, +GTEST_API_ bool ShouldShard(const char *total_shards_str, + const char *shard_index_str, bool in_subprocess_for_death_test); -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and +// Parses the environment variable var as a 32-bit integer. If it is unset, +// returns default_val. If it is not a 32-bit integer, prints an error and // and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); +GTEST_API_ int32_t Int32FromEnvOrDie(const char *env_var, int32_t default_val); // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. -GTEST_API_ bool ShouldRunTestOnShard( - int total_shards, int shard_index, int test_id); +GTEST_API_ bool ShouldRunTestOnShard(int total_shards, int shard_index, + int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template -inline int CountIf(const Container& c, Predicate predicate) { +inline int CountIf(const Container &c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { - if (predicate(*it)) - ++count; + if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template -void ForEach(const Container& c, Functor functor) { +void ForEach(const Container &c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template -inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +inline E GetElementOr(const std::vector &v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value + : v[static_cast(i)]; } // Performs an in-place shuffle of a range of the vector's elements. @@ -305,8 +308,8 @@ inline E GetElementOr(const std::vector& v, int i, E default_value) { // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template -void ShuffleRange(internal::Random* random, int begin, int end, - std::vector* v) { +void ShuffleRange(internal::Random *random, int begin, int end, + std::vector *v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " @@ -319,21 +322,24 @@ void ShuffleRange(internal::Random* random, int begin, int end, // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); + const int selected = + begin + + static_cast(random->Generate(static_cast(range_width))); + std::swap((*v)[static_cast(selected)], + (*v)[static_cast(last_in_range)]); } } // Performs an in-place shuffle of the vector's elements. template -inline void Shuffle(internal::Random* random, std::vector* v) { +inline void Shuffle(internal::Random *random, std::vector *v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template -static void Delete(T* x) { +static void Delete(T *x) { delete x; } @@ -345,10 +351,10 @@ class TestPropertyKeyIs { // Constructor. // // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} + explicit TestPropertyKeyIs(const std::string &key) : key_(key) {} - // Returns true iff the test name of test property matches on key_. - bool operator()(const TestProperty& test_property) const { + // Returns true if and only if the test name of test property matches on key_. + bool operator()(const TestProperty &test_property) const { return test_property.key() == key_; } @@ -380,16 +386,16 @@ class GTEST_API_ UnitTestOptions { // Functions for processing the gtest_filter flag. - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. + // Returns true if and only if the wildcard pattern matches the string. + // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, + // Returns true if and only if the user-specified filter matches the test + // suite name and the test name. + static bool FilterMatchesTest(const std::string &test_suite_name, const std::string &test_name); #if GTEST_OS_WINDOWS @@ -403,7 +409,7 @@ class GTEST_API_ UnitTestOptions { // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". - static bool MatchesFilter(const std::string& name, const char* filter); + static bool MatchesFilter(const std::string &name, const char *filter); }; // Returns the current application's name, removing directory path if that @@ -431,7 +437,7 @@ class OsStackTraceGetterInterface { // This string is inserted in place of stack frames that are part of // Google Test's implementation. - static const char* const kElidedFramesMarker; + static const char *const kElidedFramesMarker; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); @@ -442,8 +448,8 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} - virtual std::string CurrentStackTrace(int max_depth, int skip_count); - virtual void UponLeavingGTest(); + std::string CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; private: #if GTEST_HAS_ABSL @@ -453,7 +459,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to the stack trace code from within the user code. - void* caller_frame_ = nullptr; + void *caller_frame_ = nullptr; #endif // GTEST_HAS_ABSL GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); @@ -461,7 +467,7 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { // Information about a Google Test trace point. struct TraceInfo { - const char* file; + const char *file; int line; std::string message; }; @@ -469,15 +475,15 @@ struct TraceInfo { // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter - : public TestPartResultReporterInterface { + : public TestPartResultReporterInterface { public: - explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl *unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; private: - UnitTestImpl* const unit_test_; + UnitTestImpl *const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; @@ -487,13 +493,13 @@ class DefaultGlobalTestPartResultReporter class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: - explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl *unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; private: - UnitTestImpl* const unit_test_; + UnitTestImpl *const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; @@ -504,7 +510,7 @@ class DefaultPerThreadTestPartResultReporter // proper locking. class GTEST_API_ UnitTestImpl { public: - explicit UnitTestImpl(UnitTest* parent); + explicit UnitTestImpl(UnitTest *parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. @@ -515,35 +521,38 @@ class GTEST_API_ UnitTestImpl { // test part result for the currently running test. // Returns the global test part result reporter. - TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + TestPartResultReporterInterface *GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter); + TestPartResultReporterInterface *reporter); // Returns the test part result reporter for the current thread. - TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + TestPartResultReporterInterface *GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter); + TestPartResultReporterInterface *reporter); - // Gets the number of successful test cases. - int successful_test_case_count() const; + // Gets the number of successful test suites. + int successful_test_suite_count() const; - // Gets the number of failed test cases. - int failed_test_case_count() const; + // Gets the number of failed test suites. + int failed_test_suite_count() const; - // Gets the number of all test cases. - int total_test_case_count() const; + // Gets the number of all test suites. + int total_test_suite_count() const; - // Gets the number of all test cases that contain at least one test + // Gets the number of all test suites that contain at least one test // that should run. - int test_case_to_run_count() const; + int test_suite_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; + // Gets the number of skipped tests. + int skipped_test_count() const; + // Gets the number of failed tests. int failed_test_count() const; @@ -569,50 +578,56 @@ class GTEST_API_ UnitTestImpl { // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns true iff the unit test passed (i.e. all test cases passed). + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). bool Passed() const { return !Failed(); } - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite *GetTestSuite(int i) const { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(i)]; } - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase *GetTestCase(int i) const { return GetTestSuite(i); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite *GetMutableSuiteCase(int i) { + const int index = GetElementOr(test_suite_indices_, i, -1); + return index < 0 ? nullptr : test_suites_[static_cast(index)]; } // Provides access to the event listener list. - TestEventListeners* listeners() { return &listeners_; } + TestEventListeners *listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. - TestResult* current_test_result(); + TestResult *current_test_result(); // Returns the TestResult for the ad hoc test. - const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + const TestResult *ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. - void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + void set_os_stack_trace_getter(OsStackTraceGetterInterface *getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. - OsStackTraceGetterInterface* os_stack_trace_getter(); + OsStackTraceGetterInterface *os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // @@ -626,31 +641,39 @@ class GTEST_API_ UnitTestImpl { // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - // Finds and returns a TestCase with the given name. If one doesn't + // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // - // test_case_name: name of the test case + // test_suite_name: name of the test suite // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite *GetTestSuite(const char *test_suite_name, const char *type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + TestCase *GetTestCase(const char *test_case_name, const char *type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); + } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Adds a TestInfo to the unit test. // // Arguments: // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - TestInfo* test_info) { + void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, + TestInfo *test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as @@ -664,32 +687,42 @@ class GTEST_API_ UnitTestImpl { << "Failed to get the current working directory."; } - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); + GetTestSuite(test_info->test_suite_name(), test_info->type_param(), + set_up_tc, tear_down_tc) + ->AddTestInfo(test_info); } - // Returns ParameterizedTestCaseRegistry object used to keep track of + // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + internal::ParameterizedTestSuiteRegistry ¶meterized_test_registry() { return parameterized_test_registry_; } - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; + std::set *ignored_parameterized_test_suites() { + return &ignored_parameterized_test_suites_; + } + + // Returns TypeParameterizedTestSuiteRegistry object used to keep track of + // type-parameterized tests and instantiations of them. + internal::TypeParameterizedTestSuiteRegistry & + type_parameterized_test_registry() { + return type_parameterized_test_registry_; + } + + // Sets the TestSuite object for the test that's currently running. + void set_current_test_suite(TestSuite *a_current_test_suite) { + current_test_suite_ = a_current_test_suite; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. - void set_current_test_info(TestInfo* a_current_test_info) { + void set_current_test_info(TestInfo *a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is @@ -704,28 +737,23 @@ class GTEST_API_ UnitTestImpl { // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); + ForEach(test_suites_, TestSuite::ClearTestSuiteResult); } // Clears the results of ad-hoc test assertions. - void ClearAdHocTestResult() { - ad_hoc_test_result_.Clear(); - } + void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the + // context of a test or a test suite, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. - void RecordProperty(const TestProperty& test_property); + void RecordProperty(const TestProperty &test_property); - enum ReactionToSharding { - HONOR_SHARDING_PROTOCOL, - IGNORE_SHARDING_PROTOCOL - }; + enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. + // result in each TestSuite and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. @@ -734,19 +762,19 @@ class GTEST_API_ UnitTestImpl { // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); - const TestCase* current_test_case() const { return current_test_case_; } - TestInfo* current_test_info() { return current_test_info_; } - const TestInfo* current_test_info() const { return current_test_info_; } + const TestSuite *current_test_suite() const { return current_test_suite_; } + TestInfo *current_test_info() { return current_test_info_; } + const TestInfo *current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. - std::vector& environments() { return environments_; } + std::vector &environments() { return environments_; } // Getters for the per-thread Google Test trace stack. - std::vector& gtest_trace_stack() { + std::vector >est_trace_stack() { return *(gtest_trace_stack_.pointer()); } - const std::vector& gtest_trace_stack() const { + const std::vector >est_trace_stack() const { return gtest_trace_stack_.get(); } @@ -758,12 +786,12 @@ class GTEST_API_ UnitTestImpl { // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. - const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + const InternalRunDeathTestFlag *internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. - internal::DeathTestFactory* death_test_factory() { + internal::DeathTestFactory *death_test_factory() { return death_test_factory_.get(); } @@ -793,13 +821,13 @@ class GTEST_API_ UnitTestImpl { int random_seed() const { return random_seed_; } // Gets the random number generator. - internal::Random* random() { return &random_; } + internal::Random *random() { return &random_; } - // Shuffles all test cases, and the tests within each test case, + // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void ShuffleTests(); - // Restores the test cases and tests to their order before the first shuffle. + // Restores the test suites and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment @@ -814,7 +842,7 @@ class GTEST_API_ UnitTestImpl { void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. - UnitTest* const parent_; + UnitTest *const parent_; // The working directory when the first TEST() or TEST_F() was // executed. @@ -826,50 +854,56 @@ class GTEST_API_ UnitTestImpl { default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. - TestPartResultReporterInterface* global_test_part_result_repoter_; + TestPartResultReporterInterface *global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. - internal::ThreadLocal + internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. - std::vector environments_; + std::vector environments_; - // The vector of TestCases in their original order. It owns the + // The vector of TestSuites in their original order. It owns the // elements in the vector. - std::vector test_cases_; + std::vector test_suites_; - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the + // Provides a level of indirection for the test suite list to allow + // easy shuffling and restoring the test suite order. The i-th + // element of this vector is the index of the i-th test suite in the // shuffled order. - std::vector test_case_indices_; + std::vector test_suite_indices_; // ParameterizedTestRegistry object used to register value-parameterized // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; + internal::TypeParameterizedTestSuiteRegistry + type_parameterized_test_registry_; + + // The set holding the name of parameterized + // test suites that may go uninstantiated. + std::set ignored_parameterized_test_suites_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; + // Index of the last death test suite registered. Initially -1. + int last_death_test_suite_; - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. + // This points to the TestSuite for the currently running test. It + // changes as Google Test goes through one test suite after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; + TestSuite *current_test_suite_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. - TestInfo* current_test_info_; + TestInfo *current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google @@ -889,9 +923,9 @@ class GTEST_API_ UnitTestImpl { // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. - OsStackTraceGetterInterface* os_stack_trace_getter_; + OsStackTraceGetterInterface *os_stack_trace_getter_; - // True iff PostFlagParsingInit() has been called. + // True if and only if PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. @@ -910,8 +944,8 @@ class GTEST_API_ UnitTestImpl { #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; + std::unique_ptr internal_run_death_test_flag_; + std::unique_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. @@ -926,7 +960,7 @@ class GTEST_API_ UnitTestImpl { // Convenience function for accessing the global UnitTest // implementation object. -inline UnitTestImpl* GetUnitTestImpl() { +inline UnitTestImpl *GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } @@ -934,7 +968,7 @@ inline UnitTestImpl* GetUnitTestImpl() { // Internal helper functions for implementing the simple regular // expression matcher. -GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsInSet(char ch, const char *str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); @@ -942,18 +976,19 @@ GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ bool ValidateRegex(const char* regex); -GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); -GTEST_API_ bool MatchRepetitionAndRegexAtHead( - bool escaped, char ch, char repeat, const char* regex, const char* str); -GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); +GTEST_API_ bool ValidateRegex(const char *regex); +GTEST_API_ bool MatchRegexAtHead(const char *regex, const char *str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead(bool escaped, char ch, + char repeat, const char *regex, + const char *str); +GTEST_API_ bool MatchRegexAnywhere(const char *regex, const char *str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int *argc, char **argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int *argc, wchar_t **argv); #if GTEST_HAS_DEATH_TEST @@ -966,7 +1001,7 @@ GTEST_API_ std::string GetLastErrnoDescription(); // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template -bool ParseNaturalNumber(const ::std::string& str, Integer* number) { +bool ParseNaturalNumber(const ::std::string &str, Integer *number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. @@ -975,27 +1010,14 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { } errno = 0; - char* end; + char *end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. + using BiggestConvertible = unsigned long long; // NOLINT -# if GTEST_OS_WINDOWS && !defined(__GNUC__) - - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); - -# else - - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); - -# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); // NOLINT const bool parse_success = *end == '\0' && errno == 0; - // FIXME: Convert this to compile time assertion when it is - // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); @@ -1015,18 +1037,18 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: - static void RecordProperty(TestResult* test_result, - const std::string& xml_element, - const TestProperty& property) { + static void RecordProperty(TestResult *test_result, + const std::string &xml_element, + const TestProperty &property) { test_result->RecordProperty(xml_element, property); } - static void ClearTestPartResults(TestResult* test_result) { + static void ClearTestPartResults(TestResult *test_result) { test_result->ClearTestPartResults(); } - static const std::vector& test_part_results( - const TestResult& test_result) { + static const std::vector &test_part_results( + const TestResult &test_result) { return test_result.test_part_results(); } }; @@ -1042,38 +1064,36 @@ class StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const std::string& message) = 0; + virtual void Send(const std::string &message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const std::string& message) { Send(message + "\n"); } + void SendLn(const std::string &message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const std::string& host, const std::string& port) + SocketWriter(const std::string &host, const std::string &port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } - virtual ~SocketWriter() { - if (sockfd_ != -1) - CloseConnection(); + ~SocketWriter() override { + if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. - virtual void Send(const std::string& message) { + void Send(const std::string &message) override { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { - GTEST_LOG_(WARNING) - << "stream_result_to: failed to stream to " - << host_name_ << ":" << port_num_; + const auto len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != static_cast(len)) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; } } @@ -1082,7 +1102,7 @@ class StreamingListener : public EmptyTestEventListener { void MakeConnection(); // Closes the socket. - void CloseConnection() { + void CloseConnection() override { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; @@ -1098,21 +1118,23 @@ class StreamingListener : public EmptyTestEventListener { }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static std::string UrlEncode(const char* str); + static std::string UrlEncode(const char *str); - StreamingListener(const std::string& host, const std::string& port) + StreamingListener(const std::string &host, const std::string &port) : socket_writer_(new SocketWriter(host, port)) { Start(); } - explicit StreamingListener(AbstractSocketWriter* socket_writer) - : socket_writer_(socket_writer) { Start(); } + explicit StreamingListener(AbstractSocketWriter *socket_writer) + : socket_writer_(socket_writer) { + Start(); + } - void OnTestProgramStart(const UnitTest& /* unit_test */) { + void OnTestProgramStart(const UnitTest & /* unit_test */) override { SendLn("event=TestProgramStart"); } - void OnTestProgramEnd(const UnitTest& unit_test) { + void OnTestProgramEnd(const UnitTest &unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); @@ -1121,42 +1143,46 @@ class StreamingListener : public EmptyTestEventListener { socket_writer_->CloseConnection(); } - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + void OnTestIterationStart(const UnitTest & /* unit_test */, + int iteration) override { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - SendLn("event=TestIterationEnd&passed=" + - FormatBool(unit_test.Passed()) + "&elapsed_time=" + - StreamableToString(unit_test.elapsed_time()) + "ms"); + void OnTestIterationEnd(const UnitTest &unit_test, + int /* iteration */) override { + SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + + "ms"); } - void OnTestCaseStart(const TestCase& test_case) { + // Note that "event=TestCaseStart" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseStart(const TestCase &test_case) override { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); + // Note that "event=TestCaseEnd" is a wire format and has to remain + // "case" for compatibilty + void OnTestCaseEnd(const TestCase &test_case) override { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); } - void OnTestStart(const TestInfo& test_info) { + void OnTestStart(const TestInfo &test_info) override { SendLn(std::string("event=TestStart&name=") + test_info.name()); } - void OnTestEnd(const TestInfo& test_info) { + void OnTestEnd(const TestInfo &test_info) override { SendLn("event=TestEnd&passed=" + - FormatBool((test_info.result())->Passed()) + - "&elapsed_time=" + + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } - void OnTestPartResult(const TestPartResult& test_part_result) { - const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; + void OnTestPartResult(const TestPartResult &test_part_result) override { + const char *file_name = test_part_result.file_name(); + if (file_name == nullptr) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); @@ -1164,7 +1190,7 @@ class StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const std::string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string &message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. @@ -1172,7 +1198,7 @@ class StreamingListener : public EmptyTestEventListener { std::string FormatBool(bool value) { return value ? "1" : "0"; } - const scoped_ptr socket_writer_; + const std::unique_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-matchers.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-matchers.cc new file mode 100644 index 0000000000..27aaa2b7c5 --- /dev/null +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-matchers.cc @@ -0,0 +1,97 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-matchers.h" + +#include + +namespace testing { + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const std::string &s) { *this = Eq(s); } + +// Constructs a matcher that matches a const std::string& whose value is +// equal to s. +Matcher::Matcher(const char *s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const std::string &s) { *this = Eq(s); } + +// Constructs a matcher that matches a std::string whose value is equal to +// s. +Matcher::Matcher(const char *s) { *this = Eq(std::string(s)); } + +#if GTEST_INTERNAL_HAS_STRING_VIEW +// Constructs a matcher that matches a const StringView& whose value is +// equal to s. +Matcher::Matcher(const std::string &s) { + *this = Eq(s); +} + +// Constructs a matcher that matches a const StringView& whose value is +// equal to s. +Matcher::Matcher(const char *s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a const StringView& whose value is +// equal to s. +Matcher::Matcher(internal::StringView s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a StringView whose value is equal to +// s. +Matcher::Matcher(const std::string &s) { *this = Eq(s); } + +// Constructs a matcher that matches a StringView whose value is equal to +// s. +Matcher::Matcher(const char *s) { + *this = Eq(std::string(s)); +} + +// Constructs a matcher that matches a StringView whose value is equal to +// s. +Matcher::Matcher(internal::StringView s) { + *this = Eq(std::string(s)); +} +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + +} // namespace testing diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-port.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-port.cc index fecb5d11c2..adfdbef9c6 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-port.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-port.cc @@ -27,44 +27,56 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - #include "gtest/internal/gtest-port.h" #include -#include #include +#include #include +#include #include +#include #if GTEST_OS_WINDOWS -# include -# include -# include -# include // Used in ThreadLocal. +#include +#include +#include +#include // Used in ThreadLocal. +#ifdef _MSC_VER +#include +#endif // _MSC_VER #else -# include +#include #endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC -# include -# include -# include +#include +#include +#include #endif // GTEST_OS_MAC +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_OPENBSD +#include +#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#include +#endif +#endif + #if GTEST_OS_QNX -# include -# include -# include +#include +#include +#include #endif // GTEST_OS_QNX #if GTEST_OS_AIX -# include -# include +#include +#include #endif // GTEST_OS_AIX #if GTEST_OS_FUCHSIA -# include -# include +#include +#include #endif // GTEST_OS_FUCHSIA #include "gtest/gtest-spi.h" @@ -89,7 +101,7 @@ const int kStdErrFileno = STDERR_FILENO; namespace { template -T ReadProcFileField(const std::string& filename, int field) { +T ReadProcFileField(const std::string &filename, int field) { std::string dummy; std::ifstream file(filename.c_str()); while (field-- > 0) { @@ -105,7 +117,7 @@ T ReadProcFileField(const std::string& filename, int field) { size_t GetThreadCount() { const std::string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); - return ReadProcFileField(filename, 19); + return ReadProcFileField(filename, 19); } #elif GTEST_OS_MAC @@ -118,8 +130,7 @@ size_t GetThreadCount() { if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. - vm_deallocate(task, - reinterpret_cast(thread_list), + vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { @@ -127,6 +138,80 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ + GTEST_OS_NETBSD + +#if GTEST_OS_NETBSD +#undef KERN_PROC +#define KERN_PROC KERN_PROC2 +#define kinfo_proc kinfo_proc2 +#endif + +#if GTEST_OS_DRAGONFLY +#define KP_NLWP(kp) (kp.kp_nthreads) +#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD +#define KP_NLWP(kp) (kp.ki_numthreads) +#elif GTEST_OS_NETBSD +#define KP_NLWP(kp) (kp.p_nlwps) +#endif + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID, + getpid(), +#if GTEST_OS_NETBSD + sizeof(struct kinfo_proc), + 1, +#endif + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + struct kinfo_proc info; + size_t size = sizeof(info); + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + return static_cast(KP_NLWP(info)); +} +#elif GTEST_OS_OPENBSD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + int mib[] = { + CTL_KERN, + KERN_PROC, + KERN_PROC_PID | KERN_PROC_SHOW_THREADS, + getpid(), + sizeof(struct kinfo_proc), + 0, + }; + u_int miblen = sizeof(mib) / sizeof(mib[0]); + + // get number of structs + size_t size; + if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { + return 0; + } + mib[5] = size / mib[4]; + + // populate array of structs + struct kinfo_proc info[mib[5]]; + if (sysctl(mib, miblen, &info, &size, NULL, 0)) { + return 0; + } + + // exclude empty members + int nthreads = 0; + for (int i = 0; i < size / mib[4]; i++) { + if (info[i].p_tid != -1) nthreads++; + } + return nthreads; +} + #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that @@ -138,7 +223,7 @@ size_t GetThreadCount() { } procfs_info process_info; const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); @@ -152,7 +237,7 @@ size_t GetThreadCount() { size_t GetThreadCount() { struct procentry64 entry; pid_t pid = getpid(); - int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1); + int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); if (status == 1) { return entry.pi_thcount; } else { @@ -165,13 +250,9 @@ size_t GetThreadCount() { size_t GetThreadCount() { int dummy_buffer; size_t avail; - zx_status_t status = zx_object_get_info( - zx_process_self(), - ZX_INFO_PROCESS_THREADS, - &dummy_buffer, - 0, - nullptr, - &avail); + zx_status_t status = + zx_object_get_info(zx_process_self(), ZX_INFO_PROCESS_THREADS, + &dummy_buffer, 0, nullptr, &avail); if (status == ZX_OK) { return avail; } else { @@ -191,27 +272,17 @@ size_t GetThreadCount() { #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS -void SleepMilliseconds(int n) { - ::Sleep(n); -} +void SleepMilliseconds(int n) { ::Sleep(static_cast(n)); } -AutoHandle::AutoHandle() - : handle_(INVALID_HANDLE_VALUE) {} +AutoHandle::AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} -AutoHandle::AutoHandle(Handle handle) - : handle_(handle) {} +AutoHandle::AutoHandle(Handle handle) : handle_(handle) {} -AutoHandle::~AutoHandle() { - Reset(); -} +AutoHandle::~AutoHandle() { Reset(); } -AutoHandle::Handle AutoHandle::Get() const { - return handle_; -} +AutoHandle::Handle AutoHandle::Get() const { return handle_; } -void AutoHandle::Reset() { - Reset(INVALID_HANDLE_VALUE); -} +void AutoHandle::Reset() { Reset(INVALID_HANDLE_VALUE); } void AutoHandle::Reset(HANDLE handle) { // Resetting with the same handle we already own is invalid. @@ -223,37 +294,32 @@ void AutoHandle::Reset(HANDLE handle) { } else { GTEST_CHECK_(!IsCloseable()) << "Resetting a valid handle to itself is likely a programmer error " - "and thus not allowed."; + "and thus not allowed."; } } bool AutoHandle::IsCloseable() const { // Different Windows APIs may use either of these values to represent an // invalid handle. - return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; + return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; } Notification::Notification() - : event_(::CreateEvent(NULL, // Default security attributes. - TRUE, // Do not reset automatically. - FALSE, // Initially unset. - NULL)) { // Anonymous event. - GTEST_CHECK_(event_.Get() != NULL); + : event_(::CreateEvent(nullptr, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + nullptr)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != nullptr); } -void Notification::Notify() { - GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); -} +void Notification::Notify() { GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); } void Notification::WaitForNotification() { - GTEST_CHECK_( - ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); + GTEST_CHECK_(::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); } Mutex::Mutex() - : owner_thread_id_(0), - type_(kDynamic), - critical_section_init_phase_(0), + : owner_thread_id_(0), type_(kDynamic), critical_section_init_phase_(0), critical_section_(new CRITICAL_SECTION) { ::InitializeCriticalSection(critical_section_); } @@ -261,13 +327,10 @@ Mutex::Mutex() Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. - // FIXME: Switch to Slim Reader/Writer (SRW) Locks, which requires - // nothing to clean it up but is available only on Vista and later. - // https://docs.microsoft.com/en-us/windows/desktop/Sync/slim-reader-writer--srw--locks if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; - critical_section_ = NULL; + critical_section_ = nullptr; } } @@ -296,6 +359,7 @@ void Mutex::AssertHeld() { namespace { +#ifdef _MSC_VER // Use the RAII idiom to flag mem allocs that are intentionally never // deallocated. The motivation is to silence the false positive mem leaks // that are reported by the debug version of MS's CRT which can only detect @@ -304,23 +368,18 @@ namespace { // MemoryIsNotDeallocated memory_is_not_deallocated; // critical_section_ = new CRITICAL_SECTION; // -class MemoryIsNotDeallocated -{ +class MemoryIsNotDeallocated { public: MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { -#ifdef _MSC_VER old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT // doesn't report mem leak if there's no matching deallocation. _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); -#endif // _MSC_VER } ~MemoryIsNotDeallocated() { -#ifdef _MSC_VER // Restore the original _CRTDBG_ALLOC_MEM_DF flag _CrtSetDbgFlag(old_crtdbg_flag_); -#endif // _MSC_VER } private: @@ -328,6 +387,7 @@ class MemoryIsNotDeallocated GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); }; +#endif // _MSC_VER } // namespace @@ -343,21 +403,21 @@ void Mutex::ThreadSafeLazyInit() { owner_thread_id_ = 0; { // Use RAII to flag that following mem alloc is never deallocated. +#ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER critical_section_ = new CRITICAL_SECTION; } ::InitializeCriticalSection(critical_section_); // Updates the critical_section_init_phase_ to 2 to signal // initialization complete. - GTEST_CHECK_(::InterlockedCompareExchange( - &critical_section_init_phase_, 2L, 1L) == - 1L); + GTEST_CHECK_(::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, 1L) == 1L); break; case 1: // Somebody else is already initializing the mutex; spin until they // are done. - while (::InterlockedCompareExchange(&critical_section_init_phase_, - 2L, + while (::InterlockedCompareExchange(&critical_section_init_phase_, 2L, 2L) != 2L) { // Possibly yields the rest of the thread's time slice to other // threads. @@ -365,8 +425,7 @@ void Mutex::ThreadSafeLazyInit() { } break; - case 2: - break; // The mutex is already initialized and ready for use. + case 2: break; // The mutex is already initialized and ready for use. default: GTEST_CHECK_(false) @@ -380,21 +439,20 @@ namespace { class ThreadWithParamSupport : public ThreadWithParamBase { public: - static HANDLE CreateThread(Runnable* runnable, - Notification* thread_can_start) { - ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + static HANDLE CreateThread(Runnable *runnable, + Notification *thread_can_start) { + ThreadMainParam *param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; - // FIXME: Consider to use _beginthreadex instead. HANDLE thread_handle = ::CreateThread( - NULL, // Default security. - 0, // Default stack size. + nullptr, // Default security. + 0, // Default stack size. &ThreadWithParamSupport::ThreadMain, - param, // Parameter to ThreadMainStatic - 0x0, // Default creation flags. + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. &thread_id); // Need a valid pointer for the call to work under Win98. - GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " - << ::GetLastError() << "."; - if (thread_handle == NULL) { + GTEST_CHECK_(thread_handle != nullptr) + << "CreateThread failed with error " << ::GetLastError() << "."; + if (thread_handle == nullptr) { delete param; } return thread_handle; @@ -402,19 +460,17 @@ class ThreadWithParamSupport : public ThreadWithParamBase { private: struct ThreadMainParam { - ThreadMainParam(Runnable* runnable, Notification* thread_can_start) - : runnable_(runnable), - thread_can_start_(thread_can_start) { - } - scoped_ptr runnable_; + ThreadMainParam(Runnable *runnable, Notification *thread_can_start) + : runnable_(runnable), thread_can_start_(thread_can_start) {} + std::unique_ptr runnable_; // Does not own. - Notification* thread_can_start_; + Notification *thread_can_start_; }; - static DWORD WINAPI ThreadMain(void* ptr) { + static DWORD WINAPI ThreadMain(void *ptr) { // Transfers ownership. - scoped_ptr param(static_cast(ptr)); - if (param->thread_can_start_ != NULL) + std::unique_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != nullptr) param->thread_can_start_->WaitForNotification(); param->runnable_->Run(); return 0; @@ -429,14 +485,11 @@ class ThreadWithParamSupport : public ThreadWithParamBase { } // namespace ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, - Notification* thread_can_start) - : thread_(ThreadWithParamSupport::CreateThread(runnable, - thread_can_start)) { -} + Notification *thread_can_start) + : thread_( + ThreadWithParamSupport::CreateThread(runnable, thread_can_start)) {} -ThreadWithParamBase::~ThreadWithParamBase() { - Join(); -} +ThreadWithParamBase::~ThreadWithParamBase() { Join(); } void ThreadWithParamBase::Join() { GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) @@ -451,20 +504,25 @@ class ThreadLocalRegistryImpl { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. - static ThreadLocalValueHolderBase* GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance) { + static ThreadLocalValueHolderBase *GetValueOnCurrentThread( + const ThreadLocalBase *thread_local_instance) { +#ifdef _MSC_VER + MemoryIsNotDeallocated memory_is_not_deallocated; +#endif // _MSC_VER DWORD current_thread = ::GetCurrentThreadId(); MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = + ThreadIdToThreadLocals *const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(current_thread); if (thread_local_pos == thread_to_thread_locals->end()) { - thread_local_pos = thread_to_thread_locals->insert( - std::make_pair(current_thread, ThreadLocalValues())).first; + thread_local_pos = + thread_to_thread_locals + ->insert(std::make_pair(current_thread, ThreadLocalValues())) + .first; StartWatcherThreadFor(current_thread); } - ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues &thread_local_values = thread_local_pos->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos == thread_local_values.end()) { @@ -472,7 +530,7 @@ class ThreadLocalRegistryImpl { thread_local_values .insert(std::make_pair( thread_local_instance, - linked_ptr( + std::shared_ptr( thread_local_instance->NewValueForCurrentThread()))) .first; } @@ -480,19 +538,18 @@ class ThreadLocalRegistryImpl { } static void OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance) { - std::vector > value_holders; + const ThreadLocalBase *thread_local_instance) { + std::vector > value_holders; // Clean up the ThreadLocalValues data structure while holding the lock, but // defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = + ThreadIdToThreadLocals *const thread_to_thread_locals = GetThreadLocalsMapLocked(); for (ThreadIdToThreadLocals::iterator it = - thread_to_thread_locals->begin(); - it != thread_to_thread_locals->end(); - ++it) { - ThreadLocalValues& thread_local_values = it->second; + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); ++it) { + ThreadLocalValues &thread_local_values = it->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos != thread_local_values.end()) { @@ -509,21 +566,20 @@ class ThreadLocalRegistryImpl { static void OnThreadExit(DWORD thread_id) { GTEST_CHECK_(thread_id != 0) << ::GetLastError(); - std::vector > value_holders; + std::vector > value_holders; // Clean up the ThreadIdToThreadLocals data structure while holding the // lock, but defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); - ThreadIdToThreadLocals* const thread_to_thread_locals = + ThreadIdToThreadLocals *const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(thread_id); if (thread_local_pos != thread_to_thread_locals->end()) { - ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues &thread_local_values = thread_local_pos->second; for (ThreadLocalValues::iterator value_pos = - thread_local_values.begin(); - value_pos != thread_local_values.end(); - ++value_pos) { + thread_local_values.begin(); + value_pos != thread_local_values.end(); ++value_pos) { value_holders.push_back(value_pos->second); } thread_to_thread_locals->erase(thread_local_pos); @@ -535,8 +591,9 @@ class ThreadLocalRegistryImpl { private: // In a particular thread, maps a ThreadLocal object to its value. - typedef std::map > ThreadLocalValues; + typedef std::map > + ThreadLocalValues; // Stores all ThreadIdToThreadLocals having values in a thread, indexed by // thread's ID. typedef std::map ThreadIdToThreadLocals; @@ -548,21 +605,19 @@ class ThreadLocalRegistryImpl { static void StartWatcherThreadFor(DWORD thread_id) { // The returned handle will be kept in thread_map and closed by // watcher_thread in WatcherThreadFunc. - HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, - FALSE, - thread_id); - GTEST_CHECK_(thread != NULL); + HANDLE thread = + ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id); + GTEST_CHECK_(thread != nullptr); // We need to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( - NULL, // Default security. - 0, // Default stack size + nullptr, // Default security. + 0, // Default stack size &ThreadLocalRegistryImpl::WatcherThreadFunc, reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), - CREATE_SUSPENDED, - &watcher_thread_id); - GTEST_CHECK_(watcher_thread != NULL); + CREATE_SUSPENDED, &watcher_thread_id); + GTEST_CHECK_(watcher_thread != nullptr); // Give the watcher thread the same priority as ours to avoid being // blocked by it. ::SetThreadPriority(watcher_thread, @@ -574,10 +629,9 @@ class ThreadLocalRegistryImpl { // Monitors exit from a given thread and notifies those // ThreadIdToThreadLocals about thread termination. static DWORD WINAPI WatcherThreadFunc(LPVOID param) { - const ThreadIdAndHandle* tah = - reinterpret_cast(param); - GTEST_CHECK_( - ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + const ThreadIdAndHandle *tah = + reinterpret_cast(param); + GTEST_CHECK_(::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); OnThreadExit(tah->first); ::CloseHandle(tah->second); delete tah; @@ -585,10 +639,12 @@ class ThreadLocalRegistryImpl { } // Returns map of thread local instances. - static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + static ThreadIdToThreadLocals *GetThreadLocalsMapLocked() { mutex_.AssertHeld(); +#ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; - static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); +#endif // _MSC_VER + static ThreadIdToThreadLocals *map = new ThreadIdToThreadLocals(); return map; } @@ -601,14 +657,14 @@ class ThreadLocalRegistryImpl { Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); -ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( - const ThreadLocalBase* thread_local_instance) { +ThreadLocalValueHolderBase *ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase *thread_local_instance) { return ThreadLocalRegistryImpl::GetValueOnCurrentThread( thread_local_instance); } void ThreadLocalRegistry::OnThreadLocalDestroyed( - const ThreadLocalBase* thread_local_instance) { + const ThreadLocalBase *thread_local_instance) { ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); } @@ -627,20 +683,20 @@ RE::~RE() { regfree(&partial_regex_); regfree(&full_regex_); } - free(const_cast(pattern_)); + free(const_cast(pattern_)); } -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { +// Returns true if and only if regular expression re matches the entire str. +bool RE::FullMatch(const char *str, const RE &re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). +bool RE::PartialMatch(const char *str, const RE &re) { if (!re.is_valid_) return false; regmatch_t match; @@ -648,13 +704,13 @@ bool RE::PartialMatch(const char* str, const RE& re) { } // Initializes an RE from its string representation. -void RE::Init(const char* regex) { +void RE::Init(const char *regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; - char* const full_pattern = new char[full_regex_len]; + char *const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; @@ -667,7 +723,7 @@ void RE::Init(const char* regex) { // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { - const char* const partial_regex = (*regex == '\0') ? "()" : regex; + const char *const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) @@ -679,14 +735,14 @@ void RE::Init(const char* regex) { #elif GTEST_USES_SIMPLE_RE -// Returns true iff ch appears anywhere in str (excluding the +// Returns true if and only if ch appears anywhere in str (excluding the // terminating '\0' character). -bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; +bool IsInSet(char ch, const char *str) { + return ch != '\0' && strchr(str, ch) != nullptr; } -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the +// Returns true if and only if ch belongs to the given classification. +// Unlike similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { @@ -696,16 +752,16 @@ bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_'; + ('0' <= ch && ch <= '9') || ch == '_'; } -// Returns true iff "\\c" is a supported escape sequence. +// Returns true if and only if "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. +// Returns true if and only if the given atom (specified by escaped and +// pattern) matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { @@ -728,25 +784,23 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -static std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char *regex, int index) { return (Message() << "Syntax error at index " << index - << " in simple regular expression \"" << regex << "\": ").GetString(); + << " in simple regular expression \"" << regex << "\": ") + .GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. -bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // FIXME: fix the source file location in the - // assertion failures to match where the regex is used in user - // code. +bool ValidateRegex(const char *regex) { + if (regex == nullptr) { ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; - // True iff ?, *, or + can follow the previous atom. + // True if and only if ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence @@ -775,12 +829,12 @@ bool ValidateRegex(const char* regex) { << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' is unsupported."; + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch + << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' can only follow a repeatable token."; + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch + << "' can only follow a repeatable token."; is_valid = false; } @@ -798,12 +852,10 @@ bool ValidateRegex(const char* regex) { // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. -bool MatchRepetitionAndRegexAtHead( - bool escaped, char c, char repeat, const char* regex, - const char* str) { +bool MatchRepetitionAndRegexAtHead(bool escaped, char c, char repeat, + const char *regex, const char *str) { const size_t min_count = (repeat == '+') ? 1 : 0; - const size_t max_count = (repeat == '?') ? 1 : - static_cast(-1) - 1; + const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. @@ -816,62 +868,56 @@ bool MatchRepetitionAndRegexAtHead( // greedy match. return true; } - if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) - return false; + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the +// Returns true if and only if regex matches a prefix of str. regex must +// be a valid simple regular expression and not start with "^", or the // result is undefined. -bool MatchRegexAtHead(const char* regex, const char* str) { +bool MatchRegexAtHead(const char *regex, const char *str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. - if (*regex == '$') - return *str == '\0'; + if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; - if (escaped) - ++regex; + if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. - return MatchRepetitionAndRegexAtHead( - escaped, regex[0], regex[1], regex + 2, str); + return MatchRepetitionAndRegexAtHead(escaped, regex[0], regex[1], regex + 2, + str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && - MatchRegexAtHead(regex + 1, str + 1); + MatchRegexAtHead(regex + 1, str + 1); } } -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. +// Returns true if and only if regex matches any substring of str. regex must +// be a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). -bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; +bool MatchRegexAnywhere(const char *regex, const char *str) { + if (regex == nullptr || str == nullptr) return false; - if (*regex == '^') - return MatchRegexAtHead(regex + 1, str); + if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { - if (MatchRegexAtHead(regex, str)) - return true; + if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } @@ -879,25 +925,25 @@ bool MatchRegexAnywhere(const char* regex, const char* str) { // Implements the RE class. RE::~RE() { - free(const_cast(pattern_)); - free(const_cast(full_pattern_)); + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); } -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { +// Returns true if and only if regular expression re matches the entire str. +bool RE::FullMatch(const char *str, const RE &re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { +// Returns true if and only if regular expression re matches a substring of +// str (including str itself). +bool RE::PartialMatch(const char *str, const RE &re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { +void RE::Init(const char *regex) { + pattern_ = full_pattern_ = nullptr; + if (regex != nullptr) { pattern_ = posix::StrDup(regex); } @@ -911,7 +957,7 @@ void RE::Init(const char* regex) { // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. - char* buffer = static_cast(malloc(len + 3)); + char *buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') @@ -934,8 +980,8 @@ const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); +GTEST_API_ ::std::string FormatFileLocation(const char *file, int line) { + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) { return file_name + ":"; @@ -952,9 +998,9 @@ GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { // FormatFileLocation in order to contrast the two functions. // Note that FormatCompilerIndependentFileLocation() does NOT append colon // to the file location it produces, unlike FormatFileLocation(). -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( - const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char *file, + int line) { + const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) return file_name; @@ -962,14 +1008,17 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( return file_name + ":" + StreamableToString(line); } -GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) +GTestLog::GTestLog(GTestLogSeverity severity, const char *file, int line) : severity_(severity) { - const char* const marker = - severity == GTEST_INFO ? "[ INFO ]" : - severity == GTEST_WARNING ? "[WARNING]" : - severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - GetStream() << ::std::endl << marker << " " - << FormatFileLocation(file, line).c_str() << ": "; + const char *const marker = + severity == GTEST_INFO + ? "[ INFO ]" + : severity == GTEST_WARNING + ? "[WARNING]" + : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl + << marker << " " << FormatFileLocation(file, line).c_str() + << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. @@ -992,27 +1041,26 @@ class CapturedStream { public: // The ctor redirects the stream to a temporary file. explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { -# if GTEST_OS_WINDOWS - char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT +#if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - const UINT success = ::GetTempFileNameA(temp_dir_path, - "gtest_redir", + const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); - GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " - << temp_file_path; + GTEST_CHECK_(captured_fd != -1) + << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; -# else +#else // There's no guarantee that a test has write access to the current // directory, so we create the temporary file in the /tmp directory // instead. We use /tmp on most systems, and /sdcard on Android. // That's because Android doesn't have /tmp. -# if GTEST_OS_LINUX_ANDROID +#if GTEST_OS_LINUX_ANDROID // Note: Android applications are expected to call the framework's // Context.getExternalStorageDirectory() method through JNI to get // the location of the world-writable SD Card directory. However, @@ -1021,38 +1069,42 @@ class CapturedStream { // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; -# else + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; +#else char name_template[] = "/tmp/captured_stream.XXXXXX"; -# endif // GTEST_OS_LINUX_ANDROID +#endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); + if (captured_fd == -1) { + GTEST_LOG_(WARNING) + << "Failed to create tmp file " << name_template + << " for test; does the test have access to the /tmp directory?"; + } filename_ = name_template; -# endif // GTEST_OS_WINDOWS - fflush(NULL); +#endif // GTEST_OS_WINDOWS + fflush(nullptr); dup2(captured_fd, fd_); close(captured_fd); } - ~CapturedStream() { - remove(filename_.c_str()); - } + ~CapturedStream() { remove(filename_.c_str()); } std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. - fflush(NULL); + fflush(nullptr); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } - FILE* const file = posix::FOpen(filename_.c_str(), "r"); + FILE *const file = posix::FOpen(filename_.c_str(), "r"); + if (file == nullptr) { + GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ + << " for capturing stream."; + } const std::string content = ReadEntireFile(file); posix::FClose(file); return content; @@ -1069,13 +1121,13 @@ class CapturedStream { GTEST_DISABLE_MSC_DEPRECATED_POP_() -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; +static CapturedStream *g_captured_stderr = nullptr; +static CapturedStream *g_captured_stdout = nullptr; // Starts capturing an output stream (stdout/stderr). -static void CaptureStream(int fd, const char* stream_name, - CapturedStream** stream) { - if (*stream != NULL) { +static void CaptureStream(int fd, const char *stream_name, + CapturedStream **stream) { + if (*stream != nullptr) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } @@ -1083,11 +1135,11 @@ static void CaptureStream(int fd, const char* stream_name, } // Stops capturing the output stream and returns the captured string. -static std::string GetCapturedStream(CapturedStream** captured_stream) { +static std::string GetCapturedStream(CapturedStream **captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; - *captured_stream = NULL; + *captured_stream = nullptr; return content; } @@ -1114,18 +1166,14 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION - - - - -size_t GetFileSize(FILE* file) { +size_t GetFileSize(FILE *file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } -std::string ReadEntireFile(FILE* file) { +std::string ReadEntireFile(FILE *file) { const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; + char *const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far @@ -1135,7 +1183,8 @@ std::string ReadEntireFile(FILE* file) { // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_last_read = + fread(buffer + bytes_read, 1, file_size - bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); @@ -1146,35 +1195,29 @@ std::string ReadEntireFile(FILE* file) { } #if GTEST_HAS_DEATH_TEST -static const std::vector* g_injected_test_argvs = NULL; // Owned. +static const std::vector *g_injected_test_argvs = + nullptr; // Owned. std::vector GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { + if (g_injected_test_argvs != nullptr) { return *g_injected_test_argvs; } return GetArgvs(); } -void SetInjectableArgvs(const std::vector* new_argvs) { +void SetInjectableArgvs(const std::vector *new_argvs) { if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; g_injected_test_argvs = new_argvs; } -void SetInjectableArgvs(const std::vector& new_argvs) { +void SetInjectableArgvs(const std::vector &new_argvs) { SetInjectableArgvs( new std::vector(new_argvs.begin(), new_argvs.end())); } -#if GTEST_HAS_GLOBAL_STRING -void SetInjectableArgvs(const std::vector< ::string>& new_argvs) { - SetInjectableArgvs( - new std::vector(new_argvs.begin(), new_argvs.end())); -} -#endif // GTEST_HAS_GLOBAL_STRING - void ClearInjectableArgvs() { delete g_injected_test_argvs; - g_injected_test_argvs = NULL; + g_injected_test_argvs = nullptr; } #endif // GTEST_HAS_DEATH_TEST @@ -1190,7 +1233,7 @@ void Abort() { // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. -static std::string FlagToEnvVar(const char* flag) { +static std::string FlagToEnvVar(const char *flag) { const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); @@ -1205,9 +1248,9 @@ static std::string FlagToEnvVar(const char* flag) { // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { +bool ParseInt32(const Message &src_text, const char *str, int32_t *value) { // Parses the environment variable as a decimal integer. - char* end = NULL; + char *end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? @@ -1222,14 +1265,14 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { return false; } - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); + // Is the parsed value in the range of an int32_t? + const auto result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value - // The parsed value overflows as an Int32. - ) { + // The parsed value overflows as an int32_t. + ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" @@ -1246,35 +1289,35 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { +// The value is considered true if and only if it's not "0". +bool BoolFromGTestEnv(const char *flag, bool default_value) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; + const char *const string_value = posix::GetEnv(env_var.c_str()); + return string_value == nullptr ? default_value + : strcmp(string_value, "0") != 0; #endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +int32_t Int32FromGTestEnv(const char *flag, int32_t default_value) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { + const char *const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == nullptr) { // The environment variable is not set. return default_value; } - Int32 result = default_value; - if (!ParseInt32(Message() << "Environment variable " << env_var, - string_value, &result)) { + int32_t result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, + &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); @@ -1293,10 +1336,10 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { // not check that the flag is 'output' // In essence this checks an env variable called XML_OUTPUT_FILE // and if it is set we prepend "xml:" to its value, if it not set we return "" -std::string OutputFlagAlsoCheckEnvVar(){ +std::string OutputFlagAlsoCheckEnvVar() { std::string default_value_for_output_flag = ""; - const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); - if (NULL != xml_output_file_env) { + const char *xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (nullptr != xml_output_file_env) { default_value_for_output_flag = std::string("xml:") + xml_output_file_env; } return default_value_for_output_flag; @@ -1304,13 +1347,13 @@ std::string OutputFlagAlsoCheckEnvVar(){ // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. -const char* StringFromGTestEnv(const char* flag, const char* default_value) { +const char *StringFromGTestEnv(const char *flag, const char *default_value) { #if defined(GTEST_GET_STRING_FROM_ENV_) return GTEST_GET_STRING_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); - const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; + const char *const value = posix::GetEnv(env_var.c_str()); + return value == nullptr ? default_value : value; #endif // defined(GTEST_GET_STRING_FROM_ENV_) } diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-printers.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-printers.cc index de4d245e9f..8399386a99 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-printers.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-printers.cc @@ -27,7 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a @@ -59,9 +58,10 @@ using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, - size_t count, ostream* os) { +void PrintByteSegmentInObjectTo(const unsigned char *obj_bytes, size_t start, + size_t count, ostream *os) { char text[5] = ""; for (size_t i = 0; i != count; i++) { const size_t j = start + i; @@ -79,8 +79,8 @@ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, } // Prints the bytes in the given value to the given ostream. -void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, - ostream* os) { +void PrintBytesInObjectToImpl(const unsigned char *obj_bytes, size_t count, + ostream *os) { // Tells the user how big the object is. *os << count << "-byte object <"; @@ -89,14 +89,13 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // FIXME: let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); *os << " ... "; // Rounds up to 2-byte boundary. - const size_t resume_pos = (count - kChunkSize + 1)/2*2; + const size_t resume_pos = (count - kChunkSize + 1) / 2 * 2; PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); } *os << ">"; @@ -111,8 +110,8 @@ namespace internal2 { // uses the << operator and thus is easier done outside of the // ::testing::internal namespace, which contains a << operator that // sometimes conflicts with the one in STL. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, - ostream* os) { +void PrintBytesInObjectTo(const unsigned char *obj_bytes, size_t count, + ostream *os) { PrintBytesInObjectToImpl(obj_bytes, count, os); } @@ -125,58 +124,33 @@ namespace internal { // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), // - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). -enum CharFormat { - kAsIs, - kHexEscape, - kSpecialEscape -}; +enum CharFormat { kAsIs, kHexEscape, kSpecialEscape }; // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. -inline bool IsPrintableAscii(wchar_t c) { - return 0x20 <= c && c <= 0x7E; -} +inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } // Prints a wide or narrow char c as a character literal without the // quotes, escaping it when necessary; returns how c was formatted. // The template argument UnsignedChar is the unsigned version of Char, // which is the type of c. template -static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { - case L'\0': - *os << "\\0"; - break; - case L'\'': - *os << "\\'"; - break; - case L'\\': - *os << "\\\\"; - break; - case L'\a': - *os << "\\a"; - break; - case L'\b': - *os << "\\b"; - break; - case L'\f': - *os << "\\f"; - break; - case L'\n': - *os << "\\n"; - break; - case L'\r': - *os << "\\r"; - break; - case L'\t': - *os << "\\t"; - break; - case L'\v': - *os << "\\v"; - break; +static CharFormat PrintAsCharLiteralTo(Char c, ostream *os) { + wchar_t w_c = static_cast(c); + switch (w_c) { + case L'\0': *os << "\\0"; break; + case L'\'': *os << "\\'"; break; + case L'\\': *os << "\\\\"; break; + case L'\a': *os << "\\a"; break; + case L'\b': *os << "\\b"; break; + case L'\f': *os << "\\f"; break; + case L'\n': *os << "\\n"; break; + case L'\r': *os << "\\r"; break; + case L'\t': *os << "\\t"; break; + case L'\v': *os << "\\v"; break; default: - if (IsPrintableAscii(c)) { + if (IsPrintableAscii(w_c)) { *os << static_cast(c); return kAsIs; } else { @@ -192,22 +166,17 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { // Prints a wchar_t c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { +static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream *os) { switch (c) { - case L'\'': - *os << "'"; - return kAsIs; - case L'"': - *os << "\\\""; - return kSpecialEscape; - default: - return PrintAsCharLiteralTo(c, os); + case L'\'': *os << "'"; return kAsIs; + case L'"': *os << "\\\""; return kSpecialEscape; + default: return PrintAsCharLiteralTo(c, os); } } // Prints a char c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { +static CharFormat PrintAsStringLiteralTo(char c, ostream *os) { return PrintAsStringLiteralTo( static_cast(static_cast(c)), os); } @@ -217,7 +186,7 @@ static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { // using the standard C++ escape sequence. The template argument // UnsignedChar is the unsigned version of Char, which is the type of c. template -void PrintCharAndCodeTo(Char c, ostream* os) { +void PrintCharAndCodeTo(Char c, ostream *os) { // First, print c as a literal in the most readable form we can find. *os << ((sizeof(c) > 1) ? "L'" : "'"); const CharFormat format = PrintAsCharLiteralTo(c, os); @@ -226,8 +195,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { // To aid user debugging, we also print c's code in decimal, unless // it's 0 (in which case c was printed as '\\0', making the code // obvious). - if (c == 0) - return; + if (c == 0) return; *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexadecimal, @@ -236,35 +204,32 @@ void PrintCharAndCodeTo(Char c, ostream* os) { if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { - *os << ", 0x" << String::FormatHexInt(static_cast(c)); + *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } -void PrintTo(unsigned char c, ::std::ostream* os) { +void PrintTo(unsigned char c, ::std::ostream *os) { PrintCharAndCodeTo(c, os); } -void PrintTo(signed char c, ::std::ostream* os) { +void PrintTo(signed char c, ::std::ostream *os) { PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its code. L'\0' is printed as "L'\\0'". -void PrintTo(wchar_t wc, ostream* os) { - PrintCharAndCodeTo(wc, os); -} +void PrintTo(wchar_t wc, ostream *os) { PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template -GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static CharFormat PrintCharsAsStringTo( - const CharType* begin, size_t len, ostream* os) { - const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ + GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ + GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat + PrintCharsAsStringTo(const CharType *begin, size_t len, ostream *os) { + const char *const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; CharFormat print_format = kAsIs; @@ -289,11 +254,11 @@ static CharFormat PrintCharsAsStringTo( // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template -GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ -GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ -GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static void UniversalPrintCharArray( - const CharType* begin, size_t len, ostream* os) { +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ + GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ + GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void + UniversalPrintCharArray(const CharType *begin, size_t len, + ostream *os) { // The code // const char kFoo[] = "foo"; // generates an array of 4, not 3, elements, with the last one being '\0'. @@ -315,22 +280,22 @@ static void UniversalPrintCharArray( } // Prints a (const) char array of 'len' elements, starting at address 'begin'. -void UniversalPrintArray(const char* begin, size_t len, ostream* os) { +void UniversalPrintArray(const char *begin, size_t len, ostream *os) { UniversalPrintCharArray(begin, len, os); } // Prints a (const) wchar_t array of 'len' elements, starting at address // 'begin'. -void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { +void UniversalPrintArray(const wchar_t *begin, size_t len, ostream *os) { UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. -void PrintTo(const char* s, ostream* os) { - if (s == NULL) { +void PrintTo(const char *s, ostream *os) { + if (s == nullptr) { *os << "NULL"; } else { - *os << ImplicitCast_(s) << " pointing to "; + *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } @@ -343,40 +308,38 @@ void PrintTo(const char* s, ostream* os) { // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. -void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { +void PrintTo(const wchar_t *s, ostream *os) { + if (s == nullptr) { *os << "NULL"; } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, std::wcslen(s), os); + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native namespace { -bool ContainsUnprintableControlCodes(const char* str, size_t length) { +bool ContainsUnprintableControlCodes(const char *str, size_t length) { const unsigned char *s = reinterpret_cast(str); for (size_t i = 0; i < length; i++) { unsigned char ch = *s++; if (std::iscntrl(ch)) { - switch (ch) { + switch (ch) { case '\t': case '\n': - case '\r': - break; - default: - return true; - } + case '\r': break; + default: return true; } + } } return false; } -bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t <= 0xbf; } -bool IsValidUTF8(const char* str, size_t length) { +bool IsValidUTF8(const char *str, size_t length) { const unsigned char *s = reinterpret_cast(str); for (size_t i = 0; i < length;) { @@ -390,15 +353,13 @@ bool IsValidUTF8(const char* str, size_t length) { } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { ++i; // 2-byte character } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && - IsUTF8TrailByte(s[i]) && - IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) && // check for non-shortest form and surrogate (lead != 0xe0 || s[i] >= 0xa0) && (lead != 0xed || s[i] < 0xa0)) { i += 2; // 3-byte character } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && - IsUTF8TrailByte(s[i]) && - IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) && IsUTF8TrailByte(s[i + 2]) && // check for non-shortest form (lead != 0xf0 || s[i] >= 0x90) && @@ -411,7 +372,7 @@ bool IsValidUTF8(const char* str, size_t length) { return true; } -void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { +void ConditionalPrintAsText(const char *str, size_t length, ostream *os) { if (!ContainsUnprintableControlCodes(str, length) && IsValidUTF8(str, length)) { *os << "\n As Text: \"" << str << "\""; @@ -420,34 +381,16 @@ void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { } // anonymous namespace -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { +void PrintStringTo(const ::std::string &s, ostream *os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); } } } -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string& s, ostream* os) { - if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { - if (GTEST_FLAG(print_utf8)) { - ConditionalPrintAsText(s.data(), s.size(), os); - } - } -} - -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { +void PrintWideStringTo(const ::std::wstring &s, ostream *os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-test-part.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-test-part.cc index c88860d923..44b0e2b3f0 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-test-part.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-test-part.cc @@ -31,6 +31,8 @@ // The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" + +#include "gtest/internal/gtest-port.h" #include "src/gtest-internal-inl.h" namespace testing { @@ -39,35 +41,40 @@ using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. -std::string TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); +std::string TestPartResult::ExtractSummary(const char *message) { + const char *const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == nullptr ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; +std::ostream &operator<<(std::ostream &os, const TestPartResult &result) { + return os << internal::FormatFileLocation(result.file_name(), + result.line_number()) + << " " + << (result.type() == TestPartResult::kSuccess + ? "Success" + : result.type() == TestPartResult::kSkip + ? "Skipped" + : result.type() == TestPartResult::kFatalFailure + ? "Fatal failure" + : "Non-fatal failure") + << ":\n" + << result.message() << std::endl; } // Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { +void TestPartResultArray::Append(const TestPartResult &result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { +const TestPartResult &TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } - return array_[index]; + return array_[static_cast(index)]; } // Returns the number of TestPartResult objects in the array. @@ -79,8 +86,8 @@ namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), - original_reporter_(GetUnitTestImpl()-> - GetTestPartResultReporterForCurrentThread()) { + original_reporter_( + GetUnitTestImpl()->GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } @@ -90,9 +97,8 @@ HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { } void HasNewFatalFailureHelper::ReportTestPartResult( - const TestPartResult& result) { - if (result.fatally_failed()) - has_new_fatal_failure_ = true; + const TestPartResult &result) { + if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-typed-test.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-typed-test.cc index 1dc2ad38ba..04effad17a 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest-typed-test.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest-typed-test.cc @@ -27,7 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - #include "gtest/gtest-typed-test.h" #include "gtest/gtest.h" @@ -39,16 +38,15 @@ namespace internal { // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. -static const char* SkipSpaces(const char* str) { - while (IsSpace(*str)) - str++; +static const char *SkipSpaces(const char *str) { + while (IsSpace(*str)) str++; return str; } -static std::vector SplitIntoTestNames(const char* src) { +static std::vector SplitIntoTestNames(const char *src) { std::vector name_vec; src = SkipSpaces(src); - for (; src != NULL; src = SkipComma(src)) { + for (; src != nullptr; src = SkipComma(src)) { name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); } return name_vec; @@ -57,8 +55,11 @@ static std::vector SplitIntoTestNames(const char* src) { // Verifies that registered_tests match the test names in // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { +const char *TypedTestSuitePState::VerifyRegisteredTestNames( + const char *test_suite_name, const char *file, int line, + const char *registered_tests) { + RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line)); + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; @@ -69,7 +70,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( std::set tests; for (std::vector::const_iterator name_it = name_vec.begin(); name_it != name_vec.end(); ++name_it) { - const std::string& name = *name_it; + const std::string &name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; @@ -77,8 +78,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( bool found = false; for (RegisteredTestIter it = registered_tests_.begin(); - it != registered_tests_.end(); - ++it) { + it != registered_tests_.end(); ++it) { if (name == it->first) { found = true; break; @@ -89,19 +89,18 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( tests.insert(name); } else { errors << "No test named " << name - << " can be found in this test case.\n"; + << " can be found in this test suite.\n"; } } for (RegisteredTestIter it = registered_tests_.begin(); - it != registered_tests_.end(); - ++it) { + it != registered_tests_.end(); ++it) { if (tests.count(it->first) == 0) { errors << "You forgot to list test " << it->first << ".\n"; } } - const std::string& errors_str = errors.GetString(); + const std::string &errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest.cc index 96b07c68ab..5b4037fecb 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest.cc @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -54,88 +55,78 @@ #if GTEST_OS_LINUX -// FIXME: Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 +#define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT -# include // NOLINT -# include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT // Declares vsnprintf(). This header is not available on Windows. -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include - -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include #elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. -# include // NOLINT +#include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. -# include // NOLINT -# undef min +#include // NOLINT +#undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT +#include // NOLINT +#undef min -# if GTEST_OS_WINDOWS_MINGW +#ifdef _MSC_VER +#include // NOLINT +#include // NOLINT +#endif + +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// FIXME: Use autoconf to detect availability of -// gettimeofday(). -// FIXME: There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT -# endif // GTEST_OS_WINDOWS_MINGW - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT -# undef min +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT +#endif // GTEST_OS_WINDOWS_MINGW #else // Assume other platforms have gettimeofday(). -// FIXME: Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 +#define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. -# include // NOLINT -# include // NOLINT +#include // NOLINT +#include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS -# include +#include #endif #if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT #endif #include "src/gtest-internal-inl.h" #if GTEST_OS_WINDOWS -# define vsnprintf _vsnprintf +#define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC @@ -160,14 +151,14 @@ using internal::Shuffle; // Constants. -// A test whose test case name or test name matches this filter is +// A test whose test suite name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't +// A test suite whose name matches this filter is considered a death +// test suite and will be run before test suites whose name doesn't // match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; +static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; @@ -190,20 +181,20 @@ namespace internal { // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. +// g_help_flag is true if and only if the --help flag or an equivalent form +// is specified on the command line. bool g_help_flag = false; // Utilty function to Open File for Writing -static FILE* OpenFileForWriting(const std::string& output_file) { - FILE* fileout = NULL; +static FILE *OpenFileForWriting(const std::string &output_file) { + FILE *fileout = nullptr; FilePath output_file_path(output_file); FilePath output_dir(output_file_path.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { fileout = posix::FOpen(output_file.c_str(), "w"); } - if (fileout == NULL) { + if (fileout == nullptr) { GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; } return fileout; @@ -213,10 +204,10 @@ static FILE* OpenFileForWriting(const std::string& output_file) { // Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY // environment variable. -static const char* GetDefaultFilter() { - const char* const testbridge_test_only = +static const char *GetDefaultFilter() { + const char *const testbridge_test_only = internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); - if (testbridge_test_only != NULL) { + if (testbridge_test_only != nullptr) { return testbridge_test_only; } return kUniversalFilter; @@ -228,27 +219,24 @@ GTEST_DEFINE_bool_( "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); + break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), + "True if and only if a failed assertion should be a debugger " + "break-point."); -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); +GTEST_DEFINE_bool_(catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True if and only if " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( - color, - internal::StringFromGTestEnv("color", "auto"), + color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( - filter, - internal::StringFromGTestEnv("filter", GetDefaultFilter()), + filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " @@ -258,12 +246,12 @@ GTEST_DEFINE_string_( GTEST_DEFINE_bool_( install_failure_signal_handler, internal::BoolFromGTestEnv("install_failure_signal_handler", false), - "If true and supported on the current platform, " GTEST_NAME_ " should " + "If true and supported on the current platform, " GTEST_NAME_ + " should " "install a signal handler that dumps debugging information when fatal " "signals are raised."); -GTEST_DEFINE_bool_(list_tests, false, - "List all tests without running them."); +GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); // The net priority order after flag processing is thus: // --gtest_output command line flag @@ -273,7 +261,7 @@ GTEST_DEFINE_bool_(list_tests, false, GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", - internal::OutputFlagAlsoCheckEnvVar().c_str()), + internal::OutputFlagAlsoCheckEnvVar().c_str()), "A format (defaults to \"xml\" but can be specified to be \"json\"), " "optionally followed by a colon and an output file name or directory. " "A directory is indicated by a trailing pathname separator. " @@ -283,40 +271,32 @@ GTEST_DEFINE_string_( "executable's name and, if necessary, made unique by adding " "digits."); -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); +GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), + "True if and only if " GTEST_NAME_ + " should display elapsed time in text output."); -GTEST_DEFINE_bool_( - print_utf8, - internal::BoolFromGTestEnv("print_utf8", true), - "True iff " GTEST_NAME_ - " prints UTF8 characters as text."); +GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), + "True if and only if " GTEST_NAME_ + " prints UTF8 characters as text."); GTEST_DEFINE_int32_( - random_seed, - internal::Int32FromGTestEnv("random_seed", 0), + random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( - repeat, - internal::Int32FromGTestEnv("repeat", 1), + repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); +GTEST_DEFINE_bool_(show_internal_stack_frames, false, + "True if and only if " GTEST_NAME_ + " should include internal stack frames when " + "printing test failure stack traces."); -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); +GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), + "True if and only if " GTEST_NAME_ + " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, @@ -325,23 +305,20 @@ GTEST_DEFINE_int32_( "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( - stream_result_to, - internal::StringFromGTestEnv("stream_result_to", ""), + stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( - throw_on_failure, - internal::BoolFromGTestEnv("throw_on_failure", false), + throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise. For use with an external test framework."); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( - flagfile, - internal::StringFromGTestEnv("flagfile", ""), + flagfile, internal::StringFromGTestEnv("flagfile", ""), "This flag specifies the flagfile to read command-line flags from."); #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ @@ -350,13 +327,12 @@ namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. -UInt32 Random::Generate(UInt32 range) { +uint32_t Random::Generate(uint32_t range) { // These constants are the same as are used in glibc's rand(3). // Use wider types than necessary to prevent unsigned overflow diagnostics. - state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; + state_ = static_cast(1103515245ULL * state_ + 12345U) % kMaxRange; - GTEST_CHECK_(range > 0) - << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; @@ -367,16 +343,16 @@ UInt32 Random::Generate(UInt32 range) { return state_ % range; } -// GTestIsInitialized() returns true iff the user has initialized +// GTestIsInitialized() returns true if and only if the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). static bool GTestIsInitialized() { return GetArgvs().size() > 0; } -// Iterates over a vector of TestCases, keeping a running sum of the +// Iterates over a vector of TestSuites, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { +static int SumOverTestSuiteList(const std::vector &case_list, + int (TestSuite::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); @@ -384,47 +360,192 @@ static int SumOverTestCaseList(const std::vector& case_list, return sum; } -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); +// Returns true if and only if the test suite passed. +static bool TestSuitePassed(const TestSuite *test_suite) { + return test_suite->should_run() && test_suite->Passed(); } -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); +// Returns true if and only if the test suite failed. +static bool TestSuiteFailed(const TestSuite *test_suite) { + return test_suite->should_run() && test_suite->Failed(); } -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); +// Returns true if and only if test_suite contains at least one test that +// should run. +static bool ShouldRunTestSuite(const TestSuite *test_suite) { + return test_suite->should_run(); } // AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message) - : data_(new AssertHelperData(type, file, line, message)) { -} +AssertHelper::AssertHelper(TestPartResult::Type type, const char *file, + int line, const char *message) + : data_(new AssertHelperData(type, file, line, message)) {} -AssertHelper::~AssertHelper() { - delete data_; -} +AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. -void AssertHelper::operator=(const Message& message) const { - UnitTest::GetInstance()-> - AddTestPartResult(data_->type, data_->file, data_->line, - AppendUserMessage(data_->message, message), - UnitTest::GetInstance()->impl() - ->CurrentOsStackTraceExceptTop(1) - // Skips the stack frame for this function itself. - ); // NOLINT +void AssertHelper::operator=(const Message &message) const { + UnitTest::GetInstance()->AddTestPartResult( + data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl()->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT } -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); +namespace { + +// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P +// to creates test cases for it, a syntetic test case is +// inserted to report ether an error or a log message. +// +// This configuration bit will likely be removed at some point. +constexpr bool kErrorOnUninstantiatedParameterizedTest = false; +constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = false; + +// A test that fails at a given file/line location with a given message. +class FailureTest : public Test { + public: + explicit FailureTest(const CodeLocation &loc, std::string error_message, + bool as_error) + : loc_(loc), error_message_(std::move(error_message)), + as_error_(as_error) {} + + void TestBody() override { + if (as_error_) { + AssertHelper(TestPartResult::kNonFatalFailure, loc_.file.c_str(), + loc_.line, "") = Message() << error_message_; + } else { + std::cout << error_message_ << std::endl; + } + } + + private: + const CodeLocation loc_; + const std::string error_message_; + const bool as_error_; +}; + +} // namespace + +std::set *GetIgnoredParameterizedTestSuites() { + return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites(); +} + +// Add a given test_suit to the list of them allow to go un-instantiated. +MarkAsIgnored::MarkAsIgnored(const char *test_suite) { + GetIgnoredParameterizedTestSuites()->insert(test_suite); +} + +// If this parameterized test suite has no instantiations (and that +// has not been marked as okay), emit a test case reporting that. +void InsertSyntheticTestCase(const std::string &name, CodeLocation location, + bool has_test_p) { + const auto &ignored = *GetIgnoredParameterizedTestSuites(); + if (ignored.find(name) != ignored.end()) return; + + const char kMissingInstantiation[] = // + " is defined via TEST_P, but never instantiated. None of the test cases " + "will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only " + "ones provided expand to nothing." + "\n\n" + "Ideally, TEST_P definitions should only ever be included as part of " + "binaries that intend to use them. (As opposed to, for example, being " + "placed in a library that may be linked in to get other utilities.)"; + + const char kMissingTestCase[] = // + " is instantiated via INSTANTIATE_TEST_SUITE_P, but no tests are " + "defined via TEST_P . No test cases will run." + "\n\n" + "Ideally, INSTANTIATE_TEST_SUITE_P should only ever be invoked from " + "code that always depend on code that provides TEST_P. Failing to do " + "so is often an indication of dead code, e.g. the last TEST_P was " + "removed but the rest got left behind."; + + std::string message = + "Paramaterized test suite " + name + + (has_test_p ? kMissingInstantiation : kMissingTestCase) + + "\n\n" + "To suppress this error for this test suite, insert the following line " + "(in a non-header) in the namespace it is defined in:" + "\n\n" + "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + + name + ");"; + + std::string full_name = "UninstantiatedParamaterizedTestSuite<" + name + ">"; + RegisterTest( // + "GoogleTestVerification", full_name.c_str(), + nullptr, // No type parameter. + nullptr, // No value parameter. + location.file.c_str(), location.line, [message, location] { + return new FailureTest(location, message, + kErrorOnUninstantiatedParameterizedTest); + }); +} + +void RegisterTypeParameterizedTestSuite(const char *test_suite_name, + CodeLocation code_location) { + GetUnitTestImpl()->type_parameterized_test_registry().RegisterTestSuite( + test_suite_name, code_location); +} + +void RegisterTypeParameterizedTestSuiteInstantiation(const char *case_name) { + GetUnitTestImpl()->type_parameterized_test_registry().RegisterInstantiation( + case_name); +} + +void TypeParameterizedTestSuiteRegistry::RegisterTestSuite( + const char *test_suite_name, CodeLocation code_location) { + suites_.emplace(std::string(test_suite_name), + TypeParameterizedTestSuiteInfo(code_location)); +} + +void TypeParameterizedTestSuiteRegistry::RegisterInstantiation( + const char *test_suite_name) { + auto it = suites_.find(std::string(test_suite_name)); + if (it != suites_.end()) { + it->second.instantiated = true; + } else { + GTEST_LOG_(ERROR) << "Unknown type parameterized test suit '" + << test_suite_name << "'"; + } +} + +void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() { + const auto &ignored = *GetIgnoredParameterizedTestSuites(); + for (const auto &testcase : suites_) { + if (testcase.second.instantiated) continue; + if (ignored.find(testcase.first) != ignored.end()) continue; + + std::string message = + "Type paramaterized test suite " + testcase.first + + " is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated " + "via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run." + "\n\n" + "Ideally, TYPED_TEST_P definitions should only ever be included as " + "part of binaries that intend to use them. (As opposed to, for " + "example, being placed in a library that may be linked in to get other " + "utilities.)" + "\n\n" + "To suppress this error for this test suite, insert the following line " + "(in a non-header) in the namespace it is definedin in:" + "\n\n" + "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + + testcase.first + ");"; + + std::string full_name = + "UninstantiatedTypeParamaterizedTestSuite<" + testcase.first + ">"; + RegisterTest( // + "GoogleTestVerification", full_name.c_str(), + nullptr, // No type parameter. + nullptr, // No value parameter. + testcase.second.code_location.file.c_str(), + testcase.second.code_location.line, [message, testcase] { + return new FailureTest(testcase.second.code_location, message, + kErrorOnUninstantiatedTypeParameterizedTest); + }); + } +} // A copy of all command line arguments. Set by InitGoogleTest(). static ::std::vector g_argvs; @@ -433,7 +554,7 @@ static ::std::vector g_argvs; #if defined(GTEST_CUSTOM_GET_ARGVS_) // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or // ::string. This code converts it to the appropriate type. - const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + const auto &custom = GTEST_CUSTOM_GET_ARGVS_(); return ::std::vector(custom.begin(), custom.end()); #else // defined(GTEST_CUSTOM_GET_ARGVS_) return g_argvs; @@ -445,7 +566,7 @@ static ::std::vector g_argvs; FilePath GetCurrentExecutableName() { FilePath result; -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS || GTEST_OS_OS2 result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else result.Set(FilePath(GetArgvs()[0])); @@ -458,42 +579,37 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); + const char *const gtest_output_flag = GTEST_FLAG(output).c_str(); + const char *const colon = strchr(gtest_output_flag, ':'); + return (colon == nullptr) + ? std::string(gtest_output_flag) + : std::string(gtest_output_flag, + static_cast(colon - gtest_output_flag)); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + const char *const gtest_output_flag = GTEST_FLAG(output).c_str(); std::string format = GetOutputFormat(); - if (format.empty()) - format = std::string(kDefaultOutputFormat); + if (format.empty()) format = std::string(kDefaultOutputFormat); - const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) + const char *const colon = strchr(gtest_output_flag, ':'); + if (colon == nullptr) return internal::FilePath::MakeFileName( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile), 0, - format.c_str()).string(); + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile), 0, format.c_str()) + .string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // FIXME: on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); - if (!output_name.IsDirectory()) - return output_name.string(); + if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), @@ -501,8 +617,8 @@ std::string UnitTestOptions::GetAbsolutePathToOutputFile() { return result.string(); } -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. +// Returns true if and only if the wildcard pattern matches the string. +// The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. @@ -516,15 +632,14 @@ bool UnitTestOptions::PatternMatchesString(const char *pattern, return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); + PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); + return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } -bool UnitTestOptions::MatchesFilter( - const std::string& name, const char* filter) { +bool UnitTestOptions::MatchesFilter(const std::string &name, + const char *filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { @@ -535,7 +650,7 @@ bool UnitTestOptions::MatchesFilter( cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. - if (cur_pattern == NULL) { + if (cur_pattern == nullptr) { return false; } @@ -544,19 +659,19 @@ bool UnitTestOptions::MatchesFilter( } } -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, +// Returns true if and only if the user-specified filter matches the test +// suite name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string &test_suite_name, const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); + const std::string &full_name = test_suite_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions - const char* const p = GTEST_FLAG(filter).c_str(); - const char* const dash = strchr(p, '-'); + const char *const p = GTEST_FLAG(filter).c_str(); + const char *const dash = strchr(p, '-'); std::string positive; std::string negative; - if (dash == NULL) { + if (dash == nullptr) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { @@ -608,9 +723,8 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), - result_(result) { + TestPartResultArray *result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } @@ -618,14 +732,13 @@ ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - InterceptMode intercept_mode, TestPartResultArray* result) - : intercept_mode_(intercept_mode), - result_(result) { + InterceptMode intercept_mode, TestPartResultArray *result) + : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); @@ -638,7 +751,7 @@ void ScopedFakeTestPartResultReporter::Init() { // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { @@ -649,7 +762,7 @@ ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { + const TestPartResult &result) { result_->Append(result); } @@ -664,9 +777,7 @@ namespace internal { // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. -TypeId GetTestTypeId() { - return GetTypeId(); -} +TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). @@ -675,15 +786,15 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. -static AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, +static AssertionResult HasOneFailure(const char * /* results_expr */, + const char * /* type_expr */, + const char * /* substr_expr */, + const TestPartResultArray &results, TestPartResult::Type type, - const std::string& substr) { - const std::string expected(type == TestPartResult::kFatalFailure ? - "1 fatal failure" : - "1 non-fatal failure"); + const std::string &substr) { + const std::string expected(type == TestPartResult::kFatalFailure + ? "1 fatal failure" + : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" @@ -694,18 +805,18 @@ static AssertionResult HasOneFailure(const char* /* results_expr */, return AssertionFailure() << msg; } - const TestPartResult& r = results.GetTestPartResult(0); + const TestPartResult &r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } - if (strstr(r.message(), substr.c_str()) == NULL) { - return AssertionFailure() << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; + if (strstr(r.message(), substr.c_str()) == nullptr) { + return AssertionFailure() + << "Expected: " << expected << " containing \"" << substr << "\"\n" + << " Actual:\n" + << r; } return AssertionSuccess(); @@ -714,9 +825,9 @@ static AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray *results, TestPartResult::Type type, - const std::string& substr) + const std::string &substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given @@ -728,24 +839,26 @@ SingleFailureChecker::~SingleFailureChecker() { } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} + UnitTestImpl *unit_test) + : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { + const TestPartResult &result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} + UnitTestImpl *unit_test) + : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { + const TestPartResult &result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. -TestPartResultReporterInterface* +TestPartResultReporterInterface * UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; @@ -753,78 +866,83 @@ UnitTestImpl::GetGlobalTestPartResultReporter() { // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter) { + TestPartResultReporterInterface *reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. -TestPartResultReporterInterface* +TestPartResultReporterInterface * UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter) { + TestPartResultReporterInterface *reporter) { per_thread_test_part_result_reporter_.set(reporter); } -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); +// Gets the number of successful test suites. +int UnitTestImpl::successful_test_suite_count() const { + return CountIf(test_suites_, TestSuitePassed); } -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); +// Gets the number of failed test suites. +int UnitTestImpl::failed_test_suite_count() const { + return CountIf(test_suites_, TestSuiteFailed); } -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); +// Gets the number of all test suites. +int UnitTestImpl::total_test_suite_count() const { + return static_cast(test_suites_.size()); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); +int UnitTestImpl::test_suite_to_run_count() const { + return CountIf(test_suites_, ShouldRunTestSuite); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); +} + +// Gets the number of skipped tests. +int UnitTestImpl::skipped_test_count() const { + return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); + return SumOverTestSuiteList(test_suites_, + &TestSuite::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); + return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); } // Returns the current OS stack trace as an std::string. @@ -839,11 +957,10 @@ int UnitTestImpl::test_to_run_count() const { // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { return os_stack_trace_getter()->CurrentStackTrace( - static_cast(GTEST_FLAG(stack_trace_depth)), - skip_count + 1 + static_cast(GTEST_FLAG(stack_trace_depth)), skip_count + 1 // Skips the user-specified number of frames plus this function // itself. - ); // NOLINT + ); // NOLINT } // Returns the current time in milliseconds. @@ -852,20 +969,18 @@ TimeInMillis GetTimeInMillis() { // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; + static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // FIXME: Shouldn't this just use - // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; + kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; @@ -874,8 +989,6 @@ TimeInMillis GetTimeInMillis() { // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // FIXME: Use GetTickCount()? Or use - // SystemTimeToFileTime() GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); GTEST_DISABLE_MSC_DEPRECATED_POP_() @@ -883,10 +996,10 @@ TimeInMillis GetTimeInMillis() { return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; - gettimeofday(&now, NULL); + gettimeofday(&now, nullptr); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else -# error "Don't know how to get the current time on your system." +#error "Don't know how to get the current time on your system." #endif } @@ -899,15 +1012,13 @@ TimeInMillis GetTimeInMillis() { // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. -LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; +LPCWSTR String::AnsiToUtf16(const char *ansi) { + if (!ansi) return nullptr; const int length = strlen(ansi); const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); - WCHAR* unicode = new WCHAR[unicode_length + 1]; - MultiByteToWideChar(CP_ACP, 0, ansi, length, - unicode, unicode_length); + MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); + WCHAR *unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } @@ -916,44 +1027,43 @@ LPCWSTR String::AnsiToUtf16(const char* ansi) { // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. -const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); - char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); +const char *String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return nullptr; + const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, + 0, nullptr, nullptr); + char *ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, + nullptr); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE -// Compares two C strings. Returns true iff they have the same content. +// Compares two C strings. Returns true if and only if they have the same +// content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. -bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; +bool String::CStringEquals(const char *lhs, const char *rhs) { + if (lhs == nullptr) return rhs == nullptr; - if ( rhs == NULL ) return false; + if (rhs == nullptr) return false; return strcmp(lhs, rhs) == 0; } -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#if GTEST_HAS_STD_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, - Message* msg) { - for (size_t i = 0; i != length; ) { // NOLINT +static void StreamWideCharsToMessage(const wchar_t *wstr, size_t length, + Message *msg) { + for (size_t i = 0; i != length;) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); - while (i != length && wstr[i] != L'\0') - i++; + while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; @@ -961,10 +1071,10 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, } } -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +#endif // GTEST_HAS_STD_WSTRING -void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { +void SplitString(const ::std::string &str, char delimiter, + ::std::vector< ::std::string> *dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { @@ -995,31 +1105,22 @@ Message::Message() : ss_(new ::std::stringstream) { // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. -Message& Message::operator <<(const wchar_t* wide_c_str) { +Message &Message::operator<<(const wchar_t *wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } -Message& Message::operator <<(wchar_t* wide_c_str) { +Message &Message::operator<<(wchar_t *wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::std::wstring& wstr) { +Message &Message::operator<<(const ::std::wstring &wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { @@ -1028,15 +1129,14 @@ std::string Message::GetString() const { // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). -AssertionResult::AssertionResult(const AssertionResult& other) +AssertionResult::AssertionResult(const AssertionResult &other) : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { -} + message_(other.message_.get() != nullptr + ? new ::std::string(*other.message_) + : static_cast< ::std::string *>(nullptr)) {} // Swaps two AssertionResults. -void AssertionResult::swap(AssertionResult& other) { +void AssertionResult::swap(AssertionResult &other) { using std::swap; swap(success_, other.success_); swap(message_, other.message_); @@ -1045,32 +1145,27 @@ void AssertionResult::swap(AssertionResult& other) { // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; + if (message_.get() != nullptr) negation << *message_; return negation; } // Makes a successful assertion result. -AssertionResult AssertionSuccess() { - return AssertionResult(true); -} +AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. -AssertionResult AssertionFailure() { - return AssertionResult(false); -} +AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. -AssertionResult AssertionFailure(const Message& message) { +AssertionResult AssertionFailure(const Message &message) { return AssertionFailure() << message; } namespace internal { namespace edit_distance { -std::vector CalculateOptimalEdits(const std::vector& left, - const std::vector& right) { +std::vector CalculateOptimalEdits(const std::vector &left, + const std::vector &right) { std::vector > costs( left.size() + 1, std::vector(right.size() + 1)); std::vector > best_move( @@ -1131,7 +1226,7 @@ namespace { // Helper class to convert string into ids with deduplication. class InternalStrings { public: - size_t GetId(const std::string& str) { + size_t GetId(const std::string &str) { IdMap::iterator it = ids_.find(str); if (it != ids_.end()) return it->second; size_t id = ids_.size(); @@ -1146,8 +1241,8 @@ class InternalStrings { } // namespace std::vector CalculateOptimalEdits( - const std::vector& left, - const std::vector& right) { + const std::vector &left, + const std::vector &right) { std::vector left_ids, right_ids; { InternalStrings intern_table; @@ -1170,13 +1265,10 @@ namespace { class Hunk { public: Hunk(size_t left_start, size_t right_start) - : left_start_(left_start), - right_start_(right_start), - adds_(), - removes_(), + : left_start_(left_start), right_start_(right_start), adds_(), removes_(), common_() {} - void PushLine(char edit, const char* line) { + void PushLine(char edit, const char *line) { switch (edit) { case ' ': ++common_; @@ -1194,10 +1286,10 @@ class Hunk { } } - void PrintTo(std::ostream* os) { + void PrintTo(std::ostream *os) { PrintHeader(os); FlushEdits(); - for (std::list >::const_iterator it = + for (std::list >::const_iterator it = hunk_.begin(); it != hunk_.end(); ++it) { *os << it->first << it->second << "\n"; @@ -1216,7 +1308,7 @@ class Hunk { // The format is // "@@ -, +, @@" // where the left/right parts are omitted if unnecessary. - void PrintHeader(std::ostream* ss) const { + void PrintHeader(std::ostream *ss) const { *ss << "@@ "; if (removes_) { *ss << "-" << left_start_ << "," << (removes_ + common_); @@ -1232,7 +1324,7 @@ class Hunk { size_t left_start_, right_start_; size_t adds_, removes_, common_; - std::list > hunk_, hunk_adds_, hunk_removes_; + std::list > hunk_, hunk_adds_, hunk_removes_; }; } // namespace @@ -1244,8 +1336,8 @@ class Hunk { // 'context' represents the desired unchanged prefix/suffix around the diff. // If two hunks are close enough that their contexts overlap, then they are // joined into one hunk. -std::string CreateUnifiedDiff(const std::vector& left, - const std::vector& right, +std::string CreateUnifiedDiff(const std::vector &left, + const std::vector &right, size_t context) { const std::vector edits = CalculateOptimalEdits(left, right); @@ -1272,9 +1364,10 @@ std::string CreateUnifiedDiff(const std::vector& left, for (; edit_i < edits.size(); ++edit_i) { if (n_suffix >= context) { // Continue only if the next hunk is very close. - std::vector::const_iterator it = edits.begin() + edit_i; + auto it = edits.begin() + static_cast(edit_i); while (it != edits.end() && *it == kMatch) ++it; - if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { + if (it == edits.end() || + static_cast(it - edits.begin()) - edit_i >= context) { // There is no next edit or it is too far away. break; } @@ -1313,7 +1406,7 @@ namespace { // The string representation of the values received in EqFailure() are already // escaped. Split them on escaped '\n' boundaries. Leave all other escaped // characters the same. -std::vector SplitEscapedString(const std::string& str) { +std::vector SplitEscapedString(const std::string &str) { std::vector lines; size_t start = 0, end = str.size(); if (end > 2 && str[0] == '"' && str[end - 1] == '"') { @@ -1350,14 +1443,13 @@ std::vector SplitEscapedString(const std::string& str) { // lhs_value: "5" // rhs_value: "6" // -// The ignoring_case parameter is true iff the assertion is a +// The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. -AssertionResult EqFailure(const char* lhs_expression, - const char* rhs_expression, - const std::string& lhs_value, - const std::string& rhs_value, - bool ignoring_case) { +AssertionResult EqFailure(const char *lhs_expression, + const char *rhs_expression, + const std::string &lhs_value, + const std::string &rhs_value, bool ignoring_case) { Message msg; msg << "Expected equality of these values:"; msg << "\n " << lhs_expression; @@ -1374,10 +1466,8 @@ AssertionResult EqFailure(const char* lhs_expression, } if (!lhs_value.empty() && !rhs_value.empty()) { - const std::vector lhs_lines = - SplitEscapedString(lhs_value); - const std::vector rhs_lines = - SplitEscapedString(rhs_value); + const std::vector lhs_lines = SplitEscapedString(lhs_value); + const std::vector rhs_lines = SplitEscapedString(rhs_value); if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { msg << "\nWith diff:\n" << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); @@ -1389,47 +1479,36 @@ AssertionResult EqFailure(const char* lhs_expression, // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { - const char* actual_message = assertion_result.message(); + const AssertionResult &assertion_result, const char *expression_text, + const char *actual_predicate_value, const char *expected_predicate_value) { + const char *actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; - if (actual_message[0] != '\0') - msg << " (" << actual_message << ")"; + if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { +AssertionResult DoubleNearPredFormat(const char *expr1, const char *expr2, + const char *abs_error_expr, double val1, + double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // FIXME: do not print the value of an expression if it's - // already a literal. return AssertionFailure() - << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; + << "The difference between " << expr1 << " and " << expr2 << " is " + << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; } - // Helper template for implementing FloatLE() and DoubleLE(). template -AssertionResult FloatingPointLE(const char* expr1, - const char* expr2, - RawType val1, - RawType val2) { +AssertionResult FloatingPointLE(const char *expr1, const char *expr2, + RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); @@ -1454,24 +1533,24 @@ AssertionResult FloatingPointLE(const char* expr1, << val2; return AssertionFailure() - << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StringStreamToString(&val1_ss) << " vs " - << StringStreamToString(&val2_ss); + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2) { +AssertionResult FloatLE(const char *expr1, const char *expr2, float val1, + float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2) { +AssertionResult DoubleLE(const char *expr1, const char *expr2, double val1, + double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } @@ -1479,36 +1558,33 @@ namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. -AssertionResult CmpHelperEQ(const char* lhs_expression, - const char* rhs_expression, - BiggestInt lhs, +AssertionResult CmpHelperEQ(const char *lhs_expression, + const char *rhs_expression, BiggestInt lhs, BiggestInt rhs) { if (lhs == rhs) { return AssertionSuccess(); } - return EqFailure(lhs_expression, - rhs_expression, + return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), - FormatForComparisonFailureMessage(rhs, lhs), - false); + FormatForComparisonFailureMessage(rhs, lhs), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - BiggestInt val1, BiggestInt val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - }\ -} +#define GTEST_IMPL_CMP_HELPER_(op_name, op) \ + AssertionResult CmpHelper##op_name(const char *expr1, const char *expr2, \ + BiggestInt val1, BiggestInt val2) { \ + if (val1 op val2) { \ + return AssertionSuccess(); \ + } else { \ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2 \ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) \ + << " vs " << FormatForComparisonFailureMessage(val2, val1); \ + } \ + } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. @@ -1518,74 +1594,63 @@ GTEST_IMPL_CMP_HELPER_(NE, !=) GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. -GTEST_IMPL_CMP_HELPER_(LT, < ) +GTEST_IMPL_CMP_HELPER_(LT, <) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. -GTEST_IMPL_CMP_HELPER_(GT, > ) +GTEST_IMPL_CMP_HELPER_(GT, >) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* lhs_expression, - const char* rhs_expression, - const char* lhs, - const char* rhs) { +AssertionResult CmpHelperSTREQ(const char *lhs_expression, + const char *rhs_expression, const char *lhs, + const char *rhs) { if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(lhs_expression, - rhs_expression, - PrintToString(lhs), - PrintToString(rhs), - false); + return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), + PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, - const char* rhs_expression, - const char* lhs, - const char* rhs) { +AssertionResult CmpHelperSTRCASEEQ(const char *lhs_expression, + const char *rhs_expression, const char *lhs, + const char *rhs) { if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(lhs_expression, - rhs_expression, - PrintToString(lhs), - PrintToString(rhs), - true); + return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), + PrintToString(rhs), true); } // The helper function for {ASSERT|EXPECT}_STRNE. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { +AssertionResult CmpHelperSTRNE(const char *s1_expression, + const char *s2_expression, const char *s1, + const char *s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" << s2_expression + << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. -AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { +AssertionResult CmpHelperSTRCASENE(const char *s1_expression, + const char *s2_expression, const char *s1, + const char *s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() - << "Expected: (" << s1_expression << ") != (" - << s2_expression << ") (ignoring case), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; + << "Expected: (" << s1_expression << ") != (" << s2_expression + << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } @@ -1595,28 +1660,25 @@ namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. +// This group of overloaded functions return true if and only if needle +// is a substring of haystack. NULL is considered a substring of +// itself only. -bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; +bool IsSubstringPred(const char *needle, const char *haystack) { + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return strstr(haystack, needle) != NULL; + return strstr(haystack, needle) != nullptr; } -bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; +bool IsSubstringPred(const wchar_t *needle, const wchar_t *haystack) { + if (needle == nullptr || haystack == nullptr) return needle == haystack; - return wcsstr(haystack, needle) != NULL; + return wcsstr(haystack, needle) != nullptr; } // StringType here can be either ::std::string or ::std::wstring. template -bool IsSubstringPred(const StringType& needle, - const StringType& haystack) { +bool IsSubstringPred(const StringType &needle, const StringType &haystack) { return haystack.find(needle) != StringType::npos; } @@ -1625,21 +1687,22 @@ bool IsSubstringPred(const StringType& needle, // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template -AssertionResult IsSubstringImpl( - bool expected_to_be_substring, - const char* needle_expr, const char* haystack_expr, - const StringType& needle, const StringType& haystack) { +AssertionResult IsSubstringImpl(bool expected_to_be_substring, + const char *needle_expr, + const char *haystack_expr, + const StringType &needle, + const StringType &haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; - const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + const char *const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() - << "Value of: " << needle_expr << "\n" - << " Actual: " << begin_string_quote << needle << "\"\n" - << "Expected: " << (expected_to_be_substring ? "" : "not ") - << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""; + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace @@ -1648,52 +1711,52 @@ AssertionResult IsSubstringImpl( // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { +AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, + const char *needle, const char *haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { +AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, + const wchar_t *needle, const wchar_t *haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { +AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, const char *needle, + const char *haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { +AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, const wchar_t *needle, + const wchar_t *haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { +AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, + const ::std::string &needle, + const ::std::string &haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { +AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::string &needle, + const ::std::string &haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { +AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, + const ::std::wstring &needle, + const ::std::wstring &haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { +AssertionResult IsNotSubstring(const char *needle_expr, + const char *haystack_expr, + const ::std::wstring &needle, + const ::std::wstring &haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING @@ -1705,55 +1768,54 @@ namespace internal { namespace { // Helper function for IsHRESULT{SuccessFailure} predicates -AssertionResult HRESULTFailureHelper(const char* expr, - const char* expected, +AssertionResult HRESULTFailureHelper(const char *expr, const char *expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; -# else +#else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. - const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kFlags = + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system - hr, // the error + static_cast(hr), // the error 0, // no line width restrictions error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts + kBufSize, // buf size + nullptr); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); - --message_length) { + --message_length) { error_text[message_length - 1] = '\0'; } -# endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() - << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << " " << error_text << "\n"; + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace -AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT +AssertionResult IsHRESULTSuccess(const char *expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } -AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT +AssertionResult IsHRESULTFailure(const char *expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } @@ -1775,41 +1837,43 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; +constexpr uint32_t kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; +constexpr uint32_t kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; +constexpr uint32_t kMaxCodePoint3 = + (static_cast(1) << (4 + 2 * 6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; +constexpr uint32_t kMaxCodePoint4 = + (static_cast(1) << (3 + 3 * 6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); +inline uint32_t ChopLowBits(uint32_t *bits, int n) { + const uint32_t low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be +// code_point parameter is of type uint32_t because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". -std::string CodePointToUtf8(UInt32 code_point) { +std::string CodePointToUtf8(uint32_t code_point) { if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; - str[0] = static_cast(code_point); // 0xxxxxxx + str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx @@ -1831,30 +1895,33 @@ std::string CodePointToUtf8(UInt32 code_point) { // The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. +// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - return sizeof(wchar_t) == 2 && - (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; + return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && + (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); +inline uint32_t CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const auto first_u = static_cast(first); + const auto second_u = static_cast(second); + const uint32_t mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) + ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 + : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + first_u; } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number @@ -1865,22 +1932,21 @@ inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. -std::string WideStringToUtf8(const wchar_t* str, int num_chars) { - if (num_chars == -1) - num_chars = static_cast(wcslen(str)); +std::string WideStringToUtf8(const wchar_t *str, int num_chars) { + if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; + uint32_t unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { - unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], - str[i + 1]); + unicode_code_point = + CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { - unicode_code_point = static_cast(str[i]); + unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); @@ -1890,88 +1956,80 @@ std::string WideStringToUtf8(const wchar_t* str, int num_chars) { // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". -std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; +std::string String::ShowWideCString(const wchar_t *wide_c_str) { + if (wide_c_str == nullptr) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } -// Compares two wide C strings. Returns true iff they have the same -// content. +// Compares two wide C strings. Returns true if and only if they have the +// same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. -bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; +bool String::WideCStringEquals(const wchar_t *lhs, const wchar_t *rhs) { + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* lhs_expression, - const char* rhs_expression, - const wchar_t* lhs, - const wchar_t* rhs) { +AssertionResult CmpHelperSTREQ(const char *lhs_expression, + const char *rhs_expression, const wchar_t *lhs, + const wchar_t *rhs) { if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(lhs_expression, - rhs_expression, - PrintToString(lhs), - PrintToString(rhs), - false); + return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), + PrintToString(rhs), false); } // Helper function for *_STRNE on wide strings. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2) { +AssertionResult CmpHelperSTRNE(const char *s1_expression, + const char *s2_expression, const wchar_t *s1, + const wchar_t *s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << PrintToString(s1) - << " vs " << PrintToString(s2); + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" << s2_expression + << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } -// Compares two C strings, ignoring case. Returns true iff they have +// Compares two C strings, ignoring case. Returns true if and only if they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. -bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; +bool String::CaseInsensitiveCStringEquals(const char *lhs, const char *rhs) { + if (lhs == nullptr) return rhs == nullptr; + if (rhs == nullptr) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. -bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; +// Compares two wide C strings, ignoring case. Returns true if and only if they +// have the same content. +// +// Unlike wcscasecmp(), this function can handle NULL argument(s). +// A NULL C string is considered different to any non-NULL wide C string, +// including the empty string. +// NB: The implementations on different platforms slightly differ. +// On windows, this method uses _wcsicmp which compares according to LC_CTYPE +// environment variable. On GNU platform this method uses wcscasecmp +// which compares according to LC_CTYPE category of the current locale. +// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the +// current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t *lhs, + const wchar_t *rhs) { + if (lhs == nullptr) return rhs == nullptr; - if (rhs == NULL) return false; + if (rhs == nullptr) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; @@ -1982,17 +2040,17 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, // Other unknown OSes may not define it either. wint_t left, right; do { - left = towlower(*lhs++); - right = towlower(*rhs++); + left = towlower(static_cast(*lhs++)); + right = towlower(static_cast(*rhs++)); } while (left && left == right); return left == right; #endif // OS selector } -// Returns true iff str ends with the given suffix, ignoring case. +// Returns true if and only if str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. -bool String::EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix) { +bool String::EndsWithCaseInsensitive(const std::string &str, + const std::string &suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && @@ -2008,12 +2066,17 @@ std::string String::FormatIntWidth2(int value) { } // Formats an int value as "%X". -std::string String::FormatHexInt(int value) { +std::string String::FormatHexUInt32(uint32_t value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + return FormatHexUInt32(static_cast(value)); +} + // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; @@ -2024,14 +2087,14 @@ std::string String::FormatByte(unsigned char value) { // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. -std::string StringStreamToString(::std::stringstream* ss) { - const ::std::string& str = ss->str(); - const char* const start = str.c_str(); - const char* const end = start + str.length(); +std::string StringStreamToString(::std::stringstream *ss) { + const ::std::string &str = ss->str(); + const char *const start = str.c_str(); + const char *const end = start + str.length(); std::string result; - result.reserve(2 * (end - start)); - for (const char* ch = start; ch != end; ++ch) { + result.reserve(static_cast(2 * (end - start))); + for (const char *ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { @@ -2043,8 +2106,8 @@ std::string StringStreamToString(::std::stringstream* ss) { } // Appends the user-supplied message to the Google-Test-generated message. -std::string AppendUserMessage(const std::string& gtest_msg, - const Message& user_msg) { +std::string AppendUserMessage(const std::string >est_msg, + const Message &user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { @@ -2060,47 +2123,40 @@ std::string AppendUserMessage(const std::string& gtest_msg, // Creates an empty TestResult. TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} + : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} // D'tor. -TestResult::~TestResult() { -} +TestResult::~TestResult() {} // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. -const TestPartResult& TestResult::GetTestPartResult(int i) const { - if (i < 0 || i >= total_part_count()) - internal::posix::Abort(); - return test_part_results_.at(i); +const TestPartResult &TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) internal::posix::Abort(); + return test_part_results_.at(static_cast(i)); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. -const TestProperty& TestResult::GetTestProperty(int i) const { - if (i < 0 || i >= test_property_count()) - internal::posix::Abort(); - return test_properties_.at(i); +const TestProperty &TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) internal::posix::Abort(); + return test_properties_.at(static_cast(i)); } // Clears the test part results. -void TestResult::ClearTestPartResults() { - test_part_results_.clear(); -} +void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. -void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { +void TestResult::AddTestPartResult(const TestPartResult &test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. -void TestResult::RecordProperty(const std::string& xml_element, - const TestProperty& test_property) { +void TestResult::RecordProperty(const std::string &xml_element, + const TestProperty &test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } @@ -2117,40 +2173,37 @@ void TestResult::RecordProperty(const std::string& xml_element, // The list of reserved attributes used in the element of XML // output. -static const char* const kReservedTestSuitesAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "random_seed", - "tests", - "time", - "timestamp" +static const char *const kReservedTestSuitesAttributes[] = { + "disabled", "errors", "failures", "name", + "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. -static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" +static const char *const kReservedTestSuiteAttributes[] = { + "disabled", "errors", "failures", "name", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML output. -static const char* const kReservedTestCaseAttributes[] = { - "classname", "name", "status", "time", - "type_param", "value_param", "file", "line"}; +static const char *const kReservedTestCaseAttributes[] = { + "classname", "name", "status", "time", + "type_param", "value_param", "file", "line" +}; + +// Use a slightly different set for allowed output to ensure existing tests can +// still RecordProperty("result") or "RecordProperty(timestamp") +static const char *const kReservedOutputTestCaseAttributes[] = { + "classname", "name", "status", "time", "type_param", + "value_param", "file", "line", "result", "timestamp" +}; template -std::vector ArrayAsVector(const char* const (&array)[kSize]) { +std::vector ArrayAsVector(const char *const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( - const std::string& xml_element) { + const std::string &xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { @@ -2164,7 +2217,23 @@ static std::vector GetReservedAttributesForElement( return std::vector(); } -static std::string FormatWordList(const std::vector& words) { +// TODO(jdesprez): Merge the two getReserved attributes once skip is improved +static std::vector GetReservedOutputAttributesForElement( + const std::string &xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedOutputTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +static std::string FormatWordList(const std::vector &words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { @@ -2179,10 +2248,10 @@ static std::string FormatWordList(const std::vector& words) { } static bool ValidateTestPropertyName( - const std::string& property_name, - const std::vector& reserved_names) { + const std::string &property_name, + const std::vector &reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != - reserved_names.end()) { + reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; @@ -2193,8 +2262,8 @@ static bool ValidateTestPropertyName( // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property) { +bool TestResult::ValidateTestProperty(const std::string &xml_element, + const TestProperty &test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } @@ -2207,31 +2276,40 @@ void TestResult::Clear() { elapsed_time_ = 0; } -// Returns true iff the test failed. +// Returns true off the test part was skipped. +static bool TestPartSkipped(const TestPartResult &result) { + return result.skipped(); +} + +// Returns true if and only if the test was skipped. +bool TestResult::Skipped() const { + return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; +} + +// Returns true if and only if the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { - if (GetTestPartResult(i).failed()) - return true; + if (GetTestPartResult(i).failed()) return true; } return false; } -// Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult& result) { +// Returns true if and only if the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult &result) { return result.fatally_failed(); } -// Returns true iff the test fatally failed. +// Returns true if and only if the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } -// Returns true iff the test part non-fatally failed. -static bool TestPartNonfatallyFailed(const TestPartResult& result) { +// Returns true if and only if the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult &result) { return result.nonfatally_failed(); } -// Returns true iff the test has a non-fatal failure. +// Returns true if and only if the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } @@ -2252,35 +2330,30 @@ int TestResult::test_property_count() const { // Creates a Test object. // The c'tor saves the states of all flags. -Test::Test() - : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { -} +Test::Test() : gtest_flag_saver_(new GTEST_FLAG_SAVER_) {} // The d'tor restores the states of all flags. The actual work is // done by the d'tor of the gtest_flag_saver_ field, and thus not // visible here. -Test::~Test() { -} +Test::~Test() {} // Sets up the test fixture. // // A sub-class may override this. -void Test::SetUp() { -} +void Test::SetUp() {} // Tears down the test fixture. // // A sub-class may override this. -void Test::TearDown() { -} +void Test::TearDown() {} // Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, const std::string& value) { +void Test::RecordProperty(const std::string &key, const std::string &value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, int value) { +void Test::RecordProperty(const std::string &key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); @@ -2289,37 +2362,37 @@ void Test::RecordProperty(const std::string& key, int value) { namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message) { + const std::string &message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. + nullptr, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. message, - ""); // No stack trace, either. + ""); // No stack trace, either. } } // namespace internal -// Google Test requires all tests in the same test case to use the same test +// Google Test requires all tests in the same test suite to use the same test // fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If +// same fixture class as the first test in the current test suite. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); + const TestSuite *const test_suite = impl->current_test_suite(); - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; + // Info about the first test in the current test suite. + const TestInfo *const first_test_info = test_suite->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; - const char* const first_test_name = first_test_info->name(); + const char *const first_test_name = first_test_info->name(); // Info about the current test. - const TestInfo* const this_test_info = impl->current_test_info(); + const TestInfo *const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; - const char* const this_test_name = this_test_info->name(); + const char *const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? @@ -2328,21 +2401,21 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // Both TEST and TEST_F appear in same test case, which is incorrect. + // Both TEST and TEST_F appear in same test suite, which is incorrect. // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. - const char* const TEST_name = + const char *const TEST_name = first_is_TEST ? first_test_name : this_test_name; - const char* const TEST_F_name = + const char *const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() + << "All tests in the same test suite must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test suite is\n" + << "illegal. In test suite " << this_test_info->test_suite_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" @@ -2352,15 +2425,15 @@ bool Test::HasSameFixtureClass() { // Two fixture classes with the same name appear in two different // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " + << this_test_info->test_suite_name() << ",\n" + << "you defined test " << first_test_name << " and test " + << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; + << "of the classes to put the tests into different test suites."; } return false; } @@ -2374,11 +2447,11 @@ bool Test::HasSameFixtureClass() { // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). -static std::string* FormatSehExceptionMessage(DWORD exception_code, - const char* location) { +static std::string *FormatSehExceptionMessage(DWORD exception_code, + const char *location) { Message message; - message << "SEH exception with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " thrown in " << location << "."; + message << "SEH exception with code 0x" << std::setbase(16) << exception_code + << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } @@ -2390,10 +2463,10 @@ namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. -static std::string FormatCxxExceptionMessage(const char* description, - const char* location) { +static std::string FormatCxxExceptionMessage(const char *description, + const char *location) { Message message; - if (description != NULL) { + if (description != nullptr) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; @@ -2404,10 +2477,10 @@ static std::string FormatCxxExceptionMessage(const char* description, } static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result); + const TestPartResult &test_part_result); GoogleTestFailureException::GoogleTestFailureException( - const TestPartResult& failure) + const TestPartResult &failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS @@ -2421,8 +2494,8 @@ GoogleTestFailureException::GoogleTestFailureException( // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template -Result HandleSehExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { +Result HandleSehExceptionsInMethodIfSupported(T *object, Result (T::*method)(), + const char *location) { #if GTEST_HAS_SEH __try { return (object->*method)(); @@ -2431,8 +2504,8 @@ Result HandleSehExceptionsInMethodIfSupported( // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). - std::string* exception_message = FormatSehExceptionMessage( - GetExceptionCode(), location); + std::string *exception_message = + FormatSehExceptionMessage(GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; @@ -2448,8 +2521,8 @@ Result HandleSehExceptionsInMethodIfSupported( // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template -Result HandleExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { +Result HandleExceptionsInMethodIfSupported(T *object, Result (T::*method)(), + const char *location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag @@ -2477,21 +2550,21 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const AssertionException&) { // NOLINT + } catch (const AssertionException &) { // NOLINT // This failure was reported already. - } catch (const internal::GoogleTestFailureException&) { // NOLINT + } catch (const internal::GoogleTestFailureException &) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; - } catch (const std::exception& e) { // NOLINT + } catch (const std::exception &e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); + FormatCxxExceptionMessage(nullptr, location)); } return static_cast(0); #else @@ -2508,57 +2581,58 @@ Result HandleExceptionsInMethodIfSupported( void Test::Run() { if (!HasSameFixtureClass()) return; - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { + // We will run the test only if SetUp() was successful and didn't call + // GTEST_SKIP(). + if (!HasFatalFailure() && !IsSkipped()) { impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TestBody, "the test body"); + internal::HandleExceptionsInMethodIfSupported(this, &Test::TestBody, + "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TearDown, "TearDown()"); + internal::HandleExceptionsInMethodIfSupported(this, &Test::TearDown, + "TearDown()"); } -// Returns true iff the current test has a fatal failure. +// Returns true if and only if the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } -// Returns true iff the current test has a non-fatal failure. +// Returns true if and only if the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()-> - HasNonfatalFailure(); + return internal::GetUnitTestImpl() + ->current_test_result() + ->HasNonfatalFailure(); +} + +// Returns true if and only if the current test was skipped. +bool Test::IsSkipped() { + return internal::GetUnitTestImpl()->current_test_result()->Skipped(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, - const char* a_value_param, +TestInfo::TestInfo(const std::string &a_test_suite_name, + const std::string &a_name, const char *a_type_param, + const char *a_value_param, internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), - name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), - location_(a_code_location), - fixture_class_id_(fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory), - result_() {} + internal::TestFactoryBase *factory) + : test_suite_name_(a_test_suite_name), name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + value_param_(a_value_param ? new std::string(a_value_param) : nullptr), + location_(a_code_location), fixture_class_id_(fixture_class_id), + should_run_(false), is_disabled_(false), matches_filter_(false), + factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } @@ -2570,7 +2644,7 @@ namespace internal { // // Arguments: // -// test_case_name: name of the test case +// test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. @@ -2578,40 +2652,35 @@ namespace internal { // or NULL if this is not a value-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. -TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - CodeLocation code_location, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { - TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, +TestInfo *MakeAndRegisterTestInfo( + const char *test_suite_name, const char *name, const char *type_param, + const char *value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase *factory) { + TestInfo *const test_info = + new TestInfo(test_suite_name, name, type_param, value_param, code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } -void ReportInvalidTestCaseType(const char* test_case_name, - CodeLocation code_location) { +void ReportInvalidTestSuiteType(const char *test_suite_name, + CodeLocation code_location) { Message errors; errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" + << "Attempted redefinition of test suite " << test_suite_name << ".\n" + << "All tests in the same test suite must use the same test fixture\n" + << "class. However, in test suite " << test_suite_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" - << "test cases."; + << "test suites."; GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), code_location.line) @@ -2624,7 +2693,7 @@ namespace { // A predicate that checks the test name of a TestInfo against a known // value. // -// This is used for implementation of the TestCase class only. We put +// This is used for implementation of the TestSuite class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // @@ -2634,11 +2703,10 @@ class TestNameIs { // Constructor. // // TestNameIs has NO default constructor. - explicit TestNameIs(const char* name) - : name_(name) {} + explicit TestNameIs(const char *name) : name_(name) {} - // Returns true iff the test name of test_info matches name_. - bool operator()(const TestInfo * test_info) const { + // Returns true if and only if the test name of test_info matches name_. + bool operator()(const TestInfo *test_info) const { return test_info && test_info->name() == name_; } @@ -2651,11 +2719,12 @@ class TestNameIs { namespace internal { // This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); + type_parameterized_test_registry_.CheckForInstantiations(); parameterized_tests_registered_ = true; } } @@ -2668,10 +2737,10 @@ void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + TestEventListener *repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); @@ -2681,23 +2750,27 @@ void TestInfo::Run() { impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. - Test* const test = internal::HandleExceptionsInMethodIfSupported( + Test *const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test if the constructor didn't generate a fatal failure. + // Runs the test if the constructor didn't generate a fatal failure or invoke + // GTEST_SKIP(). // Note that the object will not be null - if (!Test::HasFatalFailure()) { + if (!Test::HasFatalFailure() && !Test::IsSkipped()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } + if (test != nullptr) { // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); + } + result_.set_start_timestamp(start); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. @@ -2705,134 +2778,148 @@ void TestInfo::Run() { // Tells UnitTest to stop associating assertion results to this // test. - impl->set_current_test_info(NULL); + impl->set_current_test_info(nullptr); } -// class TestCase +// class TestSuite -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { +// Gets the number of successful tests in this test suite. +int TestSuite::skipped_test_count() const { + return CountIf(test_info_list_, TestSkipped); +} + +// Gets the number of failed tests in this test suite. +int TestSuite::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { +int TestSuite::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { +// Gets the number of disabled tests in this test suite. +int TestSuite::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { +int TestSuite::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { +// Get the number of tests in this test suite that should run. +int TestSuite::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. -int TestCase::total_test_count() const { +int TestSuite::total_test_count() const { return static_cast(test_info_list_.size()); } -// Creates a TestCase with the given name. +// Creates a TestSuite with the given name. // // Arguments: // -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) +// name: name of the test suite +// a_type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite::TestSuite(const char *a_name, const char *a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - set_up_tc_(set_up_tc), - tear_down_tc_(tear_down_tc), - should_run_(false), - elapsed_time_(0) { -} + type_param_(a_type_param ? new std::string(a_type_param) : nullptr), + set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), + start_timestamp_(0), elapsed_time_(0) {} -// Destructor of TestCase. -TestCase::~TestCase() { +// Destructor of TestSuite. +TestSuite::~TestSuite() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { +const TestInfo *TestSuite::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { +TestInfo *TestSuite::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; + return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { +// Adds a test to this test suite. Will delete the test upon +// destruction of the TestSuite object. +void TestSuite::AddTestInfo(TestInfo *test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } -// Runs every test in this TestCase. -void TestCase::Run() { +// Runs every test in this TestSuite. +void TestSuite::Run() { if (!should_run_) return; - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); + internal::UnitTestImpl *const impl = internal::GetUnitTestImpl(); + impl->set_current_test_suite(this); - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + TestEventListener *repeater = UnitTest::GetInstance()->listeners().repeater(); + // Call both legacy and the new API + repeater->OnTestSuiteStart(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseStart(*this); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); - const internal::TimeInMillis start = internal::GetTimeInMillis(); + start_timestamp_ = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } - elapsed_time_ = internal::GetTimeInMillis() - start; + elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); + // Call both legacy and the new API + repeater->OnTestSuiteEnd(*this); +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI + + impl->set_current_test_suite(nullptr); } -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { +// Clears the results of all tests in this test suite. +void TestSuite::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { +// Shuffles the tests in this test suite. +void TestSuite::ShuffleTests(internal::Random *random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { +void TestSuite::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } @@ -2843,11 +2930,10 @@ void TestCase::UnshuffleTests() { // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". -static std::string FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { +static std::string FormatCountableNoun(int count, const char *singular_form, + const char *plural_form) { return internal::StreamableToString(count) + " " + - (count == 1 ? singular_form : plural_form); + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. @@ -2855,19 +2941,19 @@ static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); +// Formats the count of test suites. +static std::string FormatTestSuiteCount(int test_suite_count) { + return FormatCountableNoun(test_suite_count, "test suite", "test suites"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResult::Type type) { +static const char *TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { - case TestPartResult::kSuccess: - return "Success"; + case TestPartResult::kSkip: return "Skipped"; + case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: @@ -2876,8 +2962,7 @@ static const char * TestPartResultTypeToString(TestPartResult::Type type) { #else return "Failure\n"; #endif - default: - return "Unknown result type"; + default: return "Unknown result type"; } } @@ -2885,18 +2970,19 @@ namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result) { - return (Message() - << internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()) - << " " << TestPartResultTypeToString(test_part_result.type()) - << test_part_result.message()).GetString(); + const TestPartResult &test_part_result) { + return (Message() << internal::FormatFileLocation( + test_part_result.file_name(), + test_part_result.line_number()) + << " " + << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()) + .GetString(); } // Prints a TestPartResult. -static void PrintTestPartResult(const TestPartResult& test_part_result) { - const std::string& result = - PrintTestPartResultToString(test_part_result); +static void PrintTestPartResult(const TestPartResult &test_part_result) { + const std::string &result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the @@ -2913,24 +2999,16 @@ static void PrintTestPartResult(const TestPartResult& test_part_result) { } // class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \ + !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. static WORD GetColorAttribute(GTestColor color) { switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; - default: return 0; + default: return 0; } } @@ -2969,20 +3047,20 @@ static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. -static const char* GetAnsiColorCode(GTestColor color) { +static const char *GetAnsiColorCode(GTestColor color) { switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; - default: return NULL; - }; + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return nullptr; + } } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE -// Returns true iff Google Test should use colors in the output. +// Returns true if and only if Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { - const char* const gtest_color = GTEST_FLAG(color).c_str(); + const char *const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW @@ -2991,7 +3069,7 @@ bool ShouldUseColor(bool stdout_is_tty) { return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::GetEnv("TERM"); + const char *const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || @@ -3009,9 +3087,9 @@ bool ShouldUseColor(bool stdout_is_tty) { } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || - String::CaseInsensitiveCStringEquals(gtest_color, "true") || - String::CaseInsensitiveCStringEquals(gtest_color, "t") || - String::CStringEquals(gtest_color, "1"); + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. @@ -3021,19 +3099,18 @@ bool ShouldUseColor(bool stdout_is_tty) { // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. -static void ColoredPrintf(GTestColor color, const char* fmt, ...) { +void ColoredPrintf(GTestColor color, const char *fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ - GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { vprintf(fmt, args); @@ -3041,8 +3118,8 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \ + !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -3075,18 +3152,17 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) { static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; -static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { - const char* const type_param = test_info.type_param(); - const char* const value_param = test_info.value_param(); +static void PrintFullTestCommentIfPresent(const TestInfo &test_info) { + const char *const type_param = test_info.type_param(); + const char *const value_param = test_info.value_param(); - if (type_param != NULL || value_param != NULL) { + if (type_param != nullptr || value_param != nullptr) { printf(", where "); - if (type_param != NULL) { + if (type_param != nullptr) { printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); + if (value_param != nullptr) printf(" and "); } - if (value_param != NULL) { + if (value_param != nullptr) { printf("%s = %s", kValueParamLabel, value_param); } } @@ -3098,48 +3174,59 @@ static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); + static void PrintTestName(const char *test_suite, const char *test) { + printf("%s.%s", test_suite, test); } // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest & /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest &unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest &unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest & /*unit_test*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase &test_case) override; +#else + void OnTestSuiteStart(const TestSuite &test_suite) override; +#endif // OnTestCaseStart + + void OnTestStart(const TestInfo &test_info) override; + + void OnTestPartResult(const TestPartResult &result) override; + void OnTestEnd(const TestInfo &test_info) override; +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase &test_case) override; +#else + void OnTestSuiteEnd(const TestSuite &test_suite) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest &unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest & /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest & /*unit_test*/) override {} private: - static void PrintFailedTests(const UnitTest& unit_test); + static void PrintFailedTests(const UnitTest &unit_test); + static void PrintFailedTestSuites(const UnitTest &unit_test); + static void PrintSkippedTests(const UnitTest &unit_test); }; - // Fired before each iteration of tests starts. +// Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( - const UnitTest& unit_test, int iteration) { + const UnitTest &unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); - const char* const filter = GTEST_FLAG(filter).c_str(); + const char *const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); + ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %d of %s.\n", + const int32_t shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } @@ -3150,147 +3237,226 @@ void PrettyUnitTestResultPrinter::OnTestIterationStart( unit_test.random_seed()); } - ColoredPrintf(COLOR_GREEN, "[==========] "); + ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); + const UnitTest & /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase &test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { + if (test_case.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteStart( + const TestSuite &test_suite) { + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_suite.name()); + if (test_suite.type_param() == nullptr) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); + } + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo &test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); + const TestPartResult &result) { + switch (result.type()) { + // If the test part succeeded, we don't need to do anything. + case TestPartResult::kSuccess: return; + default: + // Print failure message from the assertion + // (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); + } } -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo &test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else if (test_info.result()->Skipped()) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } - PrintTestName(test_info.test_case_name(), test_info.name()); - if (test_info.result()->Failed()) - PrintFullTestCommentIfPresent(test_info); + PrintTestName(test_info.test_suite_name(), test_info.name()); + if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { - printf(" (%s ms)\n", internal::StreamableToString( - test_info.result()->elapsed_time()).c_str()); + printf(" (%s ms)\n", + internal::StreamableToString(test_info.result()->elapsed_time()) + .c_str()); } else { printf("\n"); } fflush(stdout); } -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase &test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } +#else +void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite &test_suite) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), + internal::StreamableToString(test_suite.elapsed_time()).c_str()); + fflush(stdout); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); + const UnitTest & /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. -void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest &unit_test) { const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite &test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { continue; } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo &test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); + printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } + printf("\n%2d FAILED %s\n", failed_test_count, + failed_test_count == 1 ? "TEST" : "TESTS"); +} + +// Internal helper for printing the list of test suite failures not covered by +// PrintFailedTests. +void PrettyUnitTestResultPrinter::PrintFailedTestSuites( + const UnitTest &unit_test) { + int suite_failure_count = 0; + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite &test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run()) { + continue; + } + if (test_suite.ad_hoc_test_result().Failed()) { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s: SetUpTestSuite or TearDownTestSuite\n", test_suite.name()); + ++suite_failure_count; + } + } + if (suite_failure_count > 0) { + printf("\n%2d FAILED TEST %s\n", suite_failure_count, + suite_failure_count == 1 ? "SUITE" : "SUITES"); + } +} + +// Internal helper for printing the list of skipped tests. +void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest &unit_test) { + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + const TestSuite &test_suite = *unit_test.GetTestSuite(i); + if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_suite.total_test_count(); ++j) { + const TestInfo &test_info = *test_suite.GetTestInfo(j); + if (!test_info.should_run() || !test_info.result()->Skipped()) { + continue; + } + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s.%s", test_suite.name(), test_info.name()); + printf("\n"); + } + } } -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest &unit_test, int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); + ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - int num_failures = unit_test.failed_test_count(); + const int skipped_test_count = unit_test.skipped_test_count(); + if (skipped_test_count > 0) { + ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); + printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); + PrintSkippedTests(unit_test); + } + if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); + PrintFailedTestSuites(unit_test); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { + if (unit_test.Passed()) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, + ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. @@ -3305,35 +3471,43 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); + ~TestEventRepeater() override; void Append(TestEventListener *listener); - TestEventListener* Release(TestEventListener* listener); + TestEventListener *Release(TestEventListener *listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); + void OnTestProgramStart(const UnitTest &unit_test) override; + void OnTestIterationStart(const UnitTest &unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest &unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest &unit_test) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestSuite ¶meter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteStart(const TestSuite ¶meter) override; + void OnTestStart(const TestInfo &test_info) override; + void OnTestPartResult(const TestPartResult &result) override; + void OnTestEnd(const TestInfo &test_info) override; +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase ¶meter) override; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestSuiteEnd(const TestSuite ¶meter) override; + void OnEnvironmentsTearDownStart(const UnitTest &unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest &unit_test) override; + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest &unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. - std::vector listeners_; + std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; @@ -3346,55 +3520,62 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// FIXME: Factor the search functionality into Vector::Find. -TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { +TestEventListener *TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); + listeners_.erase(listeners_.begin() + static_cast(i)); return listener; } } - return NULL; + return nullptr; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. -#define GTEST_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (size_t i = 0; i < listeners_.size(); i++) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} +#define GTEST_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type ¶meter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ + } // This defines a member that forwards the call to all listeners in reverse // order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ + void TestEventRepeater::Name(const Type ¶meter) { \ + if (forwarding_enabled_) { \ + for (size_t i = listeners_.size(); i != 0; i--) { \ + listeners_[i - 1]->Name(parameter); \ + } \ + } \ + } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ -void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, +void TestEventRepeater::OnTestIterationStart(const UnitTest &unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { @@ -3403,11 +3584,11 @@ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, } } -void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, +void TestEventRepeater::OnTestIterationEnd(const UnitTest &unit_test, int iteration) { if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); + for (size_t i = listeners_.size(); i > 0; i--) { + listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); } } } @@ -3417,14 +3598,14 @@ void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: - explicit XmlUnitTestResultPrinter(const char* output_file); + explicit XmlUnitTestResultPrinter(const char *output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - void ListTestsMatchingFilter(const std::vector& test_cases); + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; + void ListTestsMatchingFilter(const std::vector &test_suites); // Prints an XML summary of all unit tests. - static void PrintXmlTestsList(std::ostream* stream, - const std::vector& test_cases); + static void PrintXmlTestsList(std::ostream *stream, + const std::vector &test_suites); private: // Is c a whitespace character that is normalized to a space character @@ -3442,54 +3623,54 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. - static std::string EscapeXml(const std::string& str, bool is_attribute); + static std::string EscapeXml(const std::string &str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. - static std::string RemoveInvalidXmlCharacters(const std::string& str); + static std::string RemoveInvalidXmlCharacters(const std::string &str); // Convenience wrapper around EscapeXml when str is an attribute value. - static std::string EscapeXmlAttribute(const std::string& str) { + static std::string EscapeXmlAttribute(const std::string &str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. - static std::string EscapeXmlText(const char* str) { + static std::string EscapeXmlText(const char *str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. - static void OutputXmlAttribute(std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value); + static void OutputXmlAttribute(std::ostream *stream, + const std::string &element_name, + const std::string &name, + const std::string &value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. - static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + static void OutputXmlCDataSection(::std::ostream *stream, const char *data); // Streams an XML representation of a TestInfo object. - static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); + static void OutputXmlTestInfo(::std::ostream *stream, + const char *test_suite_name, + const TestInfo &test_info); - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints an XML representation of a TestSuite object + static void PrintXmlTestSuite(::std::ostream *stream, + const TestSuite &test_suite); // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(::std::ostream* stream, - const UnitTest& unit_test); + static void PrintXmlUnitTest(::std::ostream *stream, + const UnitTest &unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. - static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + static std::string TestPropertiesAsXmlAttributes(const TestResult &result); // Streams an XML representation of the test properties of a TestResult // object. - static void OutputXmlTestProperties(std::ostream* stream, - const TestResult& result); + static void OutputXmlTestProperties(std::ostream *stream, + const TestResult &result); // The output file. const std::string output_file_; @@ -3498,7 +3679,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { }; // Creates a new XmlUnitTestResultPrinter. -XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char *output_file) : output_file_(output_file) { if (output_file_.empty()) { GTEST_LOG_(FATAL) << "XML output file may not be null"; @@ -3506,9 +3687,9 @@ XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) } // Called after the unit test ends. -void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest &unit_test, int /*iteration*/) { - FILE* xmlout = OpenFileForWriting(output_file_); + FILE *xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); @@ -3516,10 +3697,10 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, } void XmlUnitTestResultPrinter::ListTestsMatchingFilter( - const std::vector& test_cases) { - FILE* xmlout = OpenFileForWriting(output_file_); + const std::vector &test_suites) { + FILE *xmlout = OpenFileForWriting(output_file_); std::stringstream stream; - PrintXmlTestsList(&stream, test_cases); + PrintXmlTestsList(&stream, test_suites); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } @@ -3534,24 +3715,16 @@ void XmlUnitTestResultPrinter::ListTestsMatchingFilter( // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// FIXME: It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. -std::string XmlUnitTestResultPrinter::EscapeXml( - const std::string& str, bool is_attribute) { +std::string XmlUnitTestResultPrinter::EscapeXml(const std::string &str, + bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; + case '<': m << "<"; break; + case '>': m << ">"; break; + case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; @@ -3583,12 +3756,11 @@ std::string XmlUnitTestResultPrinter::EscapeXml( // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( - const std::string& str) { + const std::string &str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) - if (IsValidXmlCharacter(*it)) - output.push_back(*it); + if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } @@ -3600,7 +3772,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object +// <-- corresponds to a TestSuite object // <-- corresponds to a TestInfo object // ... // ... @@ -3617,19 +3789,18 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { return ss.str(); } -static bool PortableLocaltime(time_t seconds, struct tm* out) { +static bool PortableLocaltime(time_t seconds, struct tm *out) { #if defined(_MSC_VER) return localtime_s(out, &seconds) == 0; #elif defined(__MINGW32__) || defined(__MINGW64__) // MINGW provides neither localtime_r nor localtime_s, but uses // Windows' localtime(), which has a thread-local tm buffer. - struct tm* tm_ptr = localtime(&seconds); // NOLINT - if (tm_ptr == NULL) - return false; + struct tm *tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == nullptr) return false; *out = *tm_ptr; return true; #else - return localtime_r(&seconds, out) != NULL; + return localtime_r(&seconds, out) != nullptr; #endif } @@ -3641,23 +3812,23 @@ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct.tm_mday) + "T" + - String::FormatIntWidth2(time_struct.tm_hour) + ":" + - String::FormatIntWidth2(time_struct.tm_min) + ":" + - String::FormatIntWidth2(time_struct.tm_sec); + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, - const char* data) { - const char* segment = data; +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream *stream, + const char *data) { + const char *segment = data; *stream << ""); - if (next_segment != NULL) { - stream->write( - segment, static_cast(next_segment - segment)); + const char *const next_segment = strstr(segment, "]]>"); + if (next_segment != nullptr) { + stream->write(segment, + static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { @@ -3669,15 +3840,13 @@ void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, } void XmlUnitTestResultPrinter::OutputXmlAttribute( - std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value) { - const std::vector& allowed_names = - GetReservedAttributesForElement(element_name); + std::ostream *stream, const std::string &element_name, + const std::string &name, const std::string &value) { + const std::vector &allowed_names = + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != - allowed_names.end()) + allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; @@ -3685,44 +3854,51 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// FIXME: There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream *stream, + const char *test_suite_name, + const TestInfo &test_info) { + const TestResult &result = *test_info.result(); + const std::string kTestsuite = "testcase"; if (test_info.is_in_another_shard()) { return; } *stream << " \n"; return; } - OutputXmlAttribute(stream, kTestcase, "status", + OutputXmlAttribute(stream, kTestsuite, "status", test_info.should_run() ? "run" : "notrun"); - OutputXmlAttribute(stream, kTestcase, "time", + OutputXmlAttribute(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "skipped" : "completed") + : "suppressed"); + OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); - OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); + OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { - const TestPartResult& part = result.GetTestPartResult(i); + const TestPartResult &part = result.GetTestPartResult(i); if (part.failed()) { if (++failures == 1) { *stream << ">\n"; @@ -3732,8 +3908,7 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, part.line_number()); const std::string summary = location + "\n" + part.summary(); *stream << " "; + << EscapeXmlAttribute(summary.c_str()) << "\" type=\"\">"; const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; @@ -3751,36 +3926,39 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, } } -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an XML representation of a TestSuite object +void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream *stream, + const TestSuite &test_suite) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); + StreamableToString(test_suite.reportable_test_count())); if (!GTEST_FLAG(list_tests)) { OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); + StreamableToString(test_suite.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); + StreamableToString(test_suite.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); + OutputXmlAttribute( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); + *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); } *stream << ">\n"; - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, - const UnitTest& unit_test) { +void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream *stream, + const UnitTest &unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; @@ -3794,11 +3972,11 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", @@ -3809,31 +3987,31 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) + PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); } *stream << "\n"; } void XmlUnitTestResultPrinter::PrintXmlTestsList( - std::ostream* stream, const std::vector& test_cases) { + std::ostream *stream, const std::vector &test_suites) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; int total_tests = 0; - for (size_t i = 0; i < test_cases.size(); ++i) { - total_tests += test_cases[i]->total_test_count(); + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); } OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(total_tests)); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; - for (size_t i = 0; i < test_cases.size(); ++i) { - PrintXmlTestCase(stream, *test_cases[i]); + for (auto test_suite : test_suites) { + PrintXmlTestSuite(stream, *test_suite); } *stream << "\n"; } @@ -3841,18 +4019,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestsList( // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { + const TestResult &result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); + const TestProperty &property = result.GetTestProperty(i); attributes << " " << property.key() << "=" - << "\"" << EscapeXmlAttribute(property.value()) << "\""; + << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } void XmlUnitTestResultPrinter::OutputXmlTestProperties( - std::ostream* stream, const TestResult& result) { + std::ostream *stream, const TestResult &result) { const std::string kProperties = "properties"; const std::string kProperty = "property"; @@ -3862,7 +4040,7 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties( *stream << "<" << kProperties << ">\n"; for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); + const TestProperty &property = result.GetTestProperty(i); *stream << "<" << kProperty; *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; @@ -3876,50 +4054,46 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties( // This class generates an JSON output file. class JsonUnitTestResultPrinter : public EmptyTestEventListener { public: - explicit JsonUnitTestResultPrinter(const char* output_file); + explicit JsonUnitTestResultPrinter(const char *output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; // Prints an JSON summary of all unit tests. - static void PrintJsonTestList(::std::ostream* stream, - const std::vector& test_cases); + static void PrintJsonTestList(::std::ostream *stream, + const std::vector &test_suites); private: // Returns an JSON-escaped copy of the input string str. - static std::string EscapeJson(const std::string& str); + static std::string EscapeJson(const std::string &str); //// Verifies that the given attribute belongs to the given element and //// streams the attribute as JSON. - static void OutputJsonKey(std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value, - const std::string& indent, - bool comma = true); - static void OutputJsonKey(std::ostream* stream, - const std::string& element_name, - const std::string& name, - int value, - const std::string& indent, - bool comma = true); + static void OutputJsonKey(std::ostream *stream, + const std::string &element_name, + const std::string &name, const std::string &value, + const std::string &indent, bool comma = true); + static void OutputJsonKey(std::ostream *stream, + const std::string &element_name, + const std::string &name, int value, + const std::string &indent, bool comma = true); // Streams a JSON representation of a TestInfo object. - static void OutputJsonTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); + static void OutputJsonTestInfo(::std::ostream *stream, + const char *test_suite_name, + const TestInfo &test_info); - // Prints a JSON representation of a TestCase object - static void PrintJsonTestCase(::std::ostream* stream, - const TestCase& test_case); + // Prints a JSON representation of a TestSuite object + static void PrintJsonTestSuite(::std::ostream *stream, + const TestSuite &test_suite); // Prints a JSON summary of unit_test to output stream out. - static void PrintJsonUnitTest(::std::ostream* stream, - const UnitTest& unit_test); + static void PrintJsonUnitTest(::std::ostream *stream, + const UnitTest &unit_test); // Produces a string representing the test properties in a result as // a JSON dictionary. - static std::string TestPropertiesAsJson(const TestResult& result, - const std::string& indent); + static std::string TestPropertiesAsJson(const TestResult &result, + const std::string &indent); // The output file. const std::string output_file_; @@ -3928,16 +4102,16 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { }; // Creates a new JsonUnitTestResultPrinter. -JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char *output_file) : output_file_(output_file) { if (output_file_.empty()) { GTEST_LOG_(FATAL) << "JSON output file may not be null"; } } -void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - FILE* jsonout = OpenFileForWriting(output_file_); +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest &unit_test, + int /*iteration*/) { + FILE *jsonout = OpenFileForWriting(output_file_); std::stringstream stream; PrintJsonUnitTest(&stream, unit_test); fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); @@ -3945,7 +4119,7 @@ void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, } // Returns an JSON-escaped copy of the input string str. -std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string &str) { Message m; for (size_t i = 0; i < str.size(); ++i) { @@ -3953,24 +4127,12 @@ std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { switch (ch) { case '\\': case '"': - case '/': - m << '\\' << ch; - break; - case '\b': - m << "\\b"; - break; - case '\t': - m << "\\t"; - break; - case '\n': - m << "\\n"; - break; - case '\f': - m << "\\f"; - break; - case '\r': - m << "\\r"; - break; + case '/': m << '\\' << ch; break; + case '\b': m << "\\b"; break; + case '\t': m << "\\t"; break; + case '\n': m << "\\n"; break; + case '\f': m << "\\f"; break; + case '\r': m << "\\r"; break; default: if (ch < ' ') { m << "\\u00" << String::FormatByte(static_cast(ch)); @@ -4002,97 +4164,101 @@ static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct.tm_mday) + "T" + - String::FormatIntWidth2(time_struct.tm_hour) + ":" + - String::FormatIntWidth2(time_struct.tm_min) + ":" + - String::FormatIntWidth2(time_struct.tm_sec) + "Z"; + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; } -static inline std::string Indent(int width) { +static inline std::string Indent(size_t width) { return std::string(width, ' '); } -void JsonUnitTestResultPrinter::OutputJsonKey( - std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value, - const std::string& indent, - bool comma) { - const std::vector& allowed_names = - GetReservedAttributesForElement(element_name); +void JsonUnitTestResultPrinter::OutputJsonKey(std::ostream *stream, + const std::string &element_name, + const std::string &name, + const std::string &value, + const std::string &indent, + bool comma) { + const std::vector &allowed_names = + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != - allowed_names.end()) + allowed_names.end()) << "Key \"" << name << "\" is not allowed for value \"" << element_name << "\"."; *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; - if (comma) - *stream << ",\n"; + if (comma) *stream << ",\n"; } void JsonUnitTestResultPrinter::OutputJsonKey( - std::ostream* stream, - const std::string& element_name, - const std::string& name, - int value, - const std::string& indent, - bool comma) { - const std::vector& allowed_names = - GetReservedAttributesForElement(element_name); + std::ostream *stream, const std::string &element_name, + const std::string &name, int value, const std::string &indent, bool comma) { + const std::vector &allowed_names = + GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != - allowed_names.end()) + allowed_names.end()) << "Key \"" << name << "\" is not allowed for value \"" << element_name << "\"."; *stream << indent << "\"" << name << "\": " << StreamableToString(value); - if (comma) - *stream << ",\n"; + if (comma) *stream << ",\n"; } // Prints a JSON representation of a TestInfo object. -void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream *stream, + const char *test_suite_name, + const TestInfo &test_info) { + const TestResult &result = *test_info.result(); + const std::string kTestsuite = "testcase"; const std::string kIndent = Indent(10); *stream << Indent(8) << "{\n"; - OutputJsonKey(stream, kTestcase, "name", test_info.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); - if (test_info.value_param() != NULL) { - OutputJsonKey(stream, kTestcase, "value_param", - test_info.value_param(), kIndent); + if (test_info.value_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), + kIndent); } - if (test_info.type_param() != NULL) { - OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(), + if (test_info.type_param() != nullptr) { + OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), kIndent); } if (GTEST_FLAG(list_tests)) { - OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent); - OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false); + OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); *stream << "\n" << Indent(8) << "}"; return; } - OutputJsonKey(stream, kTestcase, "status", + OutputJsonKey(stream, kTestsuite, "status", test_info.should_run() ? "RUN" : "NOTRUN", kIndent); - OutputJsonKey(stream, kTestcase, "time", + OutputJsonKey(stream, kTestsuite, "result", + test_info.should_run() + ? (result.Skipped() ? "SKIPPED" : "COMPLETED") + : "SUPPRESSED", + kIndent); + OutputJsonKey(stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuite, "time", FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); - OutputJsonKey(stream, kTestcase, "classname", test_case_name, kIndent, false); + OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, + false); *stream << TestPropertiesAsJson(result, kIndent); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { - const TestPartResult& part = result.GetTestPartResult(i); + const TestPartResult &part = result.GetTestPartResult(i); if (part.failed()) { *stream << ",\n"; if (++failures == 1) { - *stream << kIndent << "\"" << "failures" << "\": [\n"; + *stream << kIndent << "\"" + << "failures" + << "\": [\n"; } const std::string location = internal::FormatCompilerIndependentFileLocation(part.file_name(), @@ -4105,53 +4271,56 @@ void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, } } - if (failures > 0) - *stream << "\n" << kIndent << "]"; + if (failures > 0) *stream << "\n" << kIndent << "]"; *stream << "\n" << Indent(8) << "}"; } -// Prints an JSON representation of a TestCase object -void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream, - const TestCase& test_case) { +// Prints an JSON representation of a TestSuite object +void JsonUnitTestResultPrinter::PrintJsonTestSuite( + std::ostream *stream, const TestSuite &test_suite) { const std::string kTestsuite = "testsuite"; const std::string kIndent = Indent(6); *stream << Indent(4) << "{\n"; - OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent); - OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(), + OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), kIndent); if (!GTEST_FLAG(list_tests)) { - OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), - kIndent); + OutputJsonKey(stream, kTestsuite, "failures", + test_suite.failed_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "disabled", - test_case.reportable_disabled_test_count(), kIndent); + test_suite.reportable_disabled_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey( + stream, kTestsuite, "timestamp", + FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), + kIndent); OutputJsonKey(stream, kTestsuite, "time", - FormatTimeInMillisAsDuration(test_case.elapsed_time()), + FormatTimeInMillisAsDuration(test_suite.elapsed_time()), kIndent, false); - *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) << ",\n"; } *stream << kIndent << "\"" << kTestsuite << "\": [\n"; bool comma = false; - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) { + for (int i = 0; i < test_suite.total_test_count(); ++i) { + if (test_suite.GetTestInfo(i)->is_reportable()) { if (comma) { *stream << ",\n"; } else { comma = true; } - OutputJsonTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } } *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; } // Prints a JSON summary of unit_test to output stream out. -void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, - const UnitTest& unit_test) { +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream *stream, + const UnitTest &unit_test) { const std::string kTestsuites = "testsuites"; const std::string kIndent = Indent(2); *stream << "{\n"; @@ -4181,39 +4350,41 @@ void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, *stream << kIndent << "\"" << kTestsuites << "\": [\n"; bool comma = false; - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) { + for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { + if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { if (comma) { *stream << ",\n"; } else { comma = true; } - PrintJsonTestCase(stream, *unit_test.GetTestCase(i)); + PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); } } - *stream << "\n" << kIndent << "]\n" << "}\n"; + *stream << "\n" + << kIndent << "]\n" + << "}\n"; } void JsonUnitTestResultPrinter::PrintJsonTestList( - std::ostream* stream, const std::vector& test_cases) { + std::ostream *stream, const std::vector &test_suites) { const std::string kTestsuites = "testsuites"; const std::string kIndent = Indent(2); *stream << "{\n"; int total_tests = 0; - for (size_t i = 0; i < test_cases.size(); ++i) { - total_tests += test_cases[i]->total_test_count(); + for (auto test_suite : test_suites) { + total_tests += test_suite->total_test_count(); } OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); *stream << kIndent << "\"" << kTestsuites << "\": [\n"; - for (size_t i = 0; i < test_cases.size(); ++i) { + for (size_t i = 0; i < test_suites.size(); ++i) { if (i != 0) { *stream << ",\n"; } - PrintJsonTestCase(stream, *test_cases[i]); + PrintJsonTestSuite(stream, *test_suites[i]); } *stream << "\n" @@ -4223,11 +4394,12 @@ void JsonUnitTestResultPrinter::PrintJsonTestList( // Produces a string representing the test properties in a result as // a JSON dictionary. std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( - const TestResult& result, const std::string& indent) { + const TestResult &result, const std::string &indent) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << ",\n" << indent << "\"" << property.key() << "\": " + const TestProperty &property = result.GetTestProperty(i); + attributes << ",\n" + << indent << "\"" << property.key() << "\": " << "\"" << EscapeJson(property.value()) << "\""; } return attributes.GetString(); @@ -4242,7 +4414,7 @@ std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. -std::string StreamingListener::UrlEncode(const char* str) { +std::string StreamingListener::UrlEncode(const char *str) { std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { @@ -4253,9 +4425,7 @@ std::string StreamingListener::UrlEncode(const char* str) { case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; - default: - result.push_back(ch); - break; + default: result.push_back(ch); break; } } return result; @@ -4267,24 +4437,24 @@ void StreamingListener::SocketWriter::MakeConnection() { addrinfo hints; memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; + addrinfo *servinfo = nullptr; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. - const int error_num = getaddrinfo( - host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + const int error_num = + getaddrinfo(host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + for (addrinfo *cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; cur_addr = cur_addr->ai_next) { - sockfd_ = socket( - cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + sockfd_ = socket(cur_addr->ai_family, cur_addr->ai_socktype, + cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { @@ -4307,7 +4477,7 @@ void StreamingListener::SocketWriter::MakeConnection() { // class OsStackTraceGetter -const char* const OsStackTraceGetterInterface::kElidedFramesMarker = +const char *const OsStackTraceGetterInterface::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) @@ -4321,12 +4491,12 @@ std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) max_depth = std::min(max_depth, kMaxStackTraceDepth); - std::vector raw_stack(max_depth); + std::vector raw_stack(max_depth); // Skips the frames requested by the caller, plus this function. const int raw_stack_size = absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); - void* caller_frame = nullptr; + void *caller_frame = nullptr; { MutexLock lock(&mutex_); caller_frame = caller_frame_; @@ -4341,7 +4511,7 @@ std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) } char tmp[1024]; - const char* symbol = "(unknown)"; + const char *symbol = "(unknown)"; if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { symbol = tmp; } @@ -4353,7 +4523,7 @@ std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) return result; -#else // !GTEST_HAS_ABSL +#else // !GTEST_HAS_ABSL static_cast(max_depth); static_cast(skip_count); return ""; @@ -4362,7 +4532,7 @@ std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { #if GTEST_HAS_ABSL - void* caller_frame = nullptr; + void *caller_frame = nullptr; if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { caller_frame = nullptr; } @@ -4376,21 +4546,22 @@ void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: - explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath ? - premature_exit_filepath : "") { + explicit ScopedPrematureExitFile(const char *premature_exit_filepath) + : premature_exit_filepath_( + premature_exit_filepath ? premature_exit_filepath : "") { // If a path to the premature-exit file is specified... if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. - FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); + FILE *pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { +#if !defined GTEST_OS_ESP8266 if (!premature_exit_filepath_.empty()) { int retval = remove(premature_exit_filepath_.c_str()); if (retval) { @@ -4399,6 +4570,7 @@ class ScopedPrematureExitFile { << retval; } } +#endif } private: @@ -4413,9 +4585,7 @@ class ScopedPrematureExitFile { TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} + default_result_printer_(nullptr), default_xml_generator_(nullptr) {} TestEventListeners::~TestEventListeners() { delete repeater_; } @@ -4423,38 +4593,37 @@ TestEventListeners::~TestEventListeners() { delete repeater_; } // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. -void TestEventListeners::Append(TestEventListener* listener) { +void TestEventListeners::Append(TestEventListener *listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. -TestEventListener* TestEventListeners::Release(TestEventListener* listener) { +TestEventListener *TestEventListeners::Release(TestEventListener *listener) { if (listener == default_result_printer_) - default_result_printer_ = NULL; + default_result_printer_ = nullptr; else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; + default_xml_generator_ = nullptr; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. -TestEventListener* TestEventListeners::repeater() { return repeater_; } +TestEventListener *TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { +void TestEventListeners::SetDefaultResultPrinter(TestEventListener *listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -4463,14 +4632,13 @@ void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener *listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); + if (listener != nullptr) Append(listener); } } @@ -4493,53 +4661,67 @@ void TestEventListeners::SuppressEventForwarding() { // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. -UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - +UnitTest *UnitTest::GetInstance() { // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) - static UnitTest* const instance = new UnitTest; +#if defined(__BORLANDC__) + static UnitTest *const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +#endif // defined(__BORLANDC__) } -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); +// Gets the number of successful test suites. +int UnitTest::successful_test_suite_count() const { + return impl()->successful_test_suite_count(); } -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); +// Gets the number of failed test suites. +int UnitTest::failed_test_suite_count() const { + return impl()->failed_test_suite_count(); } -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); +// Gets the number of all test suites. +int UnitTest::total_test_suite_count() const { + return impl()->total_test_suite_count(); } -// Gets the number of all test cases that contain at least one test +// Gets the number of all test suites that contain at least one test // that should run. -int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); +int UnitTest::test_suite_to_run_count() const { + return impl()->test_suite_to_run_count(); } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_suite_count(); +} +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_suite_count(); +} +int UnitTest::total_test_case_count() const { + return impl()->total_test_suite_count(); +} +int UnitTest::test_case_to_run_count() const { + return impl()->test_suite_to_run_count(); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } +// Gets the number of skipped tests. +int UnitTest::skipped_test_count() const { + return impl()->skipped_test_count(); +} + // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } @@ -4567,7 +4749,7 @@ int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { - return impl()->start_timestamp(); + return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. @@ -4575,36 +4757,42 @@ internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } -// Returns true iff the unit test passed (i.e. all test cases passed). +// Returns true if and only if the unit test passed (i.e. all test suites +// passed). bool UnitTest::Passed() const { return impl()->Passed(); } -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). +// Returns true if and only if the unit test failed (i.e. some test suite +// failed or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -const TestCase* UnitTest::GetTestCase(int i) const { - return impl()->GetTestCase(i); +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +const TestSuite *UnitTest::GetTestSuite(int i) const { + return impl()->GetTestSuite(i); } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +const TestCase *UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + // Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. -const TestResult& UnitTest::ad_hoc_test_result() const { +// properties logged outside of individual test suites. +const TestResult &UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); +// Gets the i-th test suite among all the test suites. i can range from 0 to +// total_test_suite_count() - 1. If i is not in that range, returns NULL. +TestSuite *UnitTest::GetMutableTestSuite(int i) { + return impl()->GetMutableSuiteCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. -TestEventListeners& UnitTest::listeners() { - return *impl()->listeners(); -} +TestEventListeners &UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the @@ -4616,9 +4804,9 @@ TestEventListeners& UnitTest::listeners() { // // We don't protect this under mutex_, as we only support calling it // from the main thread. -Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; +Environment *UnitTest::AddEnvironment(Environment *env) { + if (env == nullptr) { + return nullptr; } impl_->environments().push_back(env); @@ -4629,12 +4817,11 @@ Environment* UnitTest::AddEnvironment(Environment* env) { // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. -void UnitTest::AddTestPartResult( - TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char *file_name, int line_number, + const std::string &message, + const std::string &os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; @@ -4642,25 +4829,25 @@ void UnitTest::AddTestPartResult( if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { - const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; - msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) - << " " << trace.message; + for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { + const internal::TraceInfo &trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" + << internal::FormatFileLocation(trace.file, trace.line) << " " + << trace.message; } } - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); - impl_->GetTestPartResultReporterForCurrentThread()-> - ReportTestPartResult(result); + const TestPartResult result = TestPartResult( + result_type, file_name, line_number, msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult( + result); - if (result_type != TestPartResult::kSuccess) { + if (result_type != TestPartResult::kSuccess && + result_type != TestPartResult::kSkip) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions @@ -4678,11 +4865,10 @@ void UnitTest::AddTestPartResult( // with clang/gcc we can achieve the same effect on x86 by invoking int3 asm("int3"); #else - // Dereference NULL through a volatile pointer to prevent the compiler + // Dereference nullptr through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast(NULL) = 1; + // portability: some debuggers don't correctly trap abort(). + *static_cast(nullptr) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS @@ -4697,12 +4883,12 @@ void UnitTest::AddTestPartResult( } // Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set +// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked +// from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. -void UnitTest::RecordProperty(const std::string& key, - const std::string& value) { +void UnitTest::RecordProperty(const std::string &key, + const std::string &value) { impl_->RecordProperty(TestProperty(key, value)); } @@ -4737,8 +4923,9 @@ int UnitTest::Run() { // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + in_death_test_child_process + ? nullptr + : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. @@ -4750,62 +4937,76 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -# endif // !GTEST_OS_WINDOWS_MOBILE +#endif // !GTEST_OS_WINDOWS_MOBILE -# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE +#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); -# endif +#endif -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +#if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // FIXME: find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -# endif + + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + if (!IsDebuggerPresent()) { + (void)_CrtSetReportMode(_CRT_ASSERT, + _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } +#endif } #endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( - impl(), - &internal::UnitTestImpl::RunAllTests, - "auxiliary test code (environments or event listeners)") ? 0 : 1; + impl(), &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") + ? 0 + : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. -const char* UnitTest::original_working_dir() const { +const char *UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } -// Returns the TestCase object for the test that's currently running, +// Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. -const TestCase* UnitTest::current_test_case() const +const TestSuite *UnitTest::current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); + return impl_->current_test_suite(); } +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +const TestCase *UnitTest::current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_suite(); +} +#endif + // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. -const TestInfo* UnitTest::current_test_info() const +const TestInfo *UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); @@ -4814,63 +5015,51 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -// Returns ParameterizedTestCaseRegistry object used to keep track of +// Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { +internal::ParameterizedTestSuiteRegistry & +UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } // Creates an empty UnitTest. -UnitTest::UnitTest() { - impl_ = new internal::UnitTestImpl(this); -} +UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. -UnitTest::~UnitTest() { - delete impl_; -} +UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. -void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) +void UnitTest::PushGTestTrace(const internal::TraceInfo &trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. -void UnitTest::PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_) { +void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { -UnitTestImpl::UnitTestImpl(UnitTest* parent) +UnitTestImpl::UnitTestImpl(UnitTest *parent) : parent_(parent), GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) - default_global_test_part_result_reporter_(this), + default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), - GTEST_DISABLE_MSC_WARNINGS_POP_() - global_test_part_result_repoter_( + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), - parameterized_test_registry_(), - parameterized_tests_registered_(false), - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), - ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), - post_flag_parse_init_performed_(false), + parameterized_test_registry_(), parameterized_tests_registered_(false), + last_death_test_suite_(-1), current_test_suite_(nullptr), + current_test_info_(nullptr), ad_hoc_test_result_(), + os_stack_trace_getter_(nullptr), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. - start_timestamp_(0), - elapsed_time_(0), + random_(0), // Will be reseeded before first use. + start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif @@ -4880,8 +5069,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) } UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); + // Deletes every TestSuite. + ForEach(test_suites_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); @@ -4890,20 +5079,20 @@ UnitTestImpl::~UnitTestImpl() { } // Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set +// context of a test, to current test suite's ad_hoc_test_result when invoke +// from SetUpTestSuite/TearDownTestSuite, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. -void UnitTestImpl::RecordProperty(const TestProperty& test_property) { +void UnitTestImpl::RecordProperty(const TestProperty &test_property) { std::string xml_element; - TestResult* test_result; // TestResult appropriate for property recording. + TestResult *test_result; // TestResult appropriate for property recording. - if (current_test_info_ != NULL) { + if (current_test_info_ != nullptr) { xml_element = "testcase"; test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { + } else if (current_test_suite_ != nullptr) { xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); + test_result = &(current_test_suite_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; @@ -4915,7 +5104,7 @@ void UnitTestImpl::RecordProperty(const TestProperty& test_property) { // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) + if (internal_run_death_test_flag_.get() != nullptr) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST @@ -4923,7 +5112,7 @@ void UnitTestImpl::SuppressTestEventsIfInSubprocess() { // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { - const std::string& output_format = UnitTestOptions::GetOutputFormat(); + const std::string &output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); @@ -4940,12 +5129,12 @@ void UnitTestImpl::ConfigureXmlOutput() { // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { - const std::string& target = GTEST_FLAG(stream_result_to); + const std::string &target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { - listeners()->Append(new StreamingListener(target.substr(0, pos), - target.substr(pos+1))); + listeners()->Append( + new StreamingListener(target.substr(0, pos), target.substr(pos + 1))); } else { GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target << "\" ignored."; @@ -4997,80 +5186,79 @@ void UnitTestImpl::PostFlagParsingInit() { } } -// A predicate that checks the name of a TestCase against a known +// A predicate that checks the name of a TestSuite against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // -// TestCaseNameIs is copyable. -class TestCaseNameIs { +// TestSuiteNameIs is copyable. +class TestSuiteNameIs { public: // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} + explicit TestSuiteNameIs(const std::string &name) : name_(name) {} - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + // Returns true if and only if the name of test_suite matches name_. + bool operator()(const TestSuite *test_suite) const { + return test_suite != nullptr && + strcmp(test_suite->name(), name_.c_str()) == 0; } private: std::string name_; }; -// Finds and returns a TestCase with the given name. If one doesn't +// Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_reverse_iterator test_case = - std::find_if(test_cases_.rbegin(), test_cases_.rend(), - TestCaseNameIs(test_case_name)); +// test_suite_name: name of the test suite +// type_param: the name of the test suite's type parameter, or NULL if +// this is not a typed or a type-parameterized test suite. +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +TestSuite *UnitTestImpl::GetTestSuite( + const char *test_suite_name, const char *type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc) { + // Can we find a TestSuite with the given name? + const auto test_suite = + std::find_if(test_suites_.rbegin(), test_suites_.rend(), + TestSuiteNameIs(test_suite_name)); - if (test_case != test_cases_.rend()) - return *test_case; + if (test_suite != test_suites_.rend()) return *test_suite; // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + auto *const new_test_suite = + new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't + // Is this a death test suite? + if (internal::UnitTestOptions::MatchesFilter(test_suite_name, + kDeathTestSuiteFilter)) { + // Yes. Inserts the test suite after the last death test suite + // defined so far. This only works when the test suites haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); + ++last_death_test_suite_; + test_suites_.insert(test_suites_.begin() + last_death_test_suite_, + new_test_suite); } else { // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); + test_suites_.push_back(new_test_suite); } - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; + test_suite_indices_.push_back(static_cast(test_suite_indices_.size())); + return new_test_suite; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. -static void SetUpEnvironment(Environment* env) { env->SetUp(); } -static void TearDownEnvironment(Environment* env) { env->TearDown(); } +static void SetUpEnvironment(Environment *env) { env->SetUp(); } +static void TearDownEnvironment(Environment *env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is @@ -5082,12 +5270,12 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // True iff Google Test is initialized before RUN_ALL_TESTS() is called. + // True if and only if Google Test is initialized before RUN_ALL_TESTS() is + // called. const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. - if (g_help_flag) - return true; + if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. @@ -5098,17 +5286,18 @@ bool UnitTestImpl::RunAllTests() { // protocol. internal::WriteToShardStatusFileIfNeeded(); - // True iff we are in a subprocess for running a thread-safe-style + // True if and only if we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); -# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + in_subprocess_for_death_test = + (internal_run_death_test_flag_.get() != nullptr); +#if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) if (in_subprocess_for_death_test) { GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); } -# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) +#endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, @@ -5116,9 +5305,9 @@ bool UnitTestImpl::RunAllTests() { // Compares the full test names with the filter to decide which // tests to run. - const bool has_tests_to_run = FilterTests(should_shard - ? HONOR_SHARDING_PROTOCOL - : IGNORE_SHARDING_PROTOCOL) > 0; + const bool has_tests_to_run = + FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { @@ -5127,13 +5316,13 @@ bool UnitTestImpl::RunAllTests() { return true; } - random_seed_ = GTEST_FLAG(shuffle) ? - GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + random_seed_ = + GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - // True iff at least one test has failed. + // True if and only if at least one test has failed. bool failed = false; - TestEventListener* repeater = listeners()->repeater(); + TestEventListener *repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); @@ -5142,17 +5331,17 @@ bool UnitTestImpl::RunAllTests() { // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { + const bool gtest_repeat_forever = repeat < 0; + for (int i = 0; gtest_repeat_forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); - // Shuffles test cases and tests if requested. + // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); + random()->Reseed(static_cast(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. @@ -5162,19 +5351,33 @@ bool UnitTestImpl::RunAllTests() { // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); - // Runs each test case if there is at least one test to run. + // Runs each test suite if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); + // Runs the tests only if there was no fatal failure or skip triggered + // during global set-up. + if (Test::IsSkipped()) { + // Emit diagnostics when global set-up calls skip, as it will not be + // emitted by default. + TestResult &test_result = + *internal::GetUnitTestImpl()->current_test_result(); + for (int j = 0; j < test_result.total_part_count(); ++j) { + const TestPartResult &test_part_result = + test_result.GetTestPartResult(j); + if (test_part_result.type() == TestPartResult::kSkip) { + const std::string &result = test_part_result.message(); + printf("%s\n", result.c_str()); + } + } + fflush(stdout); + } else if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { - GetMutableTestCase(test_index)->Run(); + GetMutableSuiteCase(test_index)->Run(); } } @@ -5233,10 +5436,10 @@ bool UnitTestImpl::RunAllTests() { // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { - FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { + const char *const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != nullptr) { + FILE *const file = posix::FOpen(test_shard_file, "w"); + if (file == nullptr) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", @@ -5254,41 +5457,40 @@ void WriteToShardStatusFileIfNeeded() { // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_env, - const char* shard_index_env, +bool ShouldShard(const char *total_shards_env, const char *shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + const int32_t total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const int32_t shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestShardIndex << " = " << shard_index - << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + const Message msg = Message() << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards + << " unset.\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() - << "Invalid environment variables: you have " - << kTestTotalShards << " = " << total_shards - << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { - const Message msg = Message() - << "Invalid environment variables: we require 0 <= " - << kTestShardIndex << " < " << kTestTotalShards - << ", but you have " << kTestShardIndex << "=" << shard_index - << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + const Message msg = + Message() << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } @@ -5299,13 +5501,13 @@ bool ShouldShard(const char* total_shards_env, // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. -Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { - const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { +int32_t Int32FromEnvOrDie(const char *var, int32_t default_val) { + const char *str_val = posix::GetEnv(var); + if (str_val == nullptr) { return default_val; } - Int32 result; + int32_t result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); @@ -5314,8 +5516,8 @@ Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { } // Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test +// returns true if and only if the test should be run on this shard. The test id +// is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; @@ -5323,16 +5525,18 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. +// each TestSuite and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md // . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + const int32_t total_shards = shard_tests == HONOR_SHARDING_PROTOCOL + ? Int32FromEnvOrDie(kTestTotalShards, -1) + : -1; + const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL + ? Int32FromEnvOrDie(kTestShardIndex, -1) + : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). @@ -5340,26 +5544,23 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); + for (auto *test_suite : test_suites_) { + const std::string &test_suite_name = test_suite->name(); + test_suite->set_should_run(false); - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + TestInfo *const test_info = test_suite->test_info_list()[j]; const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches + // A test is disabled if test suite name or test name matches // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + const bool is_disabled = internal::UnitTestOptions::MatchesFilter( + test_suite_name, kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter( + test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); + const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( + test_suite_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = @@ -5376,7 +5577,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { num_selected_tests += is_selected; test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); + test_suite->set_should_run(test_suite->should_run() || is_selected); } } return num_selected_tests; @@ -5386,8 +5587,8 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". -static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { +static void PrintOnOneLine(const char *str, int max_length) { + if (str != nullptr) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); @@ -5409,27 +5610,25 @@ void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; + for (auto *test_suite : test_suites_) { + bool printed_test_suite_name = false; - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; + for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { + const TestInfo *const test_info = test_suite->test_info_list()[j]; if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { + if (!printed_test_suite_name) { + printed_test_suite_name = true; + printf("%s.", test_suite->name()); + if (test_suite->type_param() != nullptr) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); + PrintOnOneLine(test_suite->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { + if (test_info->value_param() != nullptr) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. @@ -5440,19 +5639,19 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); - const std::string& output_format = UnitTestOptions::GetOutputFormat(); + const std::string &output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml" || output_format == "json") { - FILE* fileout = OpenFileForWriting( + FILE *fileout = OpenFileForWriting( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); std::stringstream stream; if (output_format == "xml") { XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) - .PrintXmlTestsList(&stream, test_cases_); + .PrintXmlTestsList(&stream, test_suites_); } else if (output_format == "json") { JsonUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) - .PrintJsonTestList(&stream, test_cases_); + .PrintJsonTestList(&stream, test_suites_); } fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); fclose(fileout); @@ -5465,7 +5664,7 @@ void UnitTestImpl::ListTestsMatchingFilter() { // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( - OsStackTraceGetterInterface* getter) { + OsStackTraceGetterInterface *getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; @@ -5475,8 +5674,8 @@ void UnitTestImpl::set_os_stack_trace_getter( // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. -OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { +OsStackTraceGetterInterface *UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == nullptr) { #ifdef GTEST_OS_STACK_TRACE_GETTER_ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; #else @@ -5488,39 +5687,39 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { } // Returns the most specific TestResult currently running. -TestResult* UnitTestImpl::current_test_result() { - if (current_test_info_ != NULL) { +TestResult *UnitTestImpl::current_test_result() { + if (current_test_info_ != nullptr) { return ¤t_test_info_->result_; } - if (current_test_case_ != NULL) { - return ¤t_test_case_->ad_hoc_test_result_; + if (current_test_suite_ != nullptr) { + return ¤t_test_suite_->ad_hoc_test_result_; } return &ad_hoc_test_result_; } -// Shuffles all test cases, and the tests within each test case, +// Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + // Shuffles the death test suites. + ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); + // Shuffles the non-death test suites. + ShuffleRange(random(), last_death_test_suite_ + 1, + static_cast(test_suites_.size()), &test_suite_indices_); - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); + // Shuffles the tests inside each test suite. + for (auto &test_suite : test_suites_) { + test_suite->ShuffleTests(random()); } } -// Restores the test cases and tests to their order before the first shuffle. +// Restores the test suites and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); + for (size_t i = 0; i < test_suites_.size(); i++) { + // Unshuffles the tests in each test suite. + test_suites_[i]->UnshuffleTests(); + // Resets the index of each test suite. + test_suite_indices_[i] = static_cast(i); } } @@ -5534,7 +5733,7 @@ void UnitTestImpl::UnshuffleTests() { // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, +std::string GetCurrentOsStackTraceExceptTop(UnitTest * /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. @@ -5545,7 +5744,7 @@ std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; -} +} // namespace bool IsTrue(bool condition) { return condition; } @@ -5553,8 +5752,7 @@ bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. - if (IsTrue(false)) - throw ClassUniqueToAlwaysTrue(); + if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } @@ -5562,7 +5760,7 @@ bool AlwaysTrue() { // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { +bool SkipPrefix(const char *prefix, const char **pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; @@ -5576,18 +5774,18 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -static const char* ParseFlagValue(const char* str, const char* flag, +static const char *ParseFlagValue(const char *str, const char *flag, bool def_optional) { // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; + if (str == nullptr || flag == nullptr) return nullptr; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; // Skips the flag name. - const char* flag_end = str + flag_len; + const char *flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { @@ -5597,7 +5795,7 @@ static const char* ParseFlagValue(const char* str, const char* flag, // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. - if (flag_end[0] != '=') return NULL; + if (flag_end[0] != '=') return nullptr; // Returns the string after "=". return flag_end + 1; @@ -5613,47 +5811,45 @@ static const char* ParseFlagValue(const char* str, const char* flag, // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { +static bool ParseBoolFlag(const char *str, const char *flag, bool *value) { // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, true); + const char *const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } -// Parses a string for an Int32 flag, in the form of -// "--flag=value". +// Parses a string for an int32_t flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { +bool ParseInt32Flag(const char *str, const char *flag, int32_t *value) { // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); + const char *const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. - return ParseInt32(Message() << "The value of flag --" << flag, - value_str, value); + return ParseInt32(Message() << "The value of flag --" << flag, value_str, + value); } -// Parses a string for a string flag, in the form of -// "--flag=value". +// Parses a string for a string flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. template -static bool ParseStringFlag(const char* str, const char* flag, String* value) { +static bool ParseStringFlag(const char *str, const char *flag, String *value) { // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); + const char *const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. - if (value_str == NULL) return false; + if (value_str == nullptr) return false; // Sets *value to the value of the flag. *value = value_str; @@ -5666,9 +5862,8 @@ static bool ParseStringFlag(const char* str, const char* flag, String* value) { // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. -static bool HasGoogleTestFlagPrefix(const char* str) { - return (SkipPrefix("--", &str) || - SkipPrefix("-", &str) || +static bool HasGoogleTestFlagPrefix(const char *str) { + return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || @@ -5684,9 +5879,7 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// FIXME: Write tests for this once we add stdout -// capturing to Google Test. -static void PrintColorEncoded(const char* str) { +static void PrintColorEncoded(const char *str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape @@ -5694,8 +5887,8 @@ static void PrintColorEncoded(const char* str) { // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { - const char* p = strchr(str, '@'); - if (p == NULL) { + const char *p = strchr(str, '@'); + if (p == nullptr) { ColoredPrintf(color, "%s", str); return; } @@ -5721,103 +5914,126 @@ static void PrintColorEncoded(const char* str) { } static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "This program contains tests written using " GTEST_NAME_ + ". You can use the\n" + "following command line flags to control its behavior:\n" + "\n" + "Test Selection:\n" + " @G--" GTEST_FLAG_PREFIX_ + "list_tests@D\n" + " List the names of all tests instead of running them. The name of\n" + " TEST(Foo, Bar) is \"Foo.Bar\".\n" + " @G--" GTEST_FLAG_PREFIX_ + "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate a JSON or XML report in the given directory or with the given\n" -" file name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -# if GTEST_CAN_STREAM_RESULTS_ -" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" -" Stream test results to the given server.\n" -# endif // GTEST_CAN_STREAM_RESULTS_ -"\n" -"Assertion Behavior:\n" -# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" -# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions for use by an external\n" -" test framework.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" -" Do not report exceptions as test failures. Instead, allow them\n" -" to crash the program or throw a pop-up (on Windows).\n" -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + " Run only the tests whose name matches one of the positive patterns " + "but\n" + " none of the negative patterns. '?' matches any single character; " + "'*'\n" + " matches any substring; ':' separates two patterns.\n" + " @G--" GTEST_FLAG_PREFIX_ + "also_run_disabled_tests@D\n" + " Run all disabled tests too.\n" + "\n" + "Test Execution:\n" + " @G--" GTEST_FLAG_PREFIX_ + "repeat=@Y[COUNT]@D\n" + " Run the tests repeatedly; use a negative count to repeat forever.\n" + " @G--" GTEST_FLAG_PREFIX_ + "shuffle@D\n" + " Randomize tests' orders on every iteration.\n" + " @G--" GTEST_FLAG_PREFIX_ + "random_seed=@Y[NUMBER]@D\n" + " Random number seed to use for shuffling test orders (between 1 and\n" + " 99999, or 0 to use a seed based on the current time).\n" + "\n" + "Test Output:\n" + " @G--" GTEST_FLAG_PREFIX_ + "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" + " Enable/disable colored output. The default is @Gauto@D.\n" + " -@G-" GTEST_FLAG_PREFIX_ + "print_time=0@D\n" + " Don't print the elapsed time of each test.\n" + " @G--" GTEST_FLAG_PREFIX_ + "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ + "@Y|@G:@YFILE_PATH]@D\n" + " Generate a JSON or XML report in the given directory or with the " + "given\n" + " file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ + " @G--" GTEST_FLAG_PREFIX_ + "stream_result_to=@YHOST@G:@YPORT@D\n" + " Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ + "\n" + "Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS + " @G--" GTEST_FLAG_PREFIX_ + "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" + " Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS + " @G--" GTEST_FLAG_PREFIX_ + "break_on_failure@D\n" + " Turn assertion failures into debugger break-points.\n" + " @G--" GTEST_FLAG_PREFIX_ + "throw_on_failure@D\n" + " Turn assertion failures into C++ exceptions for use by an external\n" + " test framework.\n" + " @G--" GTEST_FLAG_PREFIX_ + "catch_exceptions=0@D\n" + " Do not report exceptions as test failures. Instead, allow them\n" + " to crash the program or throw a pop-up (on Windows).\n" + "\n" + "Except for @G--" GTEST_FLAG_PREFIX_ + "list_tests@D, you can alternatively set " "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "environment variable of a flag (all letters in upper-case). For example, " + "to\n" + "disable colored text output, you can either specify " + "@G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + "the @G" GTEST_FLAG_PREFIX_UPPER_ + "COLOR@D environment variable to @Gno@D.\n" + "\n" + "For more information, please read the " GTEST_NAME_ + " documentation at\n" + "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ + "\n" + "(not one in your own code or tests), please report it to\n" + "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; -static bool ParseGoogleTestFlag(const char* const arg) { +static bool ParseGoogleTestFlag(const char *const arg) { return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)); + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)); } #if GTEST_USE_OWN_FLAGFILE_FLAG_ -static void LoadFlagsFromFile(const std::string& path) { - FILE* flagfile = posix::FOpen(path.c_str(), "r"); +static void LoadFlagsFromFile(const std::string &path) { + FILE *flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) << "\""; @@ -5827,10 +6043,8 @@ static void LoadFlagsFromFile(const std::string& path) { std::vector lines; SplitString(contents, '\n', &lines); for (size_t i = 0; i < lines.size(); ++i) { - if (lines[i].empty()) - continue; - if (!ParseGoogleTestFlag(lines[i].c_str())) - g_help_flag = true; + if (lines[i].empty()) continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) g_help_flag = true; } } #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ @@ -5839,10 +6053,10 @@ static void LoadFlagsFromFile(const std::string& path) { // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template -void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { +void ParseGoogleTestFlagsOnlyImpl(int *argc, CharType **argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); - const char* const arg = arg_string.c_str(); + const char *const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; @@ -5892,10 +6106,10 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // Parses the command line for Google Test flags, without initializing // other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv) { +void ParseGoogleTestFlagsOnly(int *argc, char **argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); - // Fix the value of *_NSGetArgc() on macOS, but iff + // Fix the value of *_NSGetArgc() on macOS, but if and only if // *_NSGetArgv() == argv // Only applicable to char** version of argv #if GTEST_OS_MAC @@ -5906,7 +6120,7 @@ void ParseGoogleTestFlagsOnly(int* argc, char** argv) { #endif #endif } -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { +void ParseGoogleTestFlagsOnly(int *argc, wchar_t **argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } @@ -5915,7 +6129,7 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { // The type parameter CharType can be instantiated to either char or // wchar_t. template -void InitGoogleTestImpl(int* argc, CharType** argv) { +void InitGoogleTestImpl(int *argc, CharType **argv) { // We don't want to run the initialization code twice. if (GTestIsInitialized()) return; @@ -5945,24 +6159,40 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // updated. // // Calling the function for the second time has no user-visible effect. -void InitGoogleTest(int* argc, char** argv) { +void InitGoogleTest(int *argc, char **argv) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); -#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. -void InitGoogleTest(int* argc, wchar_t** argv) { +void InitGoogleTest(int *argc, wchar_t **argv) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); -#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +void InitGoogleTest() { + // Since Arduino doesn't have a command line, fake out the argc/argv arguments + int argc = 1; + const auto arg0 = "dummy"; + char *argv0 = const_cast(arg0); + char **argv = &argv0; + +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + internal::InitGoogleTestImpl(&argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + std::string TempDir() { #if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); @@ -5971,15 +6201,19 @@ std::string TempDir() { #if GTEST_OS_WINDOWS_MOBILE return "\\temp\\"; #elif GTEST_OS_WINDOWS - const char* temp_dir = internal::posix::GetEnv("TEMP"); - if (temp_dir == NULL || temp_dir[0] == '\0') + const char *temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == nullptr || temp_dir[0] == '\0') return "\\temp\\"; else if (temp_dir[strlen(temp_dir) - 1] == '\\') return temp_dir; else return std::string(temp_dir) + "\\"; #elif GTEST_OS_LINUX_ANDROID - return "/sdcard/"; + const char *temp_dir = internal::posix::GetEnv("TEST_TMPDIR"); + if (temp_dir == nullptr || temp_dir[0] == '\0') + return "/data/local/tmp/"; + else + return temp_dir; #else return "/tmp/"; #endif // GTEST_OS_WINDOWS_MOBILE @@ -5989,7 +6223,7 @@ std::string TempDir() { // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. -void ScopedTrace::PushTrace(const char* file, int line, std::string message) { +void ScopedTrace::PushTrace(const char *file, int line, std::string message) { internal::TraceInfo trace; trace.file = file; trace.line = line; @@ -5999,8 +6233,7 @@ void ScopedTrace::PushTrace(const char* file, int line, std::string message) { } // Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { +ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } diff --git a/media/libaom/src/third_party/googletest/src/googletest/src/gtest_main.cc b/media/libaom/src/third_party/googletest/src/googletest/src/gtest_main.cc index 2113f621e6..77c90ce61a 100644 --- a/media/libaom/src/third_party/googletest/src/googletest/src/gtest_main.cc +++ b/media/libaom/src/third_party/googletest/src/googletest/src/gtest_main.cc @@ -27,11 +27,26 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include #include "gtest/gtest.h" +#if GTEST_OS_ESP8266 || GTEST_OS_ESP32 +#if GTEST_OS_ESP8266 +extern "C" { +#endif +void setup() { testing::InitGoogleTest(); } + +void loop() { RUN_ALL_TESTS(); } + +#if GTEST_OS_ESP8266 +} +#endif + +#else + GTEST_API_ int main(int argc, char **argv) { printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +#endif diff --git a/media/libaom/src/tools/aom_entropy_optimizer.c b/media/libaom/src/tools/aom_entropy_optimizer.c index d57b8863da..9f529d9ab2 100644 --- a/media/libaom/src/tools/aom_entropy_optimizer.c +++ b/media/libaom/src/tools/aom_entropy_optimizer.c @@ -271,7 +271,10 @@ int main(int argc, const char **argv) { FRAME_COUNTS fc; const size_t bytes = fread(&fc, sizeof(FRAME_COUNTS), 1, statsfile); - if (!bytes) return 1; + if (!bytes) { + fclose(statsfile); + return 1; + } FILE *const probsfile = fopen("optimized_probs.c", "w"); if (probsfile == NULL) { diff --git a/media/libaom/src/usage.dox b/media/libaom/src/usage.dox index 062d35a838..4004f4af5f 100644 --- a/media/libaom/src/usage.dox +++ b/media/libaom/src/usage.dox @@ -59,7 +59,6 @@ \if decoder Currently defined decoder features include: - - \ref usage_cb \endif \section usage_init Initialization @@ -81,7 +80,6 @@ The available initialization methods are: \if encoder \li #aom_codec_enc_init (calls aom_codec_enc_init_ver()) - \li #aom_codec_enc_init_multi (calls aom_codec_enc_init_multi_ver()) \endif \if decoder \li #aom_codec_dec_init (calls aom_codec_dec_init_ver()) diff --git a/media/libaom/src/usage_dx.dox b/media/libaom/src/usage_dx.dox index eef78376f7..76dc213bf0 100644 --- a/media/libaom/src/usage_dx.dox +++ b/media/libaom/src/usage_dx.dox @@ -10,31 +10,8 @@ \ref samples - \section usage_cb Callback Based Decoding - There are two methods for the application to access decoded frame data. Some - codecs support asynchronous (callback-based) decoding \ref usage_features - that allow the application to register a callback to be invoked by the - decoder when decoded data becomes available. Decoders are not required to - support this feature, however. Like all \ref usage_features, support can be - determined by calling aom_codec_get_caps(). Callbacks are available in both - frame-based and slice-based variants. Frame based callbacks conform to the - signature of #aom_codec_put_frame_cb_fn_t and are invoked once the entire - frame has been decoded. Slice based callbacks conform to the signature of - #aom_codec_put_slice_cb_fn_t and are invoked after a subsection of the frame - is decoded. For example, a slice callback could be issued for each - macroblock row. However, the number and size of slices to return is - implementation specific. Also, the image data passed in a slice callback is - not necessarily in the same memory segment as the data will be when it is - assembled into a full frame. For this reason, the application \ref MUST - examine the rectangles that describe what data is valid to access and what - data has been updated in this call. For all their additional complexity, - slice based decoding callbacks provide substantial speed gains to the - overall application in some cases, due to improved cache behavior. - - \section usage_frame_iter Frame Iterator Based Decoding - If the codec does not support callback based decoding, or the application - chooses not to make use of that feature, decoded frames are made available + Decoded frames are made available to the application through the aom_codec_get_frame() iterator. The application initializes the iterator storage (of type #aom_codec_iter_t) to NULL, then calls aom_codec_get_frame repeatedly until it returns NULL, indicating that all @@ -42,16 +19,4 @@ frames that are ready for display, depending on the codec. - \section usage_postproc Postprocessing - Postprocessing is a process that is applied after a frame is decoded to - enhance the image's appearance by removing artifacts introduced in the - compression process. It is not required to properly decode the frame, and - is generally done only when there is enough spare CPU time to execute - the required filters. Codecs may support a number of different - postprocessing filters, and the available filters may differ from platform - to platform. Embedded devices often do not have enough CPU to implement - postprocessing in software. The filter selection is generally handled - automatically by the codec. - - */