diff --git a/media/libvpx/config/generic/vpx_config.h b/media/libvpx/config/generic/vpx_config.h --- a/media/libvpx/config/generic/vpx_config.h +++ b/media/libvpx/config/generic/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/generic/vpx_config.asm b/media/libvpx/config/generic/vpx_config.asm --- a/media/libvpx/config/generic/vpx_config.asm +++ b/media/libvpx/config/generic/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/linux/arm/vpx_config.h b/media/libvpx/config/linux/arm/vpx_config.h --- a/media/libvpx/config/linux/arm/vpx_config.h +++ b/media/libvpx/config/linux/arm/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/linux/arm/vpx_config.asm b/media/libvpx/config/linux/arm/vpx_config.asm --- a/media/libvpx/config/linux/arm/vpx_config.asm +++ b/media/libvpx/config/linux/arm/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/linux/arm64/vpx_config.h b/media/libvpx/config/linux/arm64/vpx_config.h --- a/media/libvpx/config/linux/arm64/vpx_config.h +++ b/media/libvpx/config/linux/arm64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/linux/arm64/vpx_config.asm b/media/libvpx/config/linux/arm64/vpx_config.asm --- a/media/libvpx/config/linux/arm64/vpx_config.asm +++ b/media/libvpx/config/linux/arm64/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/linux/ia32/vpx_config.h b/media/libvpx/config/linux/ia32/vpx_config.h --- a/media/libvpx/config/linux/ia32/vpx_config.h +++ b/media/libvpx/config/linux/ia32/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/linux/ia32/vpx_config.asm b/media/libvpx/config/linux/ia32/vpx_config.asm --- a/media/libvpx/config/linux/ia32/vpx_config.asm +++ b/media/libvpx/config/linux/ia32/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/config/linux/loongarch64/vpx_config.h b/media/libvpx/config/linux/loongarch64/vpx_config.h --- a/media/libvpx/config/linux/loongarch64/vpx_config.h +++ b/media/libvpx/config/linux/loongarch64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/linux/loongarch64/vpx_config.asm b/media/libvpx/config/linux/loongarch64/vpx_config.asm --- a/media/libvpx/config/linux/loongarch64/vpx_config.asm +++ b/media/libvpx/config/linux/loongarch64/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/linux/x64/vpx_config.h b/media/libvpx/config/linux/x64/vpx_config.h --- a/media/libvpx/config/linux/x64/vpx_config.h +++ b/media/libvpx/config/linux/x64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/linux/x64/vpx_config.asm b/media/libvpx/config/linux/x64/vpx_config.asm --- a/media/libvpx/config/linux/x64/vpx_config.asm +++ b/media/libvpx/config/linux/x64/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/config/mac/arm64/vpx_config.h b/media/libvpx/config/mac/arm64/vpx_config.h --- a/media/libvpx/config/mac/arm64/vpx_config.h +++ b/media/libvpx/config/mac/arm64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/mac/arm64/vpx_config.asm b/media/libvpx/config/mac/arm64/vpx_config.asm --- a/media/libvpx/config/mac/arm64/vpx_config.asm +++ b/media/libvpx/config/mac/arm64/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/mac/ia32/vpx_config.h b/media/libvpx/config/mac/ia32/vpx_config.h --- a/media/libvpx/config/mac/ia32/vpx_config.h +++ b/media/libvpx/config/mac/ia32/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/mac/ia32/vpx_config.asm b/media/libvpx/config/mac/ia32/vpx_config.asm --- a/media/libvpx/config/mac/ia32/vpx_config.asm +++ b/media/libvpx/config/mac/ia32/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/config/mac/x64/vpx_config.h b/media/libvpx/config/mac/x64/vpx_config.h --- a/media/libvpx/config/mac/x64/vpx_config.h +++ b/media/libvpx/config/mac/x64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/mac/x64/vpx_config.asm b/media/libvpx/config/mac/x64/vpx_config.asm --- a/media/libvpx/config/mac/x64/vpx_config.asm +++ b/media/libvpx/config/mac/x64/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/config/vpx_version.h b/media/libvpx/config/vpx_version.h --- a/media/libvpx/config/vpx_version.h +++ b/media/libvpx/config/vpx_version.h @@ -1,11 +1,11 @@ // This file is generated. Do not edit. #ifndef VPX_VERSION_H_ #define VPX_VERSION_H_ #define VERSION_MAJOR 1 #define VERSION_MINOR 15 -#define VERSION_PATCH 0 +#define VERSION_PATCH 2 #define VERSION_EXTRA "" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.15.0" -#define VERSION_STRING " v1.15.0" +#define VERSION_STRING_NOSP "v1.15.2" +#define VERSION_STRING " v1.15.2" #endif // VPX_VERSION_H_ diff --git a/media/libvpx/config/win/aarch64/vpx_config.h b/media/libvpx/config/win/aarch64/vpx_config.h --- a/media/libvpx/config/win/aarch64/vpx_config.h +++ b/media/libvpx/config/win/aarch64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/win/aarch64/vpx_config.asm b/media/libvpx/config/win/aarch64/vpx_config.asm --- a/media/libvpx/config/win/aarch64/vpx_config.asm +++ b/media/libvpx/config/win/aarch64/vpx_config.asm @@ -91,8 +91,7 @@ .equ CONFIG_BITSTREAM_DEBUG , 0 .equ CONFIG_MISMATCH_DEBUG , 0 .equ CONFIG_FP_MB_STATS , 0 .equ CONFIG_EMULATE_HARDWARE , 0 .equ CONFIG_NON_GREEDY_MV , 0 -.equ CONFIG_RATE_CTRL , 0 .equ CONFIG_COLLECT_COMPONENT_TIMING , 0 .section .note.GNU-stack,"",%progbits diff --git a/media/libvpx/config/win/ia32/vpx_config.h b/media/libvpx/config/win/ia32/vpx_config.h --- a/media/libvpx/config/win/ia32/vpx_config.h +++ b/media/libvpx/config/win/ia32/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/win/ia32/vpx_config.asm b/media/libvpx/config/win/ia32/vpx_config.asm --- a/media/libvpx/config/win/ia32/vpx_config.asm +++ b/media/libvpx/config/win/ia32/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/config/win/x64/vpx_config.h b/media/libvpx/config/win/x64/vpx_config.h --- a/media/libvpx/config/win/x64/vpx_config.h +++ b/media/libvpx/config/win/x64/vpx_config.h @@ -100,10 +100,9 @@ #define CONFIG_BITSTREAM_DEBUG 0 #define CONFIG_MISMATCH_DEBUG 0 #define CONFIG_FP_MB_STATS 0 #define CONFIG_EMULATE_HARDWARE 0 #define CONFIG_NON_GREEDY_MV 0 -#define CONFIG_RATE_CTRL 0 #define CONFIG_COLLECT_COMPONENT_TIMING 0 #define DECODE_WIDTH_LIMIT 8192 #define DECODE_HEIGHT_LIMIT 4608 #endif /* VPX_CONFIG_H */ diff --git a/media/libvpx/config/win/x64/vpx_config.asm b/media/libvpx/config/win/x64/vpx_config.asm --- a/media/libvpx/config/win/x64/vpx_config.asm +++ b/media/libvpx/config/win/x64/vpx_config.asm @@ -88,7 +88,6 @@ %define CONFIG_BITSTREAM_DEBUG 0 %define CONFIG_MISMATCH_DEBUG 0 %define CONFIG_FP_MB_STATS 0 %define CONFIG_EMULATE_HARDWARE 0 %define CONFIG_NON_GREEDY_MV 0 -%define CONFIG_RATE_CTRL 0 %define CONFIG_COLLECT_COMPONENT_TIMING 0 diff --git a/media/libvpx/libvpx/CHANGELOG b/media/libvpx/libvpx/CHANGELOG --- a/media/libvpx/libvpx/CHANGELOG +++ b/media/libvpx/libvpx/CHANGELOG @@ -1,11 +1,23 @@ +2025-05-28 v1.15.2 "Wigeon Duck" + This release fixes CVE-2025-5283 (bug webm:413411335), and is ABI compatible + with the previous release. + +2025-01-09 v1.15.1 "Wigeon Duck" + This release bumps up the SO major version and fixes the language about ABI + compatibility in the previous release changelog. + 2024-10-22 v1.15.0 "Wigeon Duck" This release includes new codec control for key frame filtering, more Neon optimizations, improvements to RTC encoding and bug fixes. - Upgrading: - This release is ABI compatible with the previous release. + This release is ABI incompatible with the previous release. + + It is strongly recommended to skip this release and upgrade to v1.15.1 since + the shared object was versioned incorrectly, as shown in + https://issues.webmproject.org/issues/384672478. Temporal filtering improvement that can be turned on with the new codec control VP9E_SET_KEY_FRAME_FILTERING, which gives 1+% BD-rate saving with minimal encoder time increase. diff --git a/media/libvpx/libvpx/README b/media/libvpx/libvpx/README --- a/media/libvpx/libvpx/README +++ b/media/libvpx/libvpx/README @@ -68,10 +68,11 @@ arm64-darwin20-gcc arm64-darwin21-gcc arm64-darwin22-gcc arm64-darwin23-gcc arm64-darwin24-gcc + arm64-darwin25-gcc arm64-linux-gcc arm64-win64-gcc arm64-win64-vs15 arm64-win64-vs16 arm64-win64-vs16-clangcl @@ -133,10 +134,11 @@ x86_64-darwin20-gcc x86_64-darwin21-gcc x86_64-darwin22-gcc x86_64-darwin23-gcc x86_64-darwin24-gcc + x86_64-darwin25-gcc x86_64-iphonesimulator-gcc x86_64-linux-gcc x86_64-linux-icc x86_64-solaris-gcc x86_64-win64-gcc diff --git a/media/libvpx/libvpx/args.h b/media/libvpx/libvpx/args.h --- a/media/libvpx/libvpx/args.h +++ b/media/libvpx/libvpx/args.h @@ -26,26 +26,22 @@ struct arg_enum_list { const char *name; int val; }; -#define ARG_ENUM_LIST_END \ - { 0 } +#define ARG_ENUM_LIST_END { 0 } typedef struct arg_def { const char *short_name; const char *long_name; int has_val; const char *desc; const struct arg_enum_list *enums; } arg_def_t; -#define ARG_DEF(s, l, v, d) \ - { s, l, v, d, NULL } -#define ARG_DEF_ENUM(s, l, v, d, e) \ - { s, l, v, d, e } -#define ARG_DEF_LIST_END \ - { 0 } +#define ARG_DEF(s, l, v, d) { s, l, v, d, NULL } +#define ARG_DEF_ENUM(s, l, v, d, e) { s, l, v, d, e } +#define ARG_DEF_LIST_END { 0 } int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); 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/libvpx/libvpx/args.c b/media/libvpx/libvpx/args.c --- a/media/libvpx/libvpx/args.c +++ b/media/libvpx/libvpx/args.c @@ -89,28 +89,35 @@ new_argv[argc] = NULL; return new_argv; } void arg_show_usage(FILE *fp, const struct arg_def *const *defs) { - char option_text[40] = { 0 }; - for (; *defs; defs++) { const struct arg_def *def = *defs; char *short_val = def->has_val ? " " : ""; char *long_val = def->has_val ? "=" : ""; + int n = 0; + // Short options are indented with two spaces. Long options are indented + // with 12 spaces. if (def->short_name && def->long_name) { char *comma = def->has_val ? "," : ", "; - snprintf(option_text, 37, "-%s%s%s --%s%6s", def->short_name, short_val, - comma, def->long_name, long_val); + n = fprintf(fp, " -%s%s%s --%s%s", def->short_name, short_val, comma, + def->long_name, long_val); } else if (def->short_name) - snprintf(option_text, 37, "-%s%s", def->short_name, short_val); + n = fprintf(fp, " -%s%s", def->short_name, short_val); else if (def->long_name) - snprintf(option_text, 37, " --%s%s", def->long_name, long_val); + n = fprintf(fp, " --%s%s", def->long_name, long_val); - fprintf(fp, " %-37s\t%s\n", option_text, def->desc); + // Descriptions are indented with 40 spaces. If an option is 40 characters + // or longer, its description starts on the next line. + if (n < 40) + for (int i = 0; i < 40 - n; i++) fputc(' ', fp); + else + fputs("\n ", fp); + fprintf(fp, "%s\n", def->desc); if (def->enums) { const struct arg_enum_list *listptr; fprintf(fp, " %-37s\t ", ""); diff --git a/media/libvpx/libvpx/build/make/Android.mk b/media/libvpx/libvpx/build/make/Android.mk --- a/media/libvpx/libvpx/build/make/Android.mk +++ b/media/libvpx/libvpx/build/make/Android.mk @@ -23,11 +23,11 @@ # # Place an Android.mk file in the jni directory that references the # Android.mk file in the libvpx directory: # LOCAL_PATH := $(call my-dir) # include $(CLEAR_VARS) -# include jni/libvpx/build/make/Android.mk +# include libvpx/build/make/Android.mk # # By default libvpx will use the 'cpufeatures' module from the NDK. This allows # the library to be built with all available optimizations (SSE2->AVX512 for # x86, NEON for arm, DSPr2 for mips). This can be disabled with # --disable-runtime-cpu-detect diff --git a/media/libvpx/libvpx/build/make/Makefile b/media/libvpx/libvpx/build/make/Makefile --- a/media/libvpx/libvpx/build/make/Makefile +++ b/media/libvpx/libvpx/build/make/Makefile @@ -148,12 +148,12 @@ $(BUILD_PFX)%_neon_dotprod.c.o: CFLAGS += -march=armv8.2-a+dotprod $(BUILD_PFX)%_neon_i8mm.c.d: CFLAGS += -march=armv8.2-a+dotprod+i8mm $(BUILD_PFX)%_neon_i8mm.c.o: CFLAGS += -march=armv8.2-a+dotprod+i8mm $(BUILD_PFX)%_sve.c.d: CFLAGS += -march=armv8.2-a+dotprod+i8mm+sve $(BUILD_PFX)%_sve.c.o: CFLAGS += -march=armv8.2-a+dotprod+i8mm+sve -$(BUILD_PFX)%_sve2.c.d: CFLAGS += -march=armv9-a+sve2 -$(BUILD_PFX)%_sve2.c.o: CFLAGS += -march=armv9-a+sve2 +$(BUILD_PFX)%_sve2.c.d: CFLAGS += -march=armv9-a+i8mm+sve2 +$(BUILD_PFX)%_sve2.c.o: CFLAGS += -march=armv9-a+i8mm+sve2 # POWER $(BUILD_PFX)%_vsx.c.d: CFLAGS += -maltivec -mvsx $(BUILD_PFX)%_vsx.c.o: CFLAGS += -maltivec -mvsx diff --git a/media/libvpx/libvpx/build/make/configure.sh b/media/libvpx/libvpx/build/make/configure.sh --- a/media/libvpx/libvpx/build/make/configure.sh +++ b/media/libvpx/libvpx/build/make/configure.sh @@ -830,11 +830,11 @@ case "$gcctarget" in *darwin1[0-9]*) tgt_isa=x86_64 tgt_os=`echo $gcctarget | sed 's/.*\(darwin1[0-9]\).*/\1/'` ;; - *darwin2[0-4]*) + *darwin2[0-5]*) tgt_isa=`uname -m` tgt_os=`echo $gcctarget | sed 's/.*\(darwin2[0-9]\).*/\1/'` ;; x86_64*mingw32*) tgt_os=win64 @@ -989,11 +989,11 @@ ;; *-darwin19-*) add_cflags "-mmacosx-version-min=10.15" add_ldflags "-mmacosx-version-min=10.15" ;; - *-darwin2[0-4]-*) + *-darwin2[0-5]-*) add_cflags "-arch ${toolchain%%-*}" add_ldflags "-arch ${toolchain%%-*}" ;; *-iphonesimulator-*) add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}" @@ -1227,12 +1227,12 @@ fi fi ;; esac - if [ "$(show_darwin_sdk_major_version iphoneos)" -gt 8 \ - && [ "$(show_xcode_version)" -lt 16 ]; then + if [ "$(show_darwin_sdk_major_version iphoneos)" -gt 8 ] \ + && [ "$(show_xcode_version | cut -d. -f1)" -lt 16 ]; then check_add_cflags -fembed-bitcode check_add_asflags -fembed-bitcode check_add_ldflags -fembed-bitcode fi fi @@ -1379,10 +1379,14 @@ os2) disable_feature pic AS=${AS:-nasm} add_ldflags -Zhigh-mem ;; + darwin*) + enabled x86 && darwin_arch="-arch i386" || darwin_arch="-arch x86_64" + add_cflags ${darwin_arch} + add_ldflags ${darwin_arch} esac AS="${alt_as:-${AS:-auto}}" case ${tgt_cc} in icc*) @@ -1501,13 +1505,10 @@ enabled debug && [ "${AS}" = nasm ] && add_asflags -g [ "${AS##*/}" = nasm ] && check_asm_align ;; darwin*) add_asflags -f macho${bits} - enabled x86 && darwin_arch="-arch i386" || darwin_arch="-arch x86_64" - add_cflags ${darwin_arch} - add_ldflags ${darwin_arch} # -mdynamic-no-pic is still a bit of voodoo -- it was required at # one time, but does not seem to be now, and it breaks some of the # code that still relies on inline assembly. # enabled icc && ! enabled pic && add_cflags -fno-pic -mdynamic-no-pic enabled icc && ! enabled pic && add_cflags -fno-pic diff --git a/media/libvpx/libvpx/build/make/iosbuild.sh b/media/libvpx/libvpx/build/make/iosbuild.sh --- a/media/libvpx/libvpx/build/make/iosbuild.sh +++ b/media/libvpx/libvpx/build/make/iosbuild.sh @@ -28,17 +28,13 @@ HEADER_DIR="${FRAMEWORK_DIR}/Headers/vpx" SCRIPT_DIR=$(dirname "$0") LIBVPX_SOURCE_DIR=$(cd ${SCRIPT_DIR}/../..; pwd) LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo) ORIG_PWD="$(pwd)" -ARM_TARGETS="arm64-darwin-gcc - armv7-darwin-gcc - armv7s-darwin-gcc" -SIM_TARGETS="x86-iphonesimulator-gcc - x86_64-iphonesimulator-gcc" -OSX_TARGETS="x86-darwin16-gcc - x86_64-darwin16-gcc" +ARM_TARGETS="arm64-darwin-gcc" +SIM_TARGETS="x86_64-iphonesimulator-gcc" +OSX_TARGETS="x86_64-darwin16-gcc" TARGETS="${ARM_TARGETS} ${SIM_TARGETS}" # Configures for the target specified by $1, and invokes make with the dist # target using $DIST_DIR as the distribution output directory. build_target() { diff --git a/media/libvpx/libvpx/configure b/media/libvpx/libvpx/configure --- a/media/libvpx/libvpx/configure +++ b/media/libvpx/libvpx/configure @@ -102,10 +102,11 @@ all_platforms="${all_platforms} arm64-darwin20-gcc" all_platforms="${all_platforms} arm64-darwin21-gcc" all_platforms="${all_platforms} arm64-darwin22-gcc" all_platforms="${all_platforms} arm64-darwin23-gcc" all_platforms="${all_platforms} arm64-darwin24-gcc" +all_platforms="${all_platforms} arm64-darwin25-gcc" all_platforms="${all_platforms} arm64-linux-gcc" all_platforms="${all_platforms} arm64-win64-gcc" all_platforms="${all_platforms} arm64-win64-vs15" all_platforms="${all_platforms} arm64-win64-vs16" all_platforms="${all_platforms} arm64-win64-vs16-clangcl" @@ -167,10 +168,11 @@ all_platforms="${all_platforms} x86_64-darwin20-gcc" all_platforms="${all_platforms} x86_64-darwin21-gcc" all_platforms="${all_platforms} x86_64-darwin22-gcc" all_platforms="${all_platforms} x86_64-darwin23-gcc" all_platforms="${all_platforms} x86_64-darwin24-gcc" +all_platforms="${all_platforms} x86_64-darwin25-gcc" all_platforms="${all_platforms} x86_64-iphonesimulator-gcc" all_platforms="${all_platforms} x86_64-linux-gcc" all_platforms="${all_platforms} x86_64-linux-icc" all_platforms="${all_platforms} x86_64-solaris-gcc" all_platforms="${all_platforms} x86_64-win64-gcc" @@ -306,11 +308,10 @@ " EXPERIMENT_LIST=" fp_mb_stats emulate_hardware non_greedy_mv - rate_ctrl collect_component_timing " CONFIG_LIST=" dependency_tracking external_build @@ -690,14 +691,13 @@ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728 if enabled arm; then check_add_cxxflags -Wno-psabi fi - # Enforce C++11 compatibility. - check_add_cxxflags -Wc++14-extensions - check_add_cxxflags -Wc++17-extensions + # Enforce C++17 compatibility. check_add_cxxflags -Wc++20-extensions + check_add_cxxflags -Wc++23-extensions check_add_cxxflags -Wnon-virtual-dtor # disable some warnings specific to libyuv / libwebm. check_cxxflags -Wno-missing-declarations \ && LIBYUV_CXXFLAGS="${LIBYUV_CXXFLAGS} -Wno-missing-declarations" @@ -778,37 +778,37 @@ soft_enable unit_tests soft_enable webm_io soft_enable libyuv ;; *-android-*) - check_add_cxxflags -std=gnu++11 && soft_enable webm_io + check_add_cxxflags -std=gnu++17 && soft_enable webm_io soft_enable libyuv # GTestLog must be modified to use Android logging utilities. ;; *-darwin-*) - check_add_cxxflags -std=gnu++11 + check_add_cxxflags -std=gnu++17 # iOS/ARM builds do not work with gtest. This does not match # x86 targets. ;; *-iphonesimulator-*) - check_add_cxxflags -std=gnu++11 && soft_enable webm_io + check_add_cxxflags -std=gnu++17 && soft_enable webm_io soft_enable libyuv ;; *-win*) # Some mingw toolchains don't have pthread available by default. # Treat these more like visual studio where threading in gtest # would be disabled for the same reason. - check_add_cxxflags -std=gnu++11 && soft_enable unit_tests \ + check_add_cxxflags -std=gnu++17 && soft_enable unit_tests \ && soft_enable webm_io check_cxx "$@" < $@ +CLEAN-OBJS += vpxdec_srcs.txt + # # Documentation Rules # %.dox: %.c @echo " [DOXY] $@" diff --git a/media/libvpx/libvpx/examples/svc_context.h b/media/libvpx/libvpx/examples/svc_context.h --- a/media/libvpx/libvpx/examples/svc_context.h +++ b/media/libvpx/libvpx/examples/svc_context.h @@ -37,10 +37,11 @@ SVC_LOG_LEVEL log_level; // amount of information to display int output_rc_stat; // for outputting rc stats int speed; // speed setting for codec int threads; int aqmode; // turns on aq-mode=3 (cyclic_refresh): 0=off, 1=on. + int use_psnr; // private storage for vpx_svc_encode void *internal; } SvcContext; #define OPTION_BUFFER_SIZE 1024 @@ -56,18 +57,18 @@ // accumulated statistics double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; + int number_of_frames[VPX_SS_MAX_LAYERS]; // codec encoding values int width; // width of highest layer int height; // height of highest layer int kf_dist; // distance between keyframes // state variables - int psnr_pkt_received; int layer; int use_multiple_frame_contexts; vpx_codec_ctx_t *codec_ctx; } SvcInternal_t; diff --git a/media/libvpx/libvpx/examples/svc_encodeframe.c b/media/libvpx/libvpx/examples/svc_encodeframe.c --- a/media/libvpx/libvpx/examples/svc_encodeframe.c +++ b/media/libvpx/libvpx/examples/svc_encodeframe.c @@ -514,11 +514,15 @@ if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) enc_cfg->g_error_resilient = 1; // Initialize codec - res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); + vpx_codec_flags_t flags = 0; + if (svc_ctx->use_psnr) { + flags |= VPX_CODEC_USE_PSNR; + } + res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, flags); if (res != VPX_CODEC_OK) { svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); return res; } if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) { @@ -534,30 +538,20 @@ */ vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, struct vpx_image *rawimg, vpx_codec_pts_t pts, int64_t duration, int deadline) { vpx_codec_err_t res; - vpx_codec_iter_t iter; - const vpx_codec_cx_pkt_t *cx_pkt; SvcInternal_t *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { return VPX_CODEC_INVALID_PARAM; } res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline); if (res != VPX_CODEC_OK) { return res; } - // save compressed data - iter = NULL; - while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { - switch (cx_pkt->kind) { - case VPX_CODEC_PSNR_PKT: ++si->psnr_pkt_received; break; - default: break; - } - } return VPX_CODEC_OK; } static double calc_psnr(double d) { @@ -565,34 +559,32 @@ return -10.0 * log(d) / log(10.0); } // dump accumulated statistics and reset accumulated values void vpx_svc_dump_statistics(SvcContext *svc_ctx) { - int number_of_frames; int i, j; uint32_t bytes_total = 0; double scale[COMPONENTS]; double psnr[COMPONENTS]; double mse[COMPONENTS]; double y_scale; SvcInternal_t *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || si == NULL) return; - number_of_frames = si->psnr_pkt_received; - if (number_of_frames <= 0) return; - svc_log(svc_ctx, SVC_LOG_INFO, "\n"); for (i = 0; i < svc_ctx->spatial_layers; ++i) { svc_log(svc_ctx, SVC_LOG_INFO, - "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", - i, si->psnr_sum[i][0] / number_of_frames, - si->psnr_sum[i][1] / number_of_frames, - si->psnr_sum[i][2] / number_of_frames, - si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); + "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u], " + "Number_of_frames %d \n", + i, si->psnr_sum[i][0] / si->number_of_frames[i], + si->psnr_sum[i][1] / si->number_of_frames[i], + si->psnr_sum[i][2] / si->number_of_frames[i], + si->psnr_sum[i][3] / si->number_of_frames[i], si->bytes_sum[i], + si->number_of_frames[i]); // the following psnr calculation is deduced from ffmpeg.c#print_report - y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; + y_scale = si->width * si->height * 255.0 * 255.0 * si->number_of_frames[i]; scale[1] = y_scale; scale[2] = scale[3] = y_scale / 4; // U or V scale[0] = y_scale * 1.5; // total for (j = 0; j < COMPONENTS; j++) { @@ -605,21 +597,21 @@ svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], mse[1], mse[2], mse[3]); bytes_total += si->bytes_sum[i]; - // Clear sums for next time. + } + // Clear sums for next time. + for (i = 0; i < svc_ctx->spatial_layers; ++i) { si->bytes_sum[i] = 0; + si->number_of_frames[i] = 0; for (j = 0; j < COMPONENTS; ++j) { si->psnr_sum[i][j] = 0; si->sse_sum[i][j] = 0; } } - // only display statistics once - si->psnr_pkt_received = 0; - svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); } void vpx_svc_release(SvcContext *svc_ctx) { SvcInternal_t *si; diff --git a/media/libvpx/libvpx/examples/vp8_multi_resolution_encoder.c b/media/libvpx/libvpx/examples/vp8_multi_resolution_encoder.c --- a/media/libvpx/libvpx/examples/vp8_multi_resolution_encoder.c +++ b/media/libvpx/libvpx/examples/vp8_multi_resolution_encoder.c @@ -23,11 +23,10 @@ #include "./vpx_config.h" #include #include #include -#include #include #include #include #include "vpx_ports/vpx_timer.h" #include "vpx/vpx_encoder.h" @@ -436,11 +435,11 @@ cfg[0].g_timebase.num = 1; /* Set fps */ cfg[0].g_timebase.den = framerate; /* Other-resolution encoder settings */ for (i = 1; i < NUM_ENCODERS; i++) { - memcpy(&cfg[i], &cfg[0], sizeof(vpx_codec_enc_cfg_t)); + cfg[i] = cfg[0]; cfg[i].rc_target_bitrate = target_bitrate[i]; /* Note: Width & height of other-resolution encoders are calculated * from the highest-resolution encoder's size and the corresponding diff --git a/media/libvpx/libvpx/examples/vp9_spatial_svc_encoder.c b/media/libvpx/libvpx/examples/vp9_spatial_svc_encoder.c --- a/media/libvpx/libvpx/examples/vp9_spatial_svc_encoder.c +++ b/media/libvpx/libvpx/examples/vp9_spatial_svc_encoder.c @@ -12,10 +12,12 @@ * This is an example demonstrating how to implement a multi-layer * VP9 encoding scheme based on spatial scalability for video applications * that benefit from a scalable bitstream. */ +#include +#include #include #include #include #include #include @@ -23,16 +25,17 @@ #include "../args.h" #include "../tools_common.h" #include "../video_writer.h" +#include "../vpx_ports/bitops.h" #include "../vpx_ports/vpx_timer.h" #include "./svc_context.h" #include "vpx/vp8cx.h" +#include "vpx/vpx_decoder.h" #include "vpx/vpx_encoder.h" #include "../vpxstats.h" -#include "vp9/encoder/vp9_encoder.h" #include "./y4minput.h" #define OUTPUT_FRAME_STATS 0 #define OUTPUT_RC_STATS 1 @@ -88,10 +91,12 @@ ARG_DEF("aq", "aqmode", 1, "aq-mode off/on"); static const arg_def_t bitrates_arg = ARG_DEF("bl", "bitrates", 1, "bitrates[sl * num_tl + tl]"); static const arg_def_t dropframe_thresh_arg = ARG_DEF(NULL, "drop-frame", 1, "Temporal resampling threshold (buf %)"); +static const arg_def_t psnr_arg = + ARG_DEF(NULL, "psnr", 1, "Enable PSNR computation and statistics"); static const struct arg_enum_list tune_content_enum[] = { { "default", VP9E_CONTENT_DEFAULT }, { "screen", VP9E_CONTENT_SCREEN }, { "film", VP9E_CONTENT_FILM }, { NULL, 0 } @@ -141,10 +146,11 @@ &rc_end_usage_arg, &bitrates_arg, &dropframe_thresh_arg, &tune_content_arg, &inter_layer_pred_arg, + &psnr_arg, NULL }; static const uint32_t default_frames_to_skip = 0; static const uint32_t default_frames_to_code = 60 * 60; static const uint32_t default_width = 1920; @@ -200,10 +206,11 @@ #if OUTPUT_RC_STATS svc_ctx->output_rc_stat = default_output_rc_stats; #endif svc_ctx->speed = default_speed; svc_ctx->threads = default_threads; + svc_ctx->use_psnr = 0; // start with default encoder configuration res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); if (res) { die("Failed to get config: %s\n", vpx_codec_err_to_string(res)); @@ -323,10 +330,12 @@ enc_cfg->rc_dropframe_thresh = arg_parse_uint(&arg); } else if (arg_match(&arg, &tune_content_arg, argi)) { app_input->tune_content = arg_parse_uint(&arg); } else if (arg_match(&arg, &inter_layer_pred_arg, argi)) { app_input->inter_layer_pred = arg_parse_uint(&arg); + } else if (arg_match(&arg, &psnr_arg, argi)) { + svc_ctx->use_psnr = arg_parse_uint(&arg); } else { ++argj; } } @@ -775,12 +784,12 @@ uint64_t sizes[8]; uint64_t sizes_parsed[8]; int count = 0; double sum_bitrate = 0.0; double sum_bitrate2 = 0.0; - vp9_zero(sizes); - vp9_zero(sizes_parsed); + memset(sizes, 0, sizeof(sizes)); + memset(sizes_parsed, 0, sizeof(sizes_parsed)); vpx_codec_control(codec, VP9E_GET_SVC_LAYER_ID, layer_id); parse_superframe_index(cx_pkt->data.frame.buf, cx_pkt->data.frame.sz, sizes_parsed, &count); if (enc_cfg->ss_number_layers == 1) { sizes[0] = cx_pkt->data.frame.sz; @@ -1133,42 +1142,63 @@ printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY), (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts); ++frames_received; #endif - if (enc_cfg.ss_number_layers == 1 && enc_cfg.ts_number_layers == 1) + if (enc_cfg.ss_number_layers > 1) { + uint64_t sizes[8] = { 0 }; + int count = 0; + int num_layers_encoded = 0; + parse_superframe_index(cx_pkt->data.frame.buf, + cx_pkt->data.frame.sz, sizes, &count); + for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) { + if (cx_pkt->data.frame.spatial_layer_encoded[sl]) { + si->bytes_sum[sl] += (int)sizes[num_layers_encoded]; + num_layers_encoded++; + } + } + } else { si->bytes_sum[0] += (int)cx_pkt->data.frame.sz; + } #if CONFIG_VP9_DECODER && !SIMULCAST_MODE if (vpx_codec_decode(&decoder, cx_pkt->data.frame.buf, (unsigned int)cx_pkt->data.frame.sz, NULL, 0)) die_codec(&decoder, "Failed to decode frame."); + vpx_codec_control(&encoder, VP9E_GET_SVC_LAYER_ID, &layer_id); + // Don't look for mismatch on top spatial and top temporal layers as + // they are non reference frames. Don't look at frames whose top + // spatial layer is dropped. + if ((enc_cfg.ss_number_layers > 1 || enc_cfg.ts_number_layers > 1) && + cx_pkt->data.frame + .spatial_layer_encoded[enc_cfg.ss_number_layers - 1] && + !(layer_id.temporal_layer_id > 0 && + layer_id.temporal_layer_id == + (int)enc_cfg.ts_number_layers - 1)) { + test_decode(&encoder, &decoder, frame_cnt, &mismatch_seen); + } #endif break; } + case VPX_CODEC_PSNR_PKT: { + SvcInternal_t *const si = (SvcInternal_t *)svc_ctx.internal; + sl = cx_pkt->data.psnr.spatial_layer_id; + si->number_of_frames[sl]++; + for (int j = 0; j < 4; ++j) { + si->psnr_sum[sl][j] += cx_pkt->data.psnr.psnr[j]; + si->sse_sum[sl][j] += cx_pkt->data.psnr.sse[j]; + } + break; + } case VPX_CODEC_STATS_PKT: { stats_write(&app_input.rc_stats, cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); break; } default: { break; } } - -#if CONFIG_VP9_DECODER && !SIMULCAST_MODE - vpx_codec_control(&encoder, VP9E_GET_SVC_LAYER_ID, &layer_id); - // Don't look for mismatch on top spatial and top temporal layers as they - // are non reference frames. Don't look at frames whose top spatial layer - // is dropped. - if ((enc_cfg.ss_number_layers > 1 || enc_cfg.ts_number_layers > 1) && - cx_pkt->data.frame - .spatial_layer_encoded[enc_cfg.ss_number_layers - 1] && - !(layer_id.temporal_layer_id > 0 && - layer_id.temporal_layer_id == (int)enc_cfg.ts_number_layers - 1)) { - test_decode(&encoder, &decoder, frame_cnt, &mismatch_seen); - } -#endif } if (!end_of_stream) { ++frame_cnt; pts += frame_duration; diff --git a/media/libvpx/libvpx/examples/vpx_dec_fuzzer.cc b/media/libvpx/libvpx/examples/vpx_dec_fuzzer.cc --- a/media/libvpx/libvpx/examples/vpx_dec_fuzzer.cc +++ b/media/libvpx/libvpx/examples/vpx_dec_fuzzer.cc @@ -39,11 +39,11 @@ * Build libvpx $make -j32 * Build vp9 fuzzer - $ $CXX $CXXFLAGS -std=gnu++11 -DDECODER=vp9 \ + $ $CXX $CXXFLAGS -std=gnu++17 -DDECODER=vp9 \ -fsanitize=fuzzer -I../libvpx -I. -Wl,--start-group \ ../libvpx/examples/vpx_dec_fuzzer.cc -o ./vpx_dec_fuzzer_vp9 \ ./libvpx.a -Wl,--end-group * DECODER should be defined as vp9 or vp8 to enable vp9/vp8 @@ -67,10 +67,11 @@ #include #include #include #include +#include "third_party/nalloc/nalloc.h" #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" #include "vpx_ports/mem_ops.h" #define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */ @@ -83,48 +84,76 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size <= IVF_FILE_HDR_SZ) { return 0; } + nalloc_init(nullptr); vpx_codec_ctx_t codec; // Set thread count in the range [1, 64]. const unsigned int threads = (data[IVF_FILE_HDR_SZ] & 0x3f) + 1; vpx_codec_dec_cfg_t cfg = { threads, 0, 0 }; - if (vpx_codec_dec_init(&codec, VPXD_INTERFACE(DECODER), &cfg, 0)) { + vpx_codec_flags_t flags = 0; + if ((data[IVF_FILE_HDR_SZ] & 0x40) != 0) { + flags |= VPX_CODEC_USE_POSTPROC; + } + vpx_codec_err_t err = + vpx_codec_dec_init(&codec, VPXD_INTERFACE(DECODER), &cfg, flags); + if (err == VPX_CODEC_INCAPABLE) { + // vpx_codec_dec_init may fail with VPX_CODEC_USE_POSTPROC + // if the library is configured with --disable-postproc. + flags = 0; + if (vpx_codec_dec_init(&codec, VPXD_INTERFACE(DECODER), &cfg, flags)) { + return 0; + } + } else if (err != 0) { return 0; } + nalloc_start(data, size); + if (threads > 1) { const int enable = (data[IVF_FILE_HDR_SZ] & 0xa0) != 0; - const vpx_codec_err_t err = - vpx_codec_control(&codec, VP9D_SET_LOOP_FILTER_OPT, enable); - static_cast(err); + err = vpx_codec_control(&codec, VP9D_SET_LOOP_FILTER_OPT, enable); } data += IVF_FILE_HDR_SZ; size -= IVF_FILE_HDR_SZ; + int frame_cnt = 0; while (size > IVF_FRAME_HDR_SZ) { size_t frame_size = mem_get_le32(data); size -= IVF_FRAME_HDR_SZ; data += IVF_FRAME_HDR_SZ; frame_size = std::min(size, frame_size); vpx_codec_stream_info_t stream_info; stream_info.sz = sizeof(stream_info); - vpx_codec_err_t err = vpx_codec_peek_stream_info(VPXD_INTERFACE(DECODER), - data, size, &stream_info); - static_cast(err); + err = vpx_codec_peek_stream_info(VPXD_INTERFACE(DECODER), data, size, + &stream_info); + + ++frame_cnt; + if (flags & VPX_CODEC_USE_POSTPROC) { + if (frame_cnt % 16 == 4) { + vp8_postproc_cfg_t pp = { 0, 0, 0 }; + if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) goto fail; + } else if (frame_cnt % 16 == 12) { + vp8_postproc_cfg_t pp = { VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE, 4, + 0 }; + if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) goto fail; + } + } err = vpx_codec_decode(&codec, data, frame_size, nullptr, 0); static_cast(err); vpx_codec_iter_t iter = nullptr; vpx_image_t *img = nullptr; while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) { } data += frame_size; size -= frame_size; } +fail: vpx_codec_destroy(&codec); + nalloc_end(); return 0; } diff --git a/media/libvpx/libvpx/examples/vpx_enc_fuzzer.cc b/media/libvpx/libvpx/examples/vpx_enc_fuzzer.cc new file mode 100644 --- /dev/null +++ b/media/libvpx/libvpx/examples/vpx_enc_fuzzer.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2025 The WebM project authors. 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. + */ + +/* + * Fuzzer for libvpx encoders + * ========================== + * Requirements + * -------------- + * Requires Clang 6.0 or above as -fsanitize=fuzzer is used as a linker + * option. + + * Steps to build + * -------------- + * Clone libvpx repository + $git clone https://chromium.googlesource.com/webm/libvpx + + * Create a directory in parallel to libvpx and change directory + $mkdir vpx_enc_fuzzer + $cd vpx_enc_fuzzer/ + + * Enable sanitizers (Supported: address integer memory thread undefined) + $source ../libvpx/tools/set_analyzer_env.sh address + + * Configure libvpx. + * Note --size-limit and VPX_MAX_ALLOCABLE_MEMORY are defined to avoid + * Out of memory errors when running generated fuzzer binary + $../libvpx/configure --disable-unit-tests --size-limit=12288x12288 \ + --extra-cflags="-fsanitize=fuzzer-no-link \ + -DVPX_MAX_ALLOCABLE_MEMORY=1073741824" \ + --disable-webm-io --enable-debug --enable-vp8-encoder \ + --enable-vp9-encoder --disable-examples + + * Build libvpx + $make -j32 + + * Build vp9 fuzzer + $ $CXX $CXXFLAGS -std=gnu++17 -DENCODER=vp9 \ + -fsanitize=fuzzer -I../libvpx -I. -Wl,--start-group \ + ../libvpx/examples/vpx_enc_fuzzer.cc -o ./vpx_enc_fuzzer_vp9 \ + ./libvpx.a -Wl,--end-group + + * ENCODER should be defined as vp9 or vp8 to enable vp9/vp8 + * + * create a corpus directory and copy some ivf files there. + * Based on which codec (vp8/vp9) is being tested, it is recommended to + * have corresponding ivf files in corpus directory + * Empty corpus directory also is acceptable, though not recommended + $mkdir CORPUS && cp some-files CORPUS + + * Run fuzzing: + $./vpx_enc_fuzzer_vp9 CORPUS + + * References: + * http://llvm.org/docs/LibFuzzer.html + * https://github.com/google/oss-fuzz + */ + +#include +#include +#include +#include +#include +#include + +#include "vpx/vp8cx.h" +#include "vpx/vpx_encoder.h" +#include "vpx_ports/mem_ops.h" +#include "third_party/nalloc/nalloc.h" + +// fuzz header to have config options, before raw image data +#define FUZZ_HDR_SZ 32 + +#define VPXC_INTERFACE(name) VPXC_INTERFACE_(name) +#define VPXC_INTERFACE_(name) vpx_codec_##name##_cx() + +extern "C" void usage_exit(void) { exit(EXIT_FAILURE); } + +static int vpx_img_plane_width(const vpx_image_t *img, int plane) { + if (plane > 0 && img->x_chroma_shift > 0) + return (img->d_w + 1) >> img->x_chroma_shift; + else + return img->d_w; +} + +static int vpx_img_plane_height(const vpx_image_t *img, int plane) { + if (plane > 0 && img->y_chroma_shift > 0) + return (img->d_h + 1) >> img->y_chroma_shift; + else + return img->d_h; +} + +static int fuzz_vpx_img_read(vpx_image_t *img, const uint8_t *data, + size_t size) { + int plane; + // TODO: wtc - Need to clamp the sample values so that they are in range + // For example, if the bit depth is 10, the sample values must be <= 1023. + assert(img->bit_depth == 8); + const size_t bytespp = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1; + + if (size == 0) return 0; + size_t used = 0; + for (plane = 0; plane < 3; ++plane) { + unsigned char *buf = img->planes[plane]; + const int stride = img->stride[plane]; + int w = vpx_img_plane_width(img, plane); + const int h = vpx_img_plane_height(img, plane); + int y; + + // Assuming that for nv12 we read all chroma data at once + if (img->fmt == VPX_IMG_FMT_NV12 && plane > 1) break; + // Fixing NV12 chroma width if it is odd + if (img->fmt == VPX_IMG_FMT_NV12 && plane == 1) w = (w + 1) & ~1; + + for (y = 0; y < h; ++y) { + size_t nb = bytespp * w; + if (nb > size - used) { + nb = size - used; + } + memcpy(buf, data, nb); + memset(buf + nb, 0, bytespp * w - nb); + buf += stride; + data += nb; + used += nb; + } + } + + return used; +} + +static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img, + int frame_index, int flags, FILE *out, + vpx_enc_deadline_t quality) { + int got_pkts = 0; + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt = NULL; + const vpx_codec_err_t res = + vpx_codec_encode(codec, img, frame_index, 1, flags, quality); + if (res != VPX_CODEC_OK) return 0; + + while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { + got_pkts = 1; + + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { + if (fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, out) != + pkt->data.frame.sz) + return 0; + } + } + + return got_pkts; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size <= FUZZ_HDR_SZ) { + return 0; + } + nalloc_init(nullptr); + + int keyframe_interval = 0; + int frame_count = 0; + vpx_codec_ctx_t codec; + vpx_image_t raw; + vpx_codec_enc_cfg_t cfg; + vpx_enc_deadline_t quality = VPX_DL_GOOD_QUALITY; + + if ((data[0] & 0x80) != 0) { + keyframe_interval = 8; + } + if ((data[0] & 0x40) != 0) { + quality = VPX_DL_REALTIME; + } else if ((data[0] & 0x20) != 0) { + quality = VPX_DL_BEST_QUALITY; + } + + if (vpx_codec_enc_config_default(VPXC_INTERFACE(ENCODER), &cfg, 0)) abort(); + FILE *out = fopen("/dev/null", "wb"); + + switch (data[0] & 0x1F) { + case 0: cfg.g_w = 64; cfg.g_h = 1; + case 1: cfg.g_w = 1; cfg.g_h = 48; + case 2: cfg.g_w = 1; cfg.g_h = 1; + case 3: cfg.g_w = 4; cfg.g_h = 4; + case 4: cfg.g_w = 16; cfg.g_h = 16; + default: cfg.g_w = 64; cfg.g_h = 48; + } + cfg.g_timebase.num = 1; + cfg.g_timebase.den = 30; // fps + cfg.rc_target_bitrate = 200; + cfg.g_error_resilient = 1; + + if (vpx_codec_enc_init(&codec, VPXC_INTERFACE(ENCODER), &cfg, 0)) { + return 0; + } + + if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1)) { + goto fail; + } + + nalloc_start(data, size); + // We may want to add more config options (for more complex encoders as seen + // in the examples) in the future while still maintaining the same format (so + // that generated corpus is still valid). So we reserve FUZZ_HDR_SZ=32 bytes + // for this even if we just use one byte so far. + data += FUZZ_HDR_SZ; + size -= FUZZ_HDR_SZ; + + // Encode frames. + while (1) { + int flags = 0; + size_t size_read = fuzz_vpx_img_read(&raw, data, size); + if (size_read == 0) break; + data += size_read; + size -= size_read; + if (keyframe_interval > 0 && frame_count % keyframe_interval == 0) + flags |= VPX_EFLAG_FORCE_KF; + encode_frame(&codec, &raw, frame_count++, flags, out, quality); + } + + // Flush encoder. + while (encode_frame(&codec, NULL, -1, 0, out, quality)) { + } + +fail: + nalloc_end(); + vpx_img_free(&raw); + vpx_codec_destroy(&codec); + fclose(out); + return 0; +} diff --git a/media/libvpx/libvpx/examples/vpx_temporal_svc_encoder.c b/media/libvpx/libvpx/examples/vpx_temporal_svc_encoder.c --- a/media/libvpx/libvpx/examples/vpx_temporal_svc_encoder.c +++ b/media/libvpx/libvpx/examples/vpx_temporal_svc_encoder.c @@ -605,23 +605,28 @@ } } } #if ROI_MAP -static void read_mask(FILE *mask_file, int *seg_map) { +static int read_mask(FILE *mask_file, int *seg_map, int allowed_mask_rows, + int allowed_mask_cols) { int mask_rows, mask_cols, i, j; int *map_start = seg_map; - fscanf(mask_file, "%d %d\n", &mask_cols, &mask_rows); + if (fscanf(mask_file, "%d %d\n", &mask_cols, &mask_rows) != 2) return 0; + if (mask_rows != allowed_mask_rows || mask_cols != allowed_mask_cols) { + return 0; + } for (i = 0; i < mask_rows; i++) { for (j = 0; j < mask_cols; j++) { - fscanf(mask_file, "%d ", &seg_map[j]); + if (fscanf(mask_file, "%d ", &seg_map[j]) != 1) return 0; // reverse the bit seg_map[j] = 1 - seg_map[j]; } seg_map += mask_cols; } seg_map = map_start; + return 1; } #endif int main(int argc, char **argv) { VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = { NULL }; @@ -963,16 +968,20 @@ #if ROI_MAP snprintf(mask_file_name, sizeof(mask_file_name), "%s%05d.txt", argv[argc - 1], frame_cnt); mask_file = fopen(mask_file_name, "r"); if (mask_file != NULL) { - read_mask(mask_file, mask_map); + int mask_is_valid = read_mask(mask_file, mask_map, mask_rows, mask_cols); fclose(mask_file); - // set_roi_map(encoder->name, &cfg, &roi); - set_roi_skip_map(&cfg, &roi, mask_map, prev_mask_map, frame_cnt); - if (vpx_codec_control(&codec, VP9E_SET_ROI_MAP, &roi)) - die_codec(&codec, "Failed to set ROI map"); + if (mask_is_valid) { + // set_roi_map(encoder->name, &cfg, &roi); + set_roi_skip_map(&cfg, &roi, mask_map, prev_mask_map, frame_cnt); + if (vpx_codec_control(&codec, VP9E_SET_ROI_MAP, &roi)) + die_codec(&codec, "Failed to set ROI map"); + } else { + die_codec(&codec, "Mask input is invalid for ROI map"); + } } #endif frame_avail = read_frame(&input_ctx, &raw); if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id]; vpx_usec_timer_start(&timer); diff --git a/media/libvpx/libvpx/libs.mk b/media/libvpx/libvpx/libs.mk --- a/media/libvpx/libvpx/libs.mk +++ b/media/libvpx/libvpx/libs.mk @@ -180,27 +180,21 @@ INSTALL-LIBS-$(CONFIG_ENCODERS) += include/vpx/vpx_encoder.h INSTALL-LIBS-$(CONFIG_ENCODERS) += include/vpx/vpx_tpl.h ifeq ($(CONFIG_EXTERNAL_BUILD),yes) ifeq ($(CONFIG_MSVS),yes) INSTALL-LIBS-yes += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB).lib) +ifeq ($(CONFIG_STATIC),yes) INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB)d.lib) +endif INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.dll) INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.exp) endif else INSTALL-LIBS-$(CONFIG_STATIC) += $(LIBSUBDIR)/libvpx.a +ifeq ($(CONFIG_STATIC),yes) INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(LIBSUBDIR)/libvpx_g.a endif - -ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_RATE_CTRL),yesyes) - SIMPLE_ENCODE_SRCS := $(call enabled,CODEC_SRCS) - SIMPLE_ENCODE_SRCS += $(VP9_PREFIX)simple_encode.cc - SIMPLE_ENCODE_SRCS += $(VP9_PREFIX)simple_encode.h - SIMPLE_ENCODE_SRCS += ivfenc.h - SIMPLE_ENCODE_SRCS += ivfenc.c - INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)simple_encode.cc - INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)simple_encode.h endif CODEC_SRCS=$(call enabled,CODEC_SRCS) INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(CODEC_SRCS) @@ -316,13 +310,13 @@ # MAJOR = c-a, MINOR = a, PATCH = r # # To determine SO_VERSION_{MAJOR,MINOR,PATCH}, calculate c,a,r with current # SO_VERSION_* then follow the rules in the link to detemine the new version # (c1, a1, r1) and set MAJOR to [c1-a1], MINOR to a1 and PATCH to r1 -SO_VERSION_MAJOR := 9 -SO_VERSION_MINOR := 1 -SO_VERSION_PATCH := 0 +SO_VERSION_MAJOR := 11 +SO_VERSION_MINOR := 0 +SO_VERSION_PATCH := 1 ifeq ($(filter darwin%,$(TGT_OS)),$(TGT_OS)) LIBVPX_SO := libvpx.$(SO_VERSION_MAJOR).dylib SHARED_LIB_SUF := .dylib EXPORT_FILE := libvpx.syms LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \ @@ -422,17 +416,10 @@ OBJS-yes += $(RC_RTC_OBJS) LIBS-yes += $(BUILD_PFX)libvpxrc.a $(BUILD_PFX)libvpxrc_g.a $(BUILD_PFX)libvpxrc_g.a: $(RC_RTC_OBJS) endif -ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_RATE_CTRL),yesyes) - SIMPLE_ENCODE_OBJS=$(call objs,$(SIMPLE_ENCODE_SRCS)) - OBJS-yes += $(SIMPLE_ENCODE_OBJS) - LIBS-yes += $(BUILD_PFX)libsimple_encode.a $(BUILD_PFX)libsimple_encode_g.a - $(BUILD_PFX)libsimple_encode_g.a: $(SIMPLE_ENCODE_OBJS) -endif - endif # ifeq ($(CONFIG_EXTERNAL_BUILD),yes) libvpx.ver: $(call enabled,CODEC_EXPORTS) @echo " [CREATE] $@" $(qexec)echo "{ global:" > $@ @@ -516,15 +503,10 @@ RC_INTERFACE_TEST_SRCS=$(call addprefix_clean,test/,\ $(call enabled,RC_INTERFACE_TEST_SRCS)) RC_INTERFACE_TEST_OBJS := $(sort $(call objs,$(RC_INTERFACE_TEST_SRCS))) endif -SIMPLE_ENCODE_TEST_BIN=./test_simple_encode$(EXE_SFX) -SIMPLE_ENCODE_TEST_SRCS=$(call addprefix_clean,test/,\ - $(call enabled,SIMPLE_ENCODE_TEST_SRCS)) -SIMPLE_ENCODE_TEST_OBJS := $(sort $(call objs,$(SIMPLE_ENCODE_TEST_SRCS))) - libvpx_test_srcs.txt: @echo " [CREATE] $@" @echo $(LIBVPX_TEST_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ CLEAN-OBJS += libvpx_test_srcs.txt @@ -691,22 +673,10 @@ $(RC_INTERFACE_TEST_OBJS) \ -L. -lvpx -lgtest -lvpxrc $(extralibs) -lm)) endif # RC_INTERFACE_TEST endif # CONFIG_ENCODERS -ifneq ($(strip $(SIMPLE_ENCODE_TEST_OBJS)),) -$(SIMPLE_ENCODE_TEST_OBJS) $(SIMPLE_ENCODE_TEST_OBJS:.o=.d): \ - CXXFLAGS += $(GTEST_INCLUDES) -OBJS-yes += $(SIMPLE_ENCODE_TEST_OBJS) -BINS-yes += $(SIMPLE_ENCODE_TEST_BIN) - -$(SIMPLE_ENCODE_TEST_BIN): $(TEST_LIBS) libsimple_encode.a -$(eval $(call linkerxx_template,$(SIMPLE_ENCODE_TEST_BIN), \ - $(SIMPLE_ENCODE_TEST_OBJS) \ - -L. -lsimple_encode -lvpx -lgtest $(extralibs) -lm)) -endif # SIMPLE_ENCODE_TEST - endif # CONFIG_EXTERNAL_BUILD # Install test sources only if codec source is included INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(patsubst $(SRC_PATH_BARE)/%,%,\ $(shell find $(SRC_PATH_BARE)/third_party/googletest -type f)) diff --git a/media/libvpx/libvpx/test/add_noise_test.cc b/media/libvpx/libvpx/test/add_noise_test.cc --- a/media/libvpx/libvpx/test/add_noise_test.cc +++ b/media/libvpx/libvpx/test/add_noise_test.cc @@ -22,15 +22,15 @@ namespace { static const int kNoiseSize = 3072; -typedef void (*AddNoiseFunc)(uint8_t *start, const int8_t *noise, - int blackclamp, int whiteclamp, int width, - int height, int pitch); +using AddNoiseFunc = void (*)(uint8_t *start, const int8_t *noise, + int blackclamp, int whiteclamp, int width, + int height, int pitch); -typedef std::tuple AddNoiseTestFPParam; +using AddNoiseTestFPParam = std::tuple; class AddNoiseTest : public ::testing::Test, public ::testing::WithParamInterface { public: void TearDown() override { libvpx_test::ClearSystemState(); } diff --git a/media/libvpx/libvpx/test/avg_test.cc b/media/libvpx/libvpx/test/avg_test.cc --- a/media/libvpx/libvpx/test/avg_test.cc +++ b/media/libvpx/libvpx/test/avg_test.cc @@ -92,13 +92,13 @@ int source_stride_; int bit_depth_; ACMRandom rnd_; }; -typedef unsigned int (*AverageFunction)(const uint8_t *s, int pitch); +using AverageFunction = unsigned int (*)(const uint8_t *s, int pitch); -typedef std::tuple AvgFunc; +using AvgFunc = std::tuple; class AverageTest : public AverageTestBase, public ::testing::WithParamInterface { public: AverageTest() : AverageTestBase(GET_PARAM(0), GET_PARAM(1)) {} @@ -151,14 +151,14 @@ } }; #endif // CONFIG_VP9_HIGHBITDEPTH #if HAVE_NEON || HAVE_SSE2 || HAVE_MSA -typedef void (*IntProRowFunc)(int16_t hbuf[16], uint8_t const *ref, - const int ref_stride, const int height); +using IntProRowFunc = void (*)(int16_t hbuf[16], uint8_t const *ref, + const int ref_stride, const int height); -typedef std::tuple IntProRowParam; +using IntProRowParam = std::tuple; class IntProRowTest : public AverageTestBase, public ::testing::WithParamInterface { public: IntProRowTest() @@ -203,13 +203,13 @@ int16_t *hbuf_asm_; int16_t *hbuf_c_; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IntProRowTest); -typedef int16_t (*IntProColFunc)(uint8_t const *ref, const int width); +using IntProColFunc = int16_t (*)(uint8_t const *ref, const int width); -typedef std::tuple IntProColParam; +using IntProColParam = std::tuple; class IntProColTest : public AverageTestBase, public ::testing::WithParamInterface { public: IntProColTest() : AverageTestBase(GET_PARAM(0), 1), sum_asm_(0), sum_c_(0) { @@ -231,12 +231,12 @@ int16_t sum_c_; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IntProColTest); #endif // HAVE_NEON || HAVE_SSE2 || HAVE_MSA -typedef int (*SatdFunc)(const tran_low_t *coeffs, int length); -typedef std::tuple SatdTestParam; +using SatdFunc = int (*)(const tran_low_t *coeffs, int length); +using SatdTestParam = std::tuple; class SatdTest : public ::testing::Test, public ::testing::WithParamInterface { protected: void SetUp() override { @@ -283,13 +283,13 @@ src_[i] = (tran_low_t)tmp; } } }; -typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff, - const tran_low_t *dqcoeff, int block_size); -typedef std::tuple BlockErrorTestFPParam; +using BlockErrorFunc = int64_t (*)(const tran_low_t *coeff, + const tran_low_t *dqcoeff, int block_size); +using BlockErrorTestFPParam = std::tuple; class BlockErrorTestFP : public ::testing::Test, public ::testing::WithParamInterface { protected: diff --git a/media/libvpx/libvpx/test/blockiness_test.cc b/media/libvpx/libvpx/test/blockiness_test.cc --- a/media/libvpx/libvpx/test/blockiness_test.cc +++ b/media/libvpx/libvpx/test/blockiness_test.cc @@ -137,11 +137,11 @@ ACMRandom rnd_; }; #if CONFIG_VP9_ENCODER -typedef std::tuple BlockinessParam; +using BlockinessParam = std::tuple; class BlockinessVP9Test : public BlockinessTestBase, public ::testing::WithParamInterface { public: BlockinessVP9Test() : BlockinessTestBase(GET_PARAM(0), GET_PARAM(1)) {} diff --git a/media/libvpx/libvpx/test/consistency_test.cc b/media/libvpx/libvpx/test/consistency_test.cc --- a/media/libvpx/libvpx/test/consistency_test.cc +++ b/media/libvpx/libvpx/test/consistency_test.cc @@ -126,11 +126,11 @@ ACMRandom rnd_; }; #if CONFIG_VP9_ENCODER -typedef std::tuple ConsistencyParam; +using ConsistencyParam = std::tuple; class ConsistencyVP9Test : public ConsistencyTestBase, public ::testing::WithParamInterface { public: ConsistencyVP9Test() : ConsistencyTestBase(GET_PARAM(0), GET_PARAM(1)) {} diff --git a/media/libvpx/libvpx/test/convolve_test.cc b/media/libvpx/libvpx/test/convolve_test.cc --- a/media/libvpx/libvpx/test/convolve_test.cc +++ b/media/libvpx/libvpx/test/convolve_test.cc @@ -30,28 +30,28 @@ namespace { static const unsigned int kMaxDimension = 64; -typedef void (*ConvolveFunc)(const uint8_t *src, ptrdiff_t src_stride, - uint8_t *dst, ptrdiff_t dst_stride, - const InterpKernel *filter, int x0_q4, - int x_step_q4, int y0_q4, int y_step_q4, int w, - int h); +using ConvolveFunc = void (*)(const uint8_t *src, ptrdiff_t src_stride, + uint8_t *dst, ptrdiff_t dst_stride, + const InterpKernel *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, int w, + int h); #if !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER -typedef void (*ConvolveFunc12Tap)(const uint8_t *src, ptrdiff_t src_stride, - uint8_t *dst, ptrdiff_t dst_stride, - const InterpKernel12 *filter, int x0_q4, - int x_step_q4, int y0_q4, int y_step_q4, - int w, int h); +using ConvolveFunc12Tap = void (*)(const uint8_t *src, ptrdiff_t src_stride, + uint8_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, + int w, int h); #endif -typedef void (*WrapperFilterBlock2d8Func)( - const uint8_t *src_ptr, const unsigned int src_stride, - const int16_t *hfilter, const int16_t *vfilter, uint8_t *dst_ptr, - unsigned int dst_stride, unsigned int output_width, - unsigned int output_height, int use_highbd); +using WrapperFilterBlock2d8Func = + void (*)(const uint8_t *src_ptr, const unsigned int src_stride, + const int16_t *hfilter, const int16_t *vfilter, uint8_t *dst_ptr, + unsigned int dst_stride, unsigned int output_width, + unsigned int output_height, int use_highbd); struct ConvolveFunctions { ConvolveFunctions(ConvolveFunc copy, ConvolveFunc avg, ConvolveFunc h8, ConvolveFunc h8_avg, ConvolveFunc v8, ConvolveFunc v8_avg, ConvolveFunc hv8, ConvolveFunc hv8_avg, ConvolveFunc sh8, @@ -83,11 +83,11 @@ ConvolveFunc sv8_[2]; // scaled vert ConvolveFunc shv8_[2]; // scaled horiz/vert int use_highbd_; // 0 if high bitdepth not used, else the actual bit depth. }; -typedef std::tuple ConvolveParam; +using ConvolveParam = std::tuple; #if !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER struct ConvolveFunctions12Tap { ConvolveFunctions12Tap(ConvolveFunc12Tap h12, ConvolveFunc12Tap v12, ConvolveFunc12Tap hv12, int bd) @@ -101,11 +101,11 @@ ConvolveFunc12Tap v12_; ConvolveFunc12Tap hv12_; int use_highbd_; // 0 if high bitdepth not used, else the actual bit depth. }; -typedef std::tuple Convolve12TapParam; +using Convolve12TapParam = std::tuple; #endif #define ALL_SIZES(convolve_fn) \ make_tuple(4, 4, &convolve_fn), make_tuple(8, 4, &convolve_fn), \ make_tuple(4, 8, &convolve_fn), make_tuple(8, 8, &convolve_fn), \ @@ -1802,10 +1802,34 @@ WRAP12TAP(convolve12_horiz_ssse3, 12) WRAP12TAP(convolve12_vert_ssse3, 12) WRAP12TAP(convolve12_ssse3, 12) #endif // HAVE_SSSE3 +#if HAVE_NEON +WRAP12TAP(convolve12_horiz_neon, 8) +WRAP12TAP(convolve12_vert_neon, 8) +WRAP12TAP(convolve12_neon, 8) +WRAP12TAP(convolve12_horiz_neon, 10) +WRAP12TAP(convolve12_vert_neon, 10) +WRAP12TAP(convolve12_neon, 10) +WRAP12TAP(convolve12_horiz_neon, 12) +WRAP12TAP(convolve12_vert_neon, 12) +WRAP12TAP(convolve12_neon, 12) +#endif // HAVE_NEON + +#if HAVE_SVE2 +WRAP12TAP(convolve12_horiz_sve2, 8) +WRAP12TAP(convolve12_vert_sve2, 8) +WRAP12TAP(convolve12_sve2, 8) +WRAP12TAP(convolve12_horiz_sve2, 10) +WRAP12TAP(convolve12_vert_sve2, 10) +WRAP12TAP(convolve12_sve2, 10) +WRAP12TAP(convolve12_horiz_sve2, 12) +WRAP12TAP(convolve12_vert_sve2, 12) +WRAP12TAP(convolve12_sve2, 12) +#endif // HAVE_SVE2 + WRAP12TAP(convolve12_horiz_c, 8) WRAP12TAP(convolve12_vert_c, 8) WRAP12TAP(convolve12_c, 8) WRAP12TAP(convolve12_horiz_c, 10) WRAP12TAP(convolve12_vert_c, 10) @@ -2043,18 +2067,41 @@ #endif // CONFIG_VP9_HIGHBITDEPTH INSTANTIATE_TEST_SUITE_P(NEON, ConvolveTest, ::testing::ValuesIn(kArrayConvolve_neon)); #if !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER +#if CONFIG_VP9_HIGHBITDEPTH +const ConvolveFunctions12Tap convolve12tap_8bit_neon( + wrap_convolve12_horiz_neon_8, wrap_convolve12_vert_neon_8, + wrap_convolve12_neon_8, 8); + +const ConvolveFunctions12Tap convolve12tap_10bit_neon( + wrap_convolve12_horiz_neon_10, wrap_convolve12_vert_neon_10, + wrap_convolve12_neon_10, 10); + +const ConvolveFunctions12Tap convolve12tap_12bit_neon( + wrap_convolve12_horiz_neon_12, wrap_convolve12_vert_neon_12, + wrap_convolve12_neon_12, 12); + +const Convolve12TapParam kArrayConvolve12Tap_neon[] = { + ALL_SIZES_12TAP(convolve12tap_8bit_neon), + ALL_SIZES_12TAP(convolve12tap_10bit_neon), + ALL_SIZES_12TAP(convolve12tap_12bit_neon) +}; + +#else + const ConvolveFunctions12Tap convolve12Tap_neon(vpx_convolve12_horiz_neon, vpx_convolve12_vert_neon, vpx_convolve12_neon, 0); const Convolve12TapParam kArrayConvolve12Tap_neon[] = { ALL_SIZES_12TAP( convolve12Tap_neon) }; +#endif // CONFIG_VP9_HIGHBITDEPTH + INSTANTIATE_TEST_SUITE_P(NEON, ConvolveTest12Tap, ::testing::ValuesIn(kArrayConvolve12Tap_neon)); -#endif +#endif // !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER #endif // HAVE_NEON #if HAVE_NEON_DOTPROD const ConvolveFunctions convolve8_neon_dotprod( vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_neon_dotprod, @@ -2143,10 +2190,33 @@ const ConvolveParam kArrayConvolve_sve2[] = { ALL_SIZES(convolve8_sve2), ALL_SIZES(convolve10_sve2), ALL_SIZES(convolve12_sve2) }; INSTANTIATE_TEST_SUITE_P(SVE2, ConvolveTest, ::testing::ValuesIn(kArrayConvolve_sve2)); + +#if !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER +const ConvolveFunctions12Tap convolve12tap_8bit_sve2( + wrap_convolve12_horiz_sve2_8, wrap_convolve12_vert_sve2_8, + wrap_convolve12_sve2_8, 8); + +const ConvolveFunctions12Tap convolve12tap_10bit_sve2( + wrap_convolve12_horiz_sve2_10, wrap_convolve12_vert_sve2_10, + wrap_convolve12_sve2_10, 10); + +const ConvolveFunctions12Tap convolve12tap_12bit_sve2( + wrap_convolve12_horiz_sve2_12, wrap_convolve12_vert_sve2_12, + wrap_convolve12_sve2_12, 12); + +const Convolve12TapParam kArrayConvolve12Tap_sve2[] = { + ALL_SIZES_12TAP(convolve12tap_8bit_sve2), + ALL_SIZES_12TAP(convolve12tap_10bit_sve2), + ALL_SIZES_12TAP(convolve12tap_12bit_sve2) +}; + +INSTANTIATE_TEST_SUITE_P(SVE2, ConvolveTest12Tap, + ::testing::ValuesIn(kArrayConvolve12Tap_sve2)); +#endif // !CONFIG_REALTIME_ONLY && CONFIG_VP9_ENCODER #endif // CONFIG_VP9_HIGHBITDEPTH #endif // HAVE_SVE2 #if HAVE_NEON_I8MM const ConvolveFunctions convolve8_neon_i8mm( diff --git a/media/libvpx/libvpx/test/cq_test.cc b/media/libvpx/libvpx/test/cq_test.cc --- a/media/libvpx/libvpx/test/cq_test.cc +++ b/media/libvpx/libvpx/test/cq_test.cc @@ -26,11 +26,11 @@ class CQTest : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { public: // maps the cqlevel to the bitrate produced. - typedef std::map BitrateMap; + using BitrateMap = std::map; static void SetUpTestSuite() { bitrates_.clear(); } static void TearDownTestSuite() { ASSERT_TRUE(!HasFailure()) diff --git a/media/libvpx/libvpx/test/dct16x16_test.cc b/media/libvpx/libvpx/test/dct16x16_test.cc --- a/media/libvpx/libvpx/test/dct16x16_test.cc +++ b/media/libvpx/libvpx/test/dct16x16_test.cc @@ -222,20 +222,20 @@ // Scale by some magic number for (int j = 0; j < 16; ++j) output[j + i * 16] = temp_out[j] / 2; } } -typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); -typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); -typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, - int tx_type); -typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, - int tx_type); +using FdctFunc = void (*)(const int16_t *in, tran_low_t *out, int stride); +using IdctFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride); +using FhtFunc = void (*)(const int16_t *in, tran_low_t *out, int stride, + int tx_type); +using IhtFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride, + int tx_type); -typedef std::tuple Dct16x16Param; -typedef std::tuple Ht16x16Param; -typedef std::tuple Idct16x16Param; +using Dct16x16Param = std::tuple; +using Ht16x16Param = std::tuple; +using Idct16x16Param = std::tuple; void fdct16x16_ref(const int16_t *in, tran_low_t *out, int stride, int /*tx_type*/) { vpx_fdct16x16_c(in, out, stride); } diff --git a/media/libvpx/libvpx/test/dct32x32_test.cc b/media/libvpx/libvpx/test/dct32x32_test.cc --- a/media/libvpx/libvpx/test/dct32x32_test.cc +++ b/media/libvpx/libvpx/test/dct32x32_test.cc @@ -64,18 +64,18 @@ // Scale by some magic number for (int j = 0; j < 32; ++j) output[j + i * 32] = temp_out[j] / 4; } } -typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride); -typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride); +using FwdTxfmFunc = void (*)(const int16_t *in, tran_low_t *out, int stride); +using InvTxfmFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride); -typedef std::tuple - Trans32x32Param; +using Trans32x32Param = + std::tuple; -typedef std::tuple - InvTrans32x32Param; +using InvTrans32x32Param = + std::tuple; #if CONFIG_VP9_HIGHBITDEPTH void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) { vpx_highbd_idct32x32_1024_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); } diff --git a/media/libvpx/libvpx/test/dct_partial_test.cc b/media/libvpx/libvpx/test/dct_partial_test.cc --- a/media/libvpx/libvpx/test/dct_partial_test.cc +++ b/media/libvpx/libvpx/test/dct_partial_test.cc @@ -31,14 +31,14 @@ using libvpx_test::Buffer; using std::make_tuple; using std::tuple; namespace { -typedef void (*PartialFdctFunc)(const int16_t *in, tran_low_t *out, int stride); +using PartialFdctFunc = void (*)(const int16_t *in, tran_low_t *out, + int stride); -typedef tuple - PartialFdctParam; +using PartialFdctParam = tuple; tran_low_t partial_fdct_ref(const Buffer &in, int size) { int64_t sum = 0; if (in.TopLeftPixel() != nullptr) { for (int y = 0; y < size; ++y) { diff --git a/media/libvpx/libvpx/test/dct_test.cc b/media/libvpx/libvpx/test/dct_test.cc --- a/media/libvpx/libvpx/test/dct_test.cc +++ b/media/libvpx/libvpx/test/dct_test.cc @@ -32,20 +32,20 @@ using libvpx_test::Buffer; using std::make_tuple; using std::tuple; namespace { -typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); -typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); -typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, - int tx_type); -typedef void (*FhtFuncRef)(const Buffer &in, Buffer *out, - int size, int tx_type); -typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, - int tx_type); -typedef void (*IhtWithBdFunc)(const tran_low_t *in, uint8_t *out, int stride, - int tx_type, int bd); +using FdctFunc = void (*)(const int16_t *in, tran_low_t *out, int stride); +using IdctFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride); +using FhtFunc = void (*)(const int16_t *in, tran_low_t *out, int stride, + int tx_type); +using FhtFuncRef = void (*)(const Buffer &in, Buffer *out, + int size, int tx_type); +using IhtFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride, + int tx_type); +using IhtWithBdFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride, + int tx_type, int bd); template void fdct_wrapper(const int16_t *in, tran_low_t *out, int stride, int tx_type) { (void)tx_type; fn(in, out, stride); @@ -65,15 +65,15 @@ (void)bd; fn(in, out, stride, tx_type); } #if CONFIG_VP9_HIGHBITDEPTH -typedef void (*HighbdIdctFunc)(const tran_low_t *in, uint16_t *out, int stride, - int bd); +using HighbdIdctFunc = void (*)(const tran_low_t *in, uint16_t *out, int stride, + int bd); -typedef void (*HighbdIhtFunc)(const tran_low_t *in, uint16_t *out, int stride, - int tx_type, int bd); +using HighbdIhtFunc = void (*)(const tran_low_t *in, uint16_t *out, int stride, + int tx_type, int bd); template void highbd_idct_wrapper(const tran_low_t *in, uint8_t *out, int stride, int tx_type, int bd) { (void)tx_type; @@ -93,11 +93,11 @@ int size; int pixel_size; }; /* forward transform, inverse transform, size, transform type, bit depth */ -typedef tuple DctParam; +using DctParam = tuple; void fdct_ref(const Buffer &in, Buffer *out, int size, int /*tx_type*/) { const int16_t *i = in.TopLeftPixel(); const int i_stride = in.stride(); diff --git a/media/libvpx/libvpx/test/decode_corrupted.cc b/media/libvpx/libvpx/test/decode_corrupted.cc --- a/media/libvpx/libvpx/test/decode_corrupted.cc +++ b/media/libvpx/libvpx/test/decode_corrupted.cc @@ -57,11 +57,11 @@ const vpx_codec_cx_pkt_t *pkt) override { // Don't edit frame packet on key frame. if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) return pkt; if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) return pkt; - memcpy(&modified_pkt_, pkt, sizeof(*pkt)); + modified_pkt_ = *pkt; // Halve the size so it's corrupted to decoder. modified_pkt_.data.frame.sz = modified_pkt_.data.frame.sz / 2; return &modified_pkt_; diff --git a/media/libvpx/libvpx/test/decode_perf_test.cc b/media/libvpx/libvpx/test/decode_perf_test.cc --- a/media/libvpx/libvpx/test/decode_perf_test.cc +++ b/media/libvpx/libvpx/test/decode_perf_test.cc @@ -34,11 +34,11 @@ const char kNewEncodeOutputFile[] = "new_encode.ivf"; /* DecodePerfTest takes a tuple of filename + number of threads to decode with */ -typedef std::tuple DecodePerfParam; +using DecodePerfParam = std::tuple; const DecodePerfParam kVP9DecodePerfVectors[] = { make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1), make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2), make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2), diff --git a/media/libvpx/libvpx/test/decode_test_driver.cc b/media/libvpx/libvpx/test/decode_test_driver.cc --- a/media/libvpx/libvpx/test/decode_test_driver.cc +++ b/media/libvpx/libvpx/test/decode_test_driver.cc @@ -109,11 +109,11 @@ vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); RunLoop(video, dec_cfg); } void DecoderTest::set_cfg(const vpx_codec_dec_cfg_t &dec_cfg) { - memcpy(&cfg_, &dec_cfg, sizeof(cfg_)); + cfg_ = dec_cfg; } void DecoderTest::set_flags(const vpx_codec_flags_t flags) { flags_ = flags; } } // namespace libvpx_test diff --git a/media/libvpx/libvpx/test/encode_api_test.cc b/media/libvpx/libvpx/test/encode_api_test.cc --- a/media/libvpx/libvpx/test/encode_api_test.cc +++ b/media/libvpx/libvpx/test/encode_api_test.cc @@ -475,10 +475,65 @@ EXPECT_EQ(vpx_codec_get_global_headers(&enc.ctx), nullptr); EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc.ctx)); EXPECT_EQ(vpx_codec_get_global_headers(&enc.ctx), nullptr); } +// Encode a few frames for 2 temporal layers realtime mode. +// Set duration to be very large on first frame, much smaller +// on second frames, with the timestamp (pts) parameter very +// inconsistent with the duration (i.e, pts != prev_pts + duration). +// This reproduces the issue found in the bug: 431520320. +TEST(EncodeAPI, Vp8ChromiumIssue431520320) { + // Initialize libvpx encoder. + vpx_codec_iface_t *const iface = vpx_codec_vp8_cx(); + vpx_codec_ctx_t enc; + vpx_codec_enc_cfg_t cfg; + + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + + cfg.g_w = 320; + cfg.g_h = 240; + cfg.g_lag_in_frames = 0; + cfg.rc_target_bitrate = 500; + + // 2-layers, 2-frame period. + int ids[2] = { 0, 1 }; + cfg.ts_periodicity = 2; + cfg.ts_number_layers = 2; + cfg.ts_rate_decimator[0] = 2; + cfg.ts_rate_decimator[1] = 1; + cfg.ts_target_bitrate[0] = 300; + cfg.ts_target_bitrate[1] = 500; + memcpy(cfg.ts_layer_id, ids, sizeof(ids)); + + ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK); + + // Create input image. + vpx_image_t *const image = + CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h); + ASSERT_NE(image, nullptr); + + // Encode first frame. + ASSERT_EQ( + vpx_codec_encode(&enc, image, 0, /*duration=*/800000, 0, VPX_DL_REALTIME), + VPX_CODEC_OK); + + // Encode second frame. + ASSERT_EQ(vpx_codec_encode(&enc, image, 40000, /*duration=*/40000, 0, + VPX_DL_REALTIME), + VPX_CODEC_OK); + + // Encode third frame. + ASSERT_EQ(vpx_codec_encode(&enc, image, 80000, /*duration=*/40000, 0, + VPX_DL_REALTIME), + VPX_CODEC_OK); + + // Free resources. + vpx_img_free(image); + ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); +} + TEST(EncodeAPI, AomediaIssue3509VbrMinSection2PercentVP8) { // Initialize libvpx encoder. vpx_codec_iface_t *const iface = vpx_codec_vp8_cx(); vpx_codec_ctx_t enc; vpx_codec_enc_cfg_t cfg; @@ -698,11 +753,11 @@ cfg[0].rc_target_bitrate = target_bitrate; /* Set target bitrate */ cfg[0].g_timebase.num = 1; /* Set fps */ cfg[0].g_timebase.den = framerate; - memcpy(&cfg[1], &cfg[0], sizeof(cfg[0])); + cfg[1] = cfg[0]; cfg[1].rc_target_bitrate = 500; cfg[1].g_w = width_down; cfg[1].g_h = height_down; for (int i = 0; i < 2; i++) { @@ -1034,10 +1089,66 @@ vpx_img_free(image); ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); } } +TEST(EncodeAPI, PerFramePsnr) { + for (const auto *iface : kCodecIfaces) { + SCOPED_TRACE(vpx_codec_iface_name(iface)); + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + cfg.g_lag_in_frames = 0; + + vpx_codec_ctx_t enc; + ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK); + + vpx_image_t *const image = + CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h); + ASSERT_NE(image, nullptr); + + vpx_enc_frame_flags_t psnr_flags = VPX_EFLAG_CALCULATE_PSNR; + ASSERT_EQ(vpx_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, + psnr_flags, VPX_DL_REALTIME), + VPX_CODEC_OK); + + const vpx_codec_cx_pkt_t *pkt; + vpx_codec_iter_t iter = nullptr; + bool had_psnr = false; + while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) { + if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) { + ASSERT_EQ(pkt->kind, VPX_CODEC_PSNR_PKT); + had_psnr = true; + } + } + EXPECT_TRUE(had_psnr); + + vpx_enc_frame_flags_t no_psnr_flags = 0; + ASSERT_EQ(vpx_codec_encode(&enc, image, /*pts=*/1, /*duration=*/1, + no_psnr_flags, VPX_DL_REALTIME), + VPX_CODEC_OK); + + iter = nullptr; + had_psnr = false; + while ((pkt = vpx_codec_get_cx_data(&enc, &iter)) != nullptr) { + if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) { + ASSERT_EQ(pkt->kind, VPX_CODEC_PSNR_PKT); + had_psnr = true; + } + } +#if CONFIG_INTERNAL_STATS + // CONFIG_INTERNAL_STATS unconditionally generates PSNR. + EXPECT_TRUE(had_psnr); +#else + EXPECT_FALSE(had_psnr); +#endif // CONFIG_INTERNAL_STATS + + // Free resources. + vpx_img_free(image); + ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); + } +} + #if CONFIG_VP9_ENCODER // Frame size needed to trigger the overflow exceeds the max buffer allowed on // 32-bit systems defined by VPX_MAX_ALLOCABLE_MEMORY #if VPX_ARCH_X86_64 || VPX_ARCH_AARCH64 TEST(EncodeAPI, ConfigLargeTargetBitrateVp9) { @@ -1493,10 +1604,46 @@ // Encode more frames with new config. encoder.Encode(false); encoder.Encode(false); } +// Test case to capture assert issue triggered in +// vp9_bitstream.c for good_quality, speed 1, lossless; +// See comment#22 in issue:433941753. +TEST(EncodeAPI, AssertIssueGoodQualitySpeed1Lossless) { + vpx_codec_iface_t *const iface = vpx_codec_vp9_cx(); + vpx_codec_ctx_t enc; + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + cfg.g_w = 1540; + cfg.g_h = 838; + cfg.g_profile = 0; + cfg.g_bit_depth = VPX_BITS_8; + cfg.g_timebase.num = 1; + cfg.g_timebase.den = 10000; + cfg.g_pass = VPX_RC_ONE_PASS; + cfg.g_lag_in_frames = 0; + cfg.rc_end_usage = VPX_VBR; + cfg.g_threads = 1; + cfg.rc_target_bitrate = 10000; + ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK); + ASSERT_EQ(vpx_codec_control(&enc, VP9E_SET_LOSSLESS, 1), VPX_CODEC_OK); + ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, 1), VPX_CODEC_OK); + libvpx_test::RandomVideoSource video; + video.SetSize(cfg.g_w, cfg.g_h); + video.SetImageFormat(VPX_IMG_FMT_I420); + video.set_limit(20); + video.Begin(); + do { + ASSERT_EQ(vpx_codec_encode(&enc, video.img(), video.pts(), video.duration(), + 0, VPX_DL_GOOD_QUALITY), + VPX_CODEC_OK); + video.Next(); + } while (video.img() != nullptr); + ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); +} + TEST(EncodeAPI, Buganizer317105128) { VP9Encoder encoder(-9); encoder.Configure(0, 1, 1, VPX_CBR, VPX_DL_GOOD_QUALITY); encoder.Configure(16, 1920, 1, VPX_CBR, VPX_DL_REALTIME); } @@ -1594,10 +1741,197 @@ encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/798, VPX_CBR, VPX_DL_REALTIME); encoder.Encode(/*key_frame=*/false); } +// Encode some frames, flip from BEST_QUALITY to REALTIME after 2 frames. +// This test is taken from the code snippet in issue:441668134. +TEST(EncodeAPI, Buganizer441668134) { + // Get VP9 encoder interface. + vpx_codec_iface_t *iface = vpx_codec_vp9_cx(); + // Initialize encoder configuration with default values. + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + cfg.g_lag_in_frames = 0; + cfg.rc_max_quantizer = 0; + unsigned long init_flags = 0; + vpx_codec_ctx_t ctx; + ASSERT_EQ(vpx_codec_enc_init(&ctx, iface, &cfg, init_flags), VPX_CODEC_OK); + ASSERT_EQ(vpx_codec_control_(&ctx, VP8E_SET_CPUUSED, 9), 0); + ASSERT_EQ(vpx_codec_control_(&ctx, VP9E_SET_DELTA_Q_UV, -15), 0); + // Image allocation. + vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420; + vpx_image_t *img = vpx_img_alloc(NULL, img_fmt, cfg.g_w, cfg.g_h, 32); + for (unsigned int y = 0; y < img->d_h; y++) { + for (unsigned int x = 0; x < img->d_w; x++) { + img->planes[0][y * img->stride[0] + x] = ((x ^ y) * 127) & 0xFF; + } + } + const unsigned int uv_height = (img->d_h + 1) >> 1; + for (int i : { VPX_PLANE_U, VPX_PLANE_V }) { + memset(img->planes[i], 0, img->stride[i] * uv_height); + } + // Encode some frames. + int num_frames = 6; + static constexpr int kChoices[6] = { 1, 1, 0, 0, 0, 0 }; + for (int frame = 0; frame < num_frames; frame++) { + vpx_enc_deadline_t deadline = VPX_DL_REALTIME; + uint8_t dl_choice = kChoices[frame]; + if (dl_choice == 1) deadline = VPX_DL_BEST_QUALITY; + // Encode frame. + ASSERT_EQ(vpx_codec_encode(&ctx, img, frame, 1, 0, deadline), VPX_CODEC_OK); + } + vpx_img_free(img); + vpx_codec_destroy(&ctx); +} + +// Encode a few frames, with realtime mode and tile_rows set to 1, +// with row-mt enabled. This triggers an assertion in vp9_bitstream.c (in +// function write_modes()), as in the issue:442105459. In this test it happens +// on very first encoded frame since lag_in_frames = 0. Issue is due to enabling +// TILE_ROWS, with number of tile_rows more than the number of superblocks. +// This test sets 2 tile_rows with height corresponding to 1 superblock (sb). +TEST(EncodeAPI, Buganizer442105459_2RowTiles) { + // Initialize VP9 encoder interface + vpx_codec_iface_t *iface = vpx_codec_vp9_cx(); + // Get default encoder configuration + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + // Configure encoder + cfg.g_w = 946u; + cfg.g_h = 64u; // 1 sb row, 2 tile_rows set below. + cfg.g_threads = 1; + cfg.g_profile = 0; + cfg.g_bit_depth = VPX_BITS_8; + // Rate control targeting deeper encoding paths + cfg.rc_target_bitrate = 100; + cfg.rc_min_quantizer = 0; + cfg.rc_max_quantizer = 0; + cfg.rc_end_usage = VPX_VBR; + cfg.ss_number_layers = 1; + cfg.g_lag_in_frames = 0; + // Initialize encoder context + vpx_codec_ctx_t ctx; + ASSERT_EQ(vpx_codec_enc_init(&ctx, iface, &cfg, 0), VPX_CODEC_OK); + // Set control parameters + vpx_codec_control_(&ctx, VP8E_SET_CPUUSED, -5); + vpx_codec_control_(&ctx, VP9E_SET_TILE_ROWS, 1); + vpx_codec_control_(&ctx, VP9E_SET_TILE_COLUMNS, 1); + vpx_codec_control_(&ctx, VP9E_SET_ROW_MT, 1); + // Image format selection + vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420; + // Allocate image with varied alignment + vpx_image_t *img = vpx_img_alloc(nullptr, img_fmt, cfg.g_w, cfg.g_h, 1); + for (unsigned int y = 0; y < img->d_h; y++) { + for (unsigned int x = 0; x < img->d_w; x++) { + img->planes[0][y * img->stride[0] + x] = ((x ^ y) * 127) & 0xFF; + } + } + const unsigned int uv_height = (img->d_h + 1) >> 1; + for (int i : { VPX_PLANE_U, VPX_PLANE_V }) { + memset(img->planes[i], 0, img->stride[i] * uv_height); + } + // Encode with dynamic configuration changes + int num_frames = 2; + // Per-frame constants captured from the original run (indices consumed per + // frame) + const vpx_codec_pts_t frame_pts_mul[] = { 33333UL, 33333UL }; + const unsigned long frame_durations[] = { 33333UL, 33333UL }; + const vpx_enc_deadline_t frame_deadlines[] = { VPX_DL_REALTIME, + VPX_DL_REALTIME }; + for (int frame = 0; frame < num_frames; frame++) { + // Encode frame + vpx_codec_pts_t pts = frame * frame_pts_mul[frame]; + unsigned long duration = frame_durations[frame]; + vpx_enc_deadline_t deadline = frame_deadlines[frame]; + ASSERT_EQ(vpx_codec_encode(&ctx, img, pts, duration, /*flags*/ 0, deadline), + VPX_CODEC_OK); + } + // Flush encoder. + ASSERT_EQ(vpx_codec_encode(&ctx, nullptr, 0, 0, 0, VPX_DL_REALTIME), 0); + // Get remaining data + vpx_codec_iter_t iter = nullptr; + while (vpx_codec_get_cx_data(&ctx, &iter) != nullptr) { + // Process remaining packets + } + vpx_img_free(img); + vpx_codec_destroy(&ctx); +} + +// Encode a few frames, with realtime mode and tile_rows set to 1, +// with row-mt enabled. This triggers an assertion in vp9_bitstream.c (in +// function write_modes()), as in the issue:442105459. In this test it happens +// on very first encoded frame since lag_in_frames = 0. Issue is due to enabling +// TILE_ROWS, with number of tile_rows more than the number of superblocks. +// This test sets 4 tile_rows with height corresponding to 3 superblocks. +TEST(EncodeAPI, Buganizer442105459_4RowTiles) { + // Initialize VP9 encoder interface + vpx_codec_iface_t *iface = vpx_codec_vp9_cx(); + // Get default encoder configuration + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + // Configure encoder + cfg.g_w = 946u; + cfg.g_h = 192u; // 3 sb rows, 4 tile_rows set below. + cfg.g_threads = 1; + cfg.g_profile = 0; + cfg.g_bit_depth = VPX_BITS_8; + // Rate control targeting deeper encoding paths + cfg.rc_target_bitrate = 100; + cfg.rc_min_quantizer = 0; + cfg.rc_max_quantizer = 0; + cfg.rc_end_usage = VPX_VBR; + cfg.ss_number_layers = 1; + cfg.g_lag_in_frames = 0; + // Initialize encoder context + vpx_codec_ctx_t ctx; + ASSERT_EQ(vpx_codec_enc_init(&ctx, iface, &cfg, 0), VPX_CODEC_OK); + // Set control parameters + vpx_codec_control_(&ctx, VP8E_SET_CPUUSED, -5); + vpx_codec_control_(&ctx, VP9E_SET_TILE_ROWS, 2); + vpx_codec_control_(&ctx, VP9E_SET_TILE_COLUMNS, 1); + vpx_codec_control_(&ctx, VP9E_SET_ROW_MT, 1); + // Image format selection + vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420; + // Allocate image with varied alignment + vpx_image_t *img = vpx_img_alloc(nullptr, img_fmt, cfg.g_w, cfg.g_h, 1); + for (unsigned int y = 0; y < img->d_h; y++) { + for (unsigned int x = 0; x < img->d_w; x++) { + img->planes[0][y * img->stride[0] + x] = ((x ^ y) * 127) & 0xFF; + } + } + const unsigned int uv_height = (img->d_h + 1) >> 1; + for (int i : { VPX_PLANE_U, VPX_PLANE_V }) { + memset(img->planes[i], 0, img->stride[i] * uv_height); + } + // Encode with dynamic configuration changes + int num_frames = 2; + // Per-frame constants captured from the original run (indices consumed per + // frame) + const vpx_codec_pts_t frame_pts_mul[] = { 33333UL, 33333UL }; + const unsigned long frame_durations[] = { 33333UL, 33333UL }; + const vpx_enc_deadline_t frame_deadlines[] = { VPX_DL_REALTIME, + VPX_DL_REALTIME }; + for (int frame = 0; frame < num_frames; frame++) { + // Encode frame + vpx_codec_pts_t pts = frame * frame_pts_mul[frame]; + unsigned long duration = frame_durations[frame]; + vpx_enc_deadline_t deadline = frame_deadlines[frame]; + ASSERT_EQ(vpx_codec_encode(&ctx, img, pts, duration, /*flags*/ 0, deadline), + VPX_CODEC_OK); + } + // Flush encoder. + ASSERT_EQ(vpx_codec_encode(&ctx, nullptr, 0, 0, 0, VPX_DL_REALTIME), 0); + // Get remaining data + vpx_codec_iter_t iter = nullptr; + while (vpx_codec_get_cx_data(&ctx, &iter) != nullptr) { + // Process remaining packets + } + vpx_img_free(img); + vpx_codec_destroy(&ctx); +} + #if CONFIG_VP9_HIGHBITDEPTH TEST(EncodeAPI, Buganizer329674887RowMT0BitDepth12) { VP9Encoder encoder(8, 0, VPX_BITS_12, VPX_IMG_FMT_I444); encoder.Configure(/*threads=*/2, /*width=*/1030, /*height=*/583, VPX_VBR, VPX_DL_REALTIME); @@ -1920,8 +2254,30 @@ // Free resources. vpx_img_free(image); ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); } +TEST(EncodeAPI, PerFramePsnrNotSupportedWithLagInFrames) { + vpx_codec_iface_t *const iface = vpx_codec_vp9_cx(); + vpx_codec_enc_cfg_t cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK); + ASSERT_NE(cfg.g_lag_in_frames, 0u); + + vpx_codec_ctx_t enc; + ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK); + + vpx_image_t *const image = + CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h); + ASSERT_NE(image, nullptr); + + vpx_enc_frame_flags_t psnr_flags = VPX_EFLAG_CALCULATE_PSNR; + ASSERT_EQ(vpx_codec_encode(&enc, image, /*pts=*/0, /*duration=*/1, psnr_flags, + VPX_DL_REALTIME), + VPX_CODEC_INCAPABLE); + + // Free resources. + vpx_img_free(image); + ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); +} #endif // CONFIG_VP9_ENCODER } // namespace diff --git a/media/libvpx/libvpx/test/fdct8x8_test.cc b/media/libvpx/libvpx/test/fdct8x8_test.cc --- a/media/libvpx/libvpx/test/fdct8x8_test.cc +++ b/media/libvpx/libvpx/test/fdct8x8_test.cc @@ -36,20 +36,20 @@ const double kPi = 3.141592653589793238462643383279502884; const int kSignBiasMaxDiff255 = 1500; const int kSignBiasMaxDiff15 = 10000; -typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); -typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); -typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, - int tx_type); -typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, - int tx_type); +using FdctFunc = void (*)(const int16_t *in, tran_low_t *out, int stride); +using IdctFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride); +using FhtFunc = void (*)(const int16_t *in, tran_low_t *out, int stride, + int tx_type); +using IhtFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride, + int tx_type); -typedef std::tuple Dct8x8Param; -typedef std::tuple Ht8x8Param; -typedef std::tuple Idct8x8Param; +using Dct8x8Param = std::tuple; +using Ht8x8Param = std::tuple; +using Idct8x8Param = std::tuple; void reference_8x8_dct_1d(const double in[8], double out[8]) { const double kInvSqrt2 = 0.707106781186547524400844362104; for (int k = 0; k < 8; k++) { out[k] = 0.0; diff --git a/media/libvpx/libvpx/test/hadamard_test.cc b/media/libvpx/libvpx/test/hadamard_test.cc --- a/media/libvpx/libvpx/test/hadamard_test.cc +++ b/media/libvpx/libvpx/test/hadamard_test.cc @@ -21,12 +21,12 @@ namespace { using ::libvpx_test::ACMRandom; -typedef void (*HadamardFunc)(const int16_t *a, ptrdiff_t a_stride, - tran_low_t *b); +using HadamardFunc = void (*)(const int16_t *a, ptrdiff_t a_stride, + tran_low_t *b); void hadamard_loop(const tran_low_t *a, tran_low_t *out) { tran_low_t b[8]; for (int i = 0; i < 8; i += 2) { b[i + 0] = a[i * 8] + a[(i + 1) * 8]; diff --git a/media/libvpx/libvpx/test/idct_test.cc b/media/libvpx/libvpx/test/idct_test.cc --- a/media/libvpx/libvpx/test/idct_test.cc +++ b/media/libvpx/libvpx/test/idct_test.cc @@ -16,13 +16,13 @@ #include "test/buffer.h" #include "test/clear_system_state.h" #include "test/register_state_check.h" #include "vpx/vpx_integer.h" -typedef void (*IdctFunc)(int16_t *input, unsigned char *pred_ptr, - int pred_stride, unsigned char *dst_ptr, - int dst_stride); +using IdctFunc = void (*)(int16_t *input, unsigned char *pred_ptr, + int pred_stride, unsigned char *dst_ptr, + int dst_stride); namespace { using libvpx_test::Buffer; class IDCTTest : public ::testing::TestWithParam { diff --git a/media/libvpx/libvpx/test/lpf_test.cc b/media/libvpx/libvpx/test/lpf_test.cc --- a/media/libvpx/libvpx/test/lpf_test.cc +++ b/media/libvpx/libvpx/test/lpf_test.cc @@ -34,33 +34,33 @@ const int kNumCoeffs = 1024; const int number_of_iterations = 10000; #if CONFIG_VP9_HIGHBITDEPTH -typedef uint16_t Pixel; +using Pixel = uint16_t; #define PIXEL_WIDTH 16 -typedef void (*loop_op_t)(Pixel *s, int p, const uint8_t *blimit, - const uint8_t *limit, const uint8_t *thresh, int bd); -typedef void (*dual_loop_op_t)(Pixel *s, int p, const uint8_t *blimit0, - const uint8_t *limit0, const uint8_t *thresh0, - const uint8_t *blimit1, const uint8_t *limit1, - const uint8_t *thresh1, int bd); +using loop_op_t = void (*)(Pixel *s, int p, const uint8_t *blimit, + const uint8_t *limit, const uint8_t *thresh, int bd); +using dual_loop_op_t = void (*)(Pixel *s, int p, const uint8_t *blimit0, + const uint8_t *limit0, const uint8_t *thresh0, + const uint8_t *blimit1, const uint8_t *limit1, + const uint8_t *thresh1, int bd); #else -typedef uint8_t Pixel; +using Pixel = uint8_t; #define PIXEL_WIDTH 8 -typedef void (*loop_op_t)(Pixel *s, int p, const uint8_t *blimit, - const uint8_t *limit, const uint8_t *thresh); -typedef void (*dual_loop_op_t)(Pixel *s, int p, const uint8_t *blimit0, - const uint8_t *limit0, const uint8_t *thresh0, - const uint8_t *blimit1, const uint8_t *limit1, - const uint8_t *thresh1); +using loop_op_t = void (*)(Pixel *s, int p, const uint8_t *blimit, + const uint8_t *limit, const uint8_t *thresh); +using dual_loop_op_t = void (*)(Pixel *s, int p, const uint8_t *blimit0, + const uint8_t *limit0, const uint8_t *thresh0, + const uint8_t *blimit1, const uint8_t *limit1, + const uint8_t *thresh1); #endif // CONFIG_VP9_HIGHBITDEPTH -typedef std::tuple loop8_param_t; -typedef std::tuple dualloop8_param_t; +using loop8_param_t = std::tuple; +using dualloop8_param_t = std::tuple; void InitInput(Pixel *s, Pixel *ref_s, ACMRandom *rnd, const uint8_t limit, const int mask, const int32_t p, const int i) { uint16_t tmp_s[kNumCoeffs]; diff --git a/media/libvpx/libvpx/test/minmax_test.cc b/media/libvpx/libvpx/test/minmax_test.cc --- a/media/libvpx/libvpx/test/minmax_test.cc +++ b/media/libvpx/libvpx/test/minmax_test.cc @@ -23,12 +23,12 @@ namespace { using ::libvpx_test::ACMRandom; -typedef void (*MinMaxFunc)(const uint8_t *a, int a_stride, const uint8_t *b, - int b_stride, int *min, int *max); +using MinMaxFunc = void (*)(const uint8_t *a, int a_stride, const uint8_t *b, + int b_stride, int *min, int *max); class MinMaxTest : public ::testing::TestWithParam { public: void SetUp() override { mm_func_ = GetParam(); diff --git a/media/libvpx/libvpx/test/partial_idct_test.cc b/media/libvpx/libvpx/test/partial_idct_test.cc --- a/media/libvpx/libvpx/test/partial_idct_test.cc +++ b/media/libvpx/libvpx/test/partial_idct_test.cc @@ -30,33 +30,34 @@ using libvpx_test::ACMRandom; namespace { -typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride); -typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride); -typedef void (*InvTxfmWithBdFunc)(const tran_low_t *in, uint8_t *out, - int stride, int bd); +using FwdTxfmFunc = void (*)(const int16_t *in, tran_low_t *out, int stride); +using InvTxfmFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride); +using InvTxfmWithBdFunc = void (*)(const tran_low_t *in, uint8_t *out, + int stride, int bd); template void wrapper(const tran_low_t *in, uint8_t *out, int stride, int bd) { (void)bd; fn(in, out, stride); } #if CONFIG_VP9_HIGHBITDEPTH -typedef void (*InvTxfmHighbdFunc)(const tran_low_t *in, uint16_t *out, - int stride, int bd); +using InvTxfmHighbdFunc = void (*)(const tran_low_t *in, uint16_t *out, + int stride, int bd); + template void highbd_wrapper(const tran_low_t *in, uint8_t *out, int stride, int bd) { fn(in, CAST_TO_SHORTPTR(out), stride, bd); } #endif -typedef std::tuple - PartialInvTxfmParam; +using PartialInvTxfmParam = + std::tuple; const int kMaxNumCoeffs = 1024; const int kCountTestBlock = 1000; class PartialIDctTest : public ::testing::TestWithParam { public: diff --git a/media/libvpx/libvpx/test/pp_filter_test.cc b/media/libvpx/libvpx/test/pp_filter_test.cc --- a/media/libvpx/libvpx/test/pp_filter_test.cc +++ b/media/libvpx/libvpx/test/pp_filter_test.cc @@ -24,19 +24,19 @@ #include "vpx_mem/vpx_mem.h" using libvpx_test::ACMRandom; using libvpx_test::Buffer; -typedef void (*VpxPostProcDownAndAcrossMbRowFunc)( +using VpxPostProcDownAndAcrossMbRowFunc = void (*)( unsigned char *src_ptr, unsigned char *dst_ptr, int src_pixels_per_line, int dst_pixels_per_line, int cols, unsigned char *flimit, int size); -typedef void (*VpxMbPostProcAcrossIpFunc)(unsigned char *src, int pitch, - int rows, int cols, int flimit); +using VpxMbPostProcAcrossIpFunc = void (*)(unsigned char *src, int pitch, + int rows, int cols, int flimit); -typedef void (*VpxMbPostProcDownFunc)(unsigned char *dst, int pitch, int rows, - int cols, int flimit); +using VpxMbPostProcDownFunc = void (*)(unsigned char *dst, int pitch, int rows, + int cols, int flimit); namespace { // Compute the filter level used in post proc from the loop filter strength int q2mbl(int x) { if (x < 20) x = 20; diff --git a/media/libvpx/libvpx/test/predict_test.cc b/media/libvpx/libvpx/test/predict_test.cc --- a/media/libvpx/libvpx/test/predict_test.cc +++ b/media/libvpx/libvpx/test/predict_test.cc @@ -28,15 +28,15 @@ namespace { using libvpx_test::ACMRandom; using std::make_tuple; -typedef void (*PredictFunc)(uint8_t *src_ptr, int src_pixels_per_line, - int xoffset, int yoffset, uint8_t *dst_ptr, - int dst_pitch); +using PredictFunc = void (*)(uint8_t *src_ptr, int src_pixels_per_line, + int xoffset, int yoffset, uint8_t *dst_ptr, + int dst_pitch); -typedef std::tuple PredictParam; +using PredictParam = std::tuple; class PredictTestBase : public AbstractBench, public ::testing::TestWithParam { public: PredictTestBase() diff --git a/media/libvpx/libvpx/test/quantize_test.cc b/media/libvpx/libvpx/test/quantize_test.cc --- a/media/libvpx/libvpx/test/quantize_test.cc +++ b/media/libvpx/libvpx/test/quantize_test.cc @@ -31,13 +31,13 @@ namespace { const int kNumBlocks = 25; const int kNumBlockEntries = 16; -typedef void (*VP8Quantize)(BLOCK *b, BLOCKD *d); +using VP8Quantize = void (*)(BLOCK *b, BLOCKD *d); -typedef std::tuple VP8QuantizeParam; +using VP8QuantizeParam = std::tuple; using libvpx_test::ACMRandom; using std::make_tuple; // Create and populate a VP8_COMP instance which has a complete set of @@ -69,20 +69,20 @@ vp8cx_frame_init_quantizer(vp8_comp_); // Copy macroblockd from the reference to get pre-set-up dequant values. macroblockd_dst_ = reinterpret_cast( vpx_memalign(32, sizeof(*macroblockd_dst_))); - memcpy(macroblockd_dst_, &vp8_comp_->mb.e_mbd, sizeof(*macroblockd_dst_)); + *macroblockd_dst_ = vp8_comp_->mb.e_mbd; // Fix block pointers - currently they point to the blocks in the reference // structure. vp8_setup_block_dptrs(macroblockd_dst_); } void UpdateQuantizer(int q) { vp8_set_quantizer(vp8_comp_, q); - memcpy(macroblockd_dst_, &vp8_comp_->mb.e_mbd, sizeof(*macroblockd_dst_)); + *macroblockd_dst_ = vp8_comp_->mb.e_mbd; vp8_setup_block_dptrs(macroblockd_dst_); } void FillCoeffConstant(int16_t c) { for (int i = 0; i < kNumBlocks * kNumBlockEntries; ++i) { diff --git a/media/libvpx/libvpx/test/resize_test.cc b/media/libvpx/libvpx/test/resize_test.cc --- a/media/libvpx/libvpx/test/resize_test.cc +++ b/media/libvpx/libvpx/test/resize_test.cc @@ -91,15 +91,24 @@ }; void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w, unsigned int initial_h, unsigned int *w, unsigned int *h, bool flag_codec, - bool smaller_width_larger_size_) { + bool smaller_width_larger_size, + bool random_input_one_half_only) { *w = initial_w; *h = initial_h; - if (smaller_width_larger_size_) { + if (random_input_one_half_only == 1) { + if (frame < 100) { + return; + } + *w = initial_w / 2; + *h = initial_h / 2; + return; + } + if (smaller_width_larger_size) { if (frame < 30) { return; } *w = initial_w * 7 / 10; *h = initial_h * 16 / 10; @@ -234,29 +243,49 @@ } } class ResizingVideoSource : public ::libvpx_test::DummyVideoSource { public: - ResizingVideoSource() { - SetSize(kInitialWidth, kInitialHeight); + ResizingVideoSource(int width, int height) + : smaller_width_larger_size_(false), random_input_one_half_only_(false), + configured_width_(width), configured_height_(height) { limit_ = 350; - smaller_width_larger_size_ = false; + SetSize(configured_width_, configured_height_); } bool flag_codec_; bool smaller_width_larger_size_; + bool random_input_one_half_only_; + // configured_width_/height_ is the configured resolution when codec is + // created. + int configured_width_; + int configured_height_; ~ResizingVideoSource() override = default; protected: void Next() override { ++frame_; unsigned int width = 0; unsigned int height = 0; - ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height, - flag_codec_, smaller_width_larger_size_); + ScaleForFrameNumber(frame_, configured_width_, configured_height_, &width, + &height, flag_codec_, smaller_width_larger_size_, + random_input_one_half_only_); SetSize(width, height); FillFrame(); } + + void FillFrame() override { + if (img_) { + memset(img_->img_data, 0, raw_sz_); + if (random_input_one_half_only_) { + libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); + unsigned char *image = img_->planes[0]; + for (size_t i = 0; i < raw_sz_; ++i) { + image[i] = rnd.Rand8(); + } + } + } + } }; class ResizeTest : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { @@ -294,30 +323,30 @@ std::vector encode_frame_width_; std::vector encode_frame_height_; }; TEST_P(ResizeTest, TestExternalResizeWorks) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = false; video.smaller_width_larger_size_ = false; cfg_.g_lag_in_frames = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; - const size_t idx = info - frame_info_list_.begin(); - ASSERT_EQ(info->w, GetFrameWidth(idx)); - ASSERT_EQ(info->h, GetFrameHeight(idx)); + const size_t idx = &info - &frame_info_list_[0]; + ASSERT_EQ(info.w, GetFrameWidth(idx)); + ASSERT_EQ(info.h, GetFrameHeight(idx)); ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; } } const unsigned int kStepDownFrame = 3; @@ -417,19 +446,18 @@ // frames to detect mismatch would then not be possible. Set // g_lag_in_frames = 0 to get around this. cfg_.g_lag_in_frames = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const vpx_codec_pts_t pts = info->pts; + for (const auto &info : frame_info_list_) { + const vpx_codec_pts_t pts = info.pts; if (pts >= kStepDownFrame && pts < kStepUpFrame) { - ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width"; - ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height"; + ASSERT_EQ(282U, info.w) << "Frame " << pts << " had unexpected width"; + ASSERT_EQ(173U, info.h) << "Frame " << pts << " had unexpected height"; } else { - EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width"; - EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height"; + EXPECT_EQ(352U, info.w) << "Frame " << pts << " had unexpected width"; + EXPECT_EQ(288U, info.h) << "Frame " << pts << " had unexpected height"; } } } TEST_P(ResizeInternalTest, TestInternalResizeChangeConfig) { @@ -451,10 +479,14 @@ void PreEncodeFrameHook(libvpx_test::VideoSource *video, libvpx_test::Encoder *encoder) override { if (video->frame() == 0) { encoder->Control(VP9E_SET_AQ_MODE, 3); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); + if (cfg_.g_threads > 0) { + encoder->Control(VP9E_SET_ROW_MT, 1); + encoder->Control(VP9E_SET_TILE_COLUMNS, cfg_.g_threads >> 1); + } } if (change_bitrate_ && video->frame() == 120) { change_bitrate_ = false; cfg_.rc_target_bitrate = 500; @@ -526,62 +558,95 @@ std::vector encode_frame_width_; std::vector encode_frame_height_; }; TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = true; video.smaller_width_larger_size_ = false; DefaultConfig(); // Disable internal resize for this test. cfg_.rc_resize_allowed = 0; change_bitrate_ = false; mismatch_psnr_ = 0.0; mismatch_nframes_ = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); + } +} + +// This test uses 4 threads with small keyframe spacing, random input, +// and uses 640x480 as initial resolution. +TEST_P(ResizeRealtimeTest, TestExternalResizeWorks4Threads) { + ResizingVideoSource video(640, 480); + video.flag_codec_ = true; + video.smaller_width_larger_size_ = false; + video.random_input_one_half_only_ = true; + DefaultConfig(); + // Disable internal resize for this test. + cfg_.rc_resize_allowed = 0; + cfg_.g_threads = 4; + cfg_.kf_max_dist = 50; + cfg_.kf_min_dist = 50; + change_bitrate_ = false; + mismatch_psnr_ = 0.0; + mismatch_nframes_ = 0; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); + unsigned int expected_w; + unsigned int expected_h; + ScaleForFrameNumber(frame, 640, 480, &expected_w, &expected_h, + video.flag_codec_, video.smaller_width_larger_size_, + video.random_input_one_half_only_); + EXPECT_EQ(expected_w, info.w) + << "Frame " << frame << " had unexpected width"; + EXPECT_EQ(expected_h, info.h) + << "Frame " << frame << " had unexpected height"; + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); } } TEST_P(ResizeRealtimeTest, TestExternalResizeSmallerWidthBiggerSize) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = true; video.smaller_width_larger_size_ = true; DefaultConfig(); // Disable internal resize for this test. cfg_.rc_resize_allowed = 0; change_bitrate_ = false; mismatch_psnr_ = 0.0; mismatch_nframes_ = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); } } // Verify the dynamic resizer behavior for real time, 1 pass CBR mode. // Run at low bitrate, with resize_allowed = 1, and verify that we get @@ -599,25 +664,24 @@ #if CONFIG_VP9_DECODER unsigned int last_w = cfg_.g_w; unsigned int last_h = cfg_.g_h; int resize_count = 0; - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - if (info->w != last_w || info->h != last_h) { + for (const auto &info : frame_info_list_) { + if (info.w != last_w || info.h != last_h) { // Verify that resize down occurs. - ASSERT_LT(info->w, last_w); - ASSERT_LT(info->h, last_h); - last_w = info->w; - last_h = info->h; + ASSERT_LT(info.w, last_w); + ASSERT_LT(info.h, last_h); + last_w = info.w; + last_h = info.h; resize_count++; } } // Verify that we get 1 resize down event in this test. ASSERT_EQ(1, resize_count) << "Resizing should occur."; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); #else GTEST_SKIP() << "Warning: VP9 decoder unavailable, unable to check resize count!\n"; #endif } @@ -641,35 +705,34 @@ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); unsigned int last_w = cfg_.g_w; unsigned int last_h = cfg_.g_h; int resize_count = 0; - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const size_t idx = info - frame_info_list_.begin(); - ASSERT_EQ(info->w, GetFrameWidth(idx)); - ASSERT_EQ(info->h, GetFrameHeight(idx)); - if (info->w != last_w || info->h != last_h) { + for (const auto &info : frame_info_list_) { + const size_t idx = &info - &frame_info_list_[0]; + ASSERT_EQ(info.w, GetFrameWidth(idx)); + ASSERT_EQ(info.h, GetFrameHeight(idx)); + if (info.w != last_w || info.h != last_h) { resize_count++; if (resize_count <= 2) { // Verify that resize down occurs. - ASSERT_LT(info->w, last_w); - ASSERT_LT(info->h, last_h); + ASSERT_LT(info.w, last_w); + ASSERT_LT(info.h, last_h); } else if (resize_count > 2) { // Verify that resize up occurs. - ASSERT_GT(info->w, last_w); - ASSERT_GT(info->h, last_h); + ASSERT_GT(info.w, last_w); + ASSERT_GT(info.h, last_h); } - last_w = info->w; - last_h = info->h; + last_w = info.w; + last_h = info.h; } } #if CONFIG_VP9_DECODER // Verify that we get 4 resize events in this test. ASSERT_EQ(resize_count, 4) << "Resizing should occur twice."; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); #else GTEST_SKIP() << "Warning: VP9 decoder unavailable, unable to check resize count!\n"; #endif } diff --git a/media/libvpx/libvpx/test/sad_test.cc b/media/libvpx/libvpx/test/sad_test.cc --- a/media/libvpx/libvpx/test/sad_test.cc +++ b/media/libvpx/libvpx/test/sad_test.cc @@ -36,36 +36,36 @@ : width(w), height(h), bit_depth(bd), func(f) {} int width, height, bit_depth; Function func; }; -typedef unsigned int (*SadMxNFunc)(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_ptr, int ref_stride); -typedef TestParams SadMxNParam; +using SadMxNFunc = unsigned int (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr, int ref_stride); +using SadMxNParam = TestParams; -typedef unsigned int (*SadSkipMxNFunc)(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_ptr, int ref_stride); -typedef TestParams SadSkipMxNParam; +using SadSkipMxNFunc = unsigned int (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr, int ref_stride); +using SadSkipMxNParam = TestParams; -typedef unsigned int (*SadMxNAvgFunc)(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_ptr, int ref_stride, - const uint8_t *second_pred); -typedef TestParams SadMxNAvgParam; +using SadMxNAvgFunc = unsigned int (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr, int ref_stride, + const uint8_t *second_pred); +using SadMxNAvgParam = TestParams; -typedef void (*SadMxNx4Func)(const uint8_t *src_ptr, int src_stride, - const uint8_t *const ref_ptr[], int ref_stride, - unsigned int *sad_array); -typedef TestParams SadMxNx4Param; +using SadMxNx4Func = void (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *const ref_ptr[], int ref_stride, + unsigned int *sad_array); +using SadMxNx4Param = TestParams; -typedef void (*SadSkipMxNx4Func)(const uint8_t *src_ptr, int src_stride, - const uint8_t *const ref_ptr[], int ref_stride, - unsigned int *sad_array); -typedef TestParams SadSkipMxNx4Param; +using SadSkipMxNx4Func = void (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *const ref_ptr[], + int ref_stride, unsigned int *sad_array); +using SadSkipMxNx4Param = TestParams; -typedef void (*SadMxNx8Func)(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_ptr, int ref_stride, - unsigned int *sad_array); +using SadMxNx8Func = void (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr, int ref_stride, + unsigned int *sad_array); using libvpx_test::ACMRandom; namespace { template diff --git a/media/libvpx/libvpx/test/simple_encode_test.cc b/media/libvpx/libvpx/test/simple_encode_test.cc deleted file mode 100644 --- a/media/libvpx/libvpx/test/simple_encode_test.cc +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright (c) 2019 The WebM project authors. 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 -#include -#include -#include "gtest/gtest.h" -#include "test/video_source.h" -#include "vp9/simple_encode.h" - -namespace vp9 { -namespace { - -double GetBitrateInKbps(size_t bit_size, int num_frames, int frame_rate_num, - int frame_rate_den) { - return static_cast(bit_size) / num_frames * frame_rate_num / - frame_rate_den / 1000.0; -} - -// Returns the number of unit in size of 4. -// For example, if size is 7, return 2. -int GetNumUnit4x4(int size) { return (size + 3) >> 2; } - -class SimpleEncodeTest : public ::testing::Test { - protected: - const int width_ = 352; - const int height_ = 288; - const int frame_rate_num_ = 30; - const int frame_rate_den_ = 1; - const int target_bitrate_ = 1000; - const int num_frames_ = 17; - const int target_level_ = LEVEL_UNKNOWN; - const std::string in_file_path_str_ = - libvpx_test::GetDataPath() + "/bus_352x288_420_f20_b8.yuv"; -}; - -TEST_F(SimpleEncodeTest, ComputeFirstPassStats) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - std::vector> frame_stats = - simple_encode.ObserveFirstPassStats(); - EXPECT_EQ(frame_stats.size(), static_cast(num_frames_)); - const size_t data_num = frame_stats[0].size(); - // Read ObserveFirstPassStats before changing FIRSTPASS_STATS. - EXPECT_EQ(data_num, static_cast(25)); - for (size_t i = 0; i < frame_stats.size(); ++i) { - EXPECT_EQ(frame_stats[i].size(), data_num); - // FIRSTPASS_STATS's first element is frame - EXPECT_EQ(frame_stats[i][0], i); - // FIRSTPASS_STATS's last element is count, and the count is 1 for single - // frame stats - EXPECT_EQ(frame_stats[i][data_num - 1], 1); - } -} - -TEST_F(SimpleEncodeTest, ObserveFirstPassMotionVectors) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - std::vector> fps_motion_vectors = - simple_encode.ObserveFirstPassMotionVectors(); - EXPECT_EQ(fps_motion_vectors.size(), static_cast(num_frames_)); - const size_t num_blocks = ((width_ + 15) >> 4) * ((height_ + 15) >> 4); - EXPECT_EQ(num_blocks, fps_motion_vectors[0].size()); - for (size_t i = 0; i < fps_motion_vectors.size(); ++i) { - EXPECT_EQ(num_blocks, fps_motion_vectors[i].size()); - for (size_t j = 0; j < num_blocks; ++j) { - const int mv_count = fps_motion_vectors[i][j].mv_count; - const int ref_count = - (fps_motion_vectors[i][j].ref_frame[0] != kRefFrameTypeNone) + - (fps_motion_vectors[i][j].ref_frame[1] != kRefFrameTypeNone); - EXPECT_EQ(mv_count, ref_count); - } - } -} - -TEST_F(SimpleEncodeTest, GetCodingFrameNum) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - EXPECT_EQ(num_coding_frames, 19); -} - -TEST_F(SimpleEncodeTest, EncodeFrame) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - int num_coding_frames = simple_encode.GetCodingFrameNum(); - EXPECT_GE(num_coding_frames, num_frames_); - simple_encode.StartEncode(); - size_t total_data_bit_size = 0; - int coded_show_frame_count = 0; - int frame_coding_index = 0; - while (coded_show_frame_count < num_frames_) { - const GroupOfPicture group_of_picture = - simple_encode.ObserveGroupOfPicture(); - const std::vector &encode_frame_list = - group_of_picture.encode_frame_list; - for (size_t group_index = 0; group_index < encode_frame_list.size(); - ++group_index) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - EXPECT_EQ(encode_frame_result.show_idx, - encode_frame_list[group_index].show_idx); - EXPECT_EQ(encode_frame_result.frame_type, - encode_frame_list[group_index].frame_type); - EXPECT_EQ(encode_frame_list[group_index].coding_index, - frame_coding_index); - EXPECT_GE(encode_frame_result.psnr, 34) - << "The psnr is supposed to be greater than 34 given the " - "target_bitrate 1000 kbps"; - EXPECT_EQ(encode_frame_result.ref_frame_info, - encode_frame_list[group_index].ref_frame_info); - total_data_bit_size += encode_frame_result.coding_data_bit_size; - ++frame_coding_index; - } - coded_show_frame_count += group_of_picture.show_frame_count; - } - const double bitrate = GetBitrateInKbps(total_data_bit_size, num_frames_, - frame_rate_num_, frame_rate_den_); - const double off_target_threshold = 150; - EXPECT_LE(fabs(target_bitrate_ - bitrate), off_target_threshold); - simple_encode.EndEncode(); -} - -TEST_F(SimpleEncodeTest, ObserveKeyFrameMap) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - std::vector key_frame_map = simple_encode.ObserveKeyFrameMap(); - EXPECT_EQ(key_frame_map.size(), static_cast(num_frames_)); - simple_encode.StartEncode(); - int coded_show_frame_count = 0; - while (coded_show_frame_count < num_frames_) { - const GroupOfPicture group_of_picture = - simple_encode.ObserveGroupOfPicture(); - const std::vector &encode_frame_list = - group_of_picture.encode_frame_list; - for (size_t group_index = 0; group_index < encode_frame_list.size(); - ++group_index) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - if (encode_frame_result.frame_type == kFrameTypeKey) { - EXPECT_EQ(key_frame_map[encode_frame_result.show_idx], 1); - } else { - EXPECT_EQ(key_frame_map[encode_frame_result.show_idx], 0); - } - } - coded_show_frame_count += group_of_picture.show_frame_count; - } - simple_encode.EndEncode(); -} - -TEST_F(SimpleEncodeTest, EncodeFrameWithTargetFrameBits) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameInfo encode_frame_info = simple_encode.GetNextEncodeFrameInfo(); - int target_frame_bits; - switch (encode_frame_info.frame_type) { - case kFrameTypeInter: target_frame_bits = 20000; break; - case kFrameTypeKey: - case kFrameTypeAltRef: - case kFrameTypeGolden: target_frame_bits = 100000; break; - case kFrameTypeOverlay: target_frame_bits = 2000; break; - default: target_frame_bits = 20000; - } - - double percent_diff = 15; - if (encode_frame_info.frame_type == kFrameTypeOverlay) { - percent_diff = 100; - } - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrameWithTargetFrameBits( - &encode_frame_result, target_frame_bits, percent_diff); - const int recode_count = encode_frame_result.recode_count; - // TODO(angiebird): Replace 7 by RATE_CTRL_MAX_RECODE_NUM - EXPECT_LE(recode_count, 7); - EXPECT_GE(recode_count, 1); - - const double diff = fabs((double)encode_frame_result.coding_data_bit_size - - target_frame_bits); - EXPECT_LE(diff * 100 / target_frame_bits, percent_diff); - } - simple_encode.EndEncode(); -} - -TEST_F(SimpleEncodeTest, EncodeFrameWithQuantizeIndex) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - const int assigned_quantize_index = 100 + i; - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrameWithQuantizeIndex(&encode_frame_result, - assigned_quantize_index); - EXPECT_EQ(encode_frame_result.quantize_index, assigned_quantize_index); - } - simple_encode.EndEncode(); -} - -// This test encodes the video using EncodeFrame(), where quantize indexes -// are selected by vp9 rate control. -// Encode stats and the quantize_indexes are collected. -// Then the test encodes the video again using EncodeFrameWithQuantizeIndex() -// using the quantize indexes collected from the first run. -// Then test whether the encode stats of the two encoding runs match. -TEST_F(SimpleEncodeTest, EncodeConsistencyTest) { - std::vector quantize_index_list; - std::vector ref_sse_list; - std::vector ref_psnr_list; - std::vector ref_bit_size_list; - std::vector ref_frame_type_list; - std::vector ref_show_idx_list; - { - // The first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - quantize_index_list.push_back(encode_frame_result.quantize_index); - ref_sse_list.push_back(encode_frame_result.sse); - ref_psnr_list.push_back(encode_frame_result.psnr); - ref_bit_size_list.push_back(encode_frame_result.coding_data_bit_size); - ref_frame_type_list.push_back(encode_frame_result.frame_type); - ref_show_idx_list.push_back(encode_frame_result.show_idx); - } - simple_encode.EndEncode(); - } - { - // The second encode with quantize index got from the first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - EXPECT_EQ(static_cast(num_coding_frames), - quantize_index_list.size()); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrameWithQuantizeIndex(&encode_frame_result, - quantize_index_list[i]); - EXPECT_EQ(encode_frame_result.quantize_index, quantize_index_list[i]); - EXPECT_EQ(encode_frame_result.sse, ref_sse_list[i]); - EXPECT_DOUBLE_EQ(encode_frame_result.psnr, ref_psnr_list[i]); - EXPECT_EQ(encode_frame_result.coding_data_bit_size, ref_bit_size_list[i]); - EXPECT_EQ(encode_frame_result.frame_type, ref_frame_type_list[i]); - EXPECT_EQ(encode_frame_result.show_idx, ref_show_idx_list[i]); - } - simple_encode.EndEncode(); - } -} - -// Test the information (partition info and motion vector info) stored in -// encoder is the same between two encode runs. -TEST_F(SimpleEncodeTest, EncodeConsistencyTest2) { - const int num_rows_4x4 = GetNumUnit4x4(width_); - const int num_cols_4x4 = GetNumUnit4x4(height_); - const int num_units_4x4 = num_rows_4x4 * num_cols_4x4; - // The first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - std::vector partition_info_list(num_units_4x4 * - num_coding_frames); - std::vector motion_vector_info_list(num_units_4x4 * - num_coding_frames); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) { - partition_info_list[i * num_units_4x4 + j] = - encode_frame_result.partition_info[j]; - motion_vector_info_list[i * num_units_4x4 + j] = - encode_frame_result.motion_vector_info[j]; - } - } - simple_encode.EndEncode(); - // The second encode. - SimpleEncode simple_encode_2(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode_2.ComputeFirstPassStats(); - const int num_coding_frames_2 = simple_encode_2.GetCodingFrameNum(); - simple_encode_2.StartEncode(); - for (int i = 0; i < num_coding_frames_2; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode_2.EncodeFrame(&encode_frame_result); - for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) { - EXPECT_EQ(encode_frame_result.partition_info[j].row, - partition_info_list[i * num_units_4x4 + j].row); - EXPECT_EQ(encode_frame_result.partition_info[j].column, - partition_info_list[i * num_units_4x4 + j].column); - EXPECT_EQ(encode_frame_result.partition_info[j].row_start, - partition_info_list[i * num_units_4x4 + j].row_start); - EXPECT_EQ(encode_frame_result.partition_info[j].column_start, - partition_info_list[i * num_units_4x4 + j].column_start); - EXPECT_EQ(encode_frame_result.partition_info[j].width, - partition_info_list[i * num_units_4x4 + j].width); - EXPECT_EQ(encode_frame_result.partition_info[j].height, - partition_info_list[i * num_units_4x4 + j].height); - - EXPECT_EQ(encode_frame_result.motion_vector_info[j].mv_count, - motion_vector_info_list[i * num_units_4x4 + j].mv_count); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].ref_frame[0], - motion_vector_info_list[i * num_units_4x4 + j].ref_frame[0]); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].ref_frame[1], - motion_vector_info_list[i * num_units_4x4 + j].ref_frame[1]); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].mv_row[0], - motion_vector_info_list[i * num_units_4x4 + j].mv_row[0]); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].mv_column[0], - motion_vector_info_list[i * num_units_4x4 + j].mv_column[0]); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].mv_row[1], - motion_vector_info_list[i * num_units_4x4 + j].mv_row[1]); - EXPECT_EQ(encode_frame_result.motion_vector_info[j].mv_column[1], - motion_vector_info_list[i * num_units_4x4 + j].mv_column[1]); - } - } - simple_encode_2.EndEncode(); -} - -// Test the information stored in encoder is the same between two encode runs. -TEST_F(SimpleEncodeTest, EncodeConsistencyTest3) { - std::vector quantize_index_list; - const int num_rows_4x4 = GetNumUnit4x4(width_); - const int num_cols_4x4 = GetNumUnit4x4(height_); - const int num_units_4x4 = num_rows_4x4 * num_cols_4x4; - // The first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - std::vector partition_info_list(num_units_4x4 * - num_coding_frames); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - quantize_index_list.push_back(encode_frame_result.quantize_index); - for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) { - partition_info_list[i * num_units_4x4 + j] = - encode_frame_result.partition_info[j]; - } - } - simple_encode.EndEncode(); - // The second encode. - SimpleEncode simple_encode_2(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode_2.ComputeFirstPassStats(); - const int num_coding_frames_2 = simple_encode_2.GetCodingFrameNum(); - simple_encode_2.StartEncode(); - for (int i = 0; i < num_coding_frames_2; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode_2.EncodeFrameWithQuantizeIndex(&encode_frame_result, - quantize_index_list[i]); - for (int j = 0; j < num_rows_4x4 * num_cols_4x4; ++j) { - EXPECT_EQ(encode_frame_result.partition_info[j].row, - partition_info_list[i * num_units_4x4 + j].row); - EXPECT_EQ(encode_frame_result.partition_info[j].column, - partition_info_list[i * num_units_4x4 + j].column); - EXPECT_EQ(encode_frame_result.partition_info[j].row_start, - partition_info_list[i * num_units_4x4 + j].row_start); - EXPECT_EQ(encode_frame_result.partition_info[j].column_start, - partition_info_list[i * num_units_4x4 + j].column_start); - EXPECT_EQ(encode_frame_result.partition_info[j].width, - partition_info_list[i * num_units_4x4 + j].width); - EXPECT_EQ(encode_frame_result.partition_info[j].height, - partition_info_list[i * num_units_4x4 + j].height); - } - } - simple_encode_2.EndEncode(); -} - -// Encode with default VP9 decision first. -// Get QPs and arf locations from the first encode. -// Set external arfs and QPs for the second encode. -// Expect to get matched results. -TEST_F(SimpleEncodeTest, EncodeConsistencySetExternalGroupOfPicturesMap) { - std::vector quantize_index_list; - std::vector ref_sse_list; - std::vector ref_psnr_list; - std::vector ref_bit_size_list; - std::vector gop_map(num_frames_, 0); - { - // The first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - simple_encode.StartEncode(); - - int coded_show_frame_count = 0; - while (coded_show_frame_count < num_frames_) { - const GroupOfPicture group_of_picture = - simple_encode.ObserveGroupOfPicture(); - gop_map[coded_show_frame_count] |= kGopMapFlagStart; - if (group_of_picture.use_alt_ref) { - gop_map[coded_show_frame_count] |= kGopMapFlagUseAltRef; - } - const std::vector &encode_frame_list = - group_of_picture.encode_frame_list; - for (size_t group_index = 0; group_index < encode_frame_list.size(); - ++group_index) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - quantize_index_list.push_back(encode_frame_result.quantize_index); - ref_sse_list.push_back(encode_frame_result.sse); - ref_psnr_list.push_back(encode_frame_result.psnr); - ref_bit_size_list.push_back(encode_frame_result.coding_data_bit_size); - } - coded_show_frame_count += group_of_picture.show_frame_count; - } - simple_encode.EndEncode(); - } - { - // The second encode with quantize index got from the first encode. - // The external arfs are the same as the first encode. - SimpleEncode simple_encode(width_, height_, frame_rate_num_, - frame_rate_den_, target_bitrate_, num_frames_, - target_level_, in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - simple_encode.SetExternalGroupOfPicturesMap(gop_map.data(), gop_map.size()); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - EXPECT_EQ(static_cast(num_coding_frames), - quantize_index_list.size()); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrameWithQuantizeIndex(&encode_frame_result, - quantize_index_list[i]); - EXPECT_EQ(encode_frame_result.quantize_index, quantize_index_list[i]); - EXPECT_EQ(encode_frame_result.sse, ref_sse_list[i]); - EXPECT_DOUBLE_EQ(encode_frame_result.psnr, ref_psnr_list[i]); - EXPECT_EQ(encode_frame_result.coding_data_bit_size, ref_bit_size_list[i]); - } - simple_encode.EndEncode(); - } -} - -TEST_F(SimpleEncodeTest, SetExternalGroupOfPicturesMap) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - - std::vector gop_map(num_frames_, 0); - - // Should be the first gop group. - gop_map[0] = 0; - - // Second gop group with an alt ref. - gop_map[5] |= kGopMapFlagStart | kGopMapFlagUseAltRef; - - // Third gop group without an alt ref. - gop_map[10] |= kGopMapFlagStart; - - // Last gop group. - gop_map[14] |= kGopMapFlagStart | kGopMapFlagUseAltRef; - - simple_encode.SetExternalGroupOfPicturesMap(gop_map.data(), gop_map.size()); - - std::vector observed_gop_map = - simple_encode.ObserveExternalGroupOfPicturesMap(); - - // First gop group. - // There is always a key frame at show_idx 0 and key frame should always be - // the start of a gop. We expect ObserveExternalGroupOfPicturesMap() will - // insert an extra gop start here. - EXPECT_EQ(observed_gop_map[0], kGopMapFlagStart | kGopMapFlagUseAltRef); - - // Second gop group with an alt ref. - EXPECT_EQ(observed_gop_map[5], kGopMapFlagStart | kGopMapFlagUseAltRef); - - // Third gop group without an alt ref. - EXPECT_EQ(observed_gop_map[10], kGopMapFlagStart); - - // Last gop group. The last gop is not supposed to use an alt ref. We expect - // ObserveExternalGroupOfPicturesMap() will remove the alt ref flag here. - EXPECT_EQ(observed_gop_map[14], kGopMapFlagStart); - - int ref_gop_show_frame_count_list[4] = { 5, 5, 4, 3 }; - size_t ref_gop_coded_frame_count_list[4] = { 6, 6, 4, 3 }; - int gop_count = 0; - - simple_encode.StartEncode(); - int coded_show_frame_count = 0; - while (coded_show_frame_count < num_frames_) { - const GroupOfPicture group_of_picture = - simple_encode.ObserveGroupOfPicture(); - const std::vector &encode_frame_list = - group_of_picture.encode_frame_list; - EXPECT_EQ(encode_frame_list.size(), - ref_gop_coded_frame_count_list[gop_count]); - EXPECT_EQ(group_of_picture.show_frame_count, - ref_gop_show_frame_count_list[gop_count]); - for (size_t group_index = 0; group_index < encode_frame_list.size(); - ++group_index) { - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - } - coded_show_frame_count += group_of_picture.show_frame_count; - ++gop_count; - } - EXPECT_EQ(gop_count, 4); - simple_encode.EndEncode(); -} - -TEST_F(SimpleEncodeTest, GetEncodeFrameInfo) { - // Makes sure that the encode_frame_info obtained from GetEncodeFrameInfo() - // matches the counterpart in encode_frame_result obtained from EncodeFrame() - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - simple_encode.ComputeFirstPassStats(); - const int num_coding_frames = simple_encode.GetCodingFrameNum(); - simple_encode.StartEncode(); - for (int i = 0; i < num_coding_frames; ++i) { - EncodeFrameInfo encode_frame_info = simple_encode.GetNextEncodeFrameInfo(); - EncodeFrameResult encode_frame_result; - simple_encode.EncodeFrame(&encode_frame_result); - EXPECT_EQ(encode_frame_info.show_idx, encode_frame_result.show_idx); - EXPECT_EQ(encode_frame_info.frame_type, encode_frame_result.frame_type); - } - simple_encode.EndEncode(); -} - -TEST_F(SimpleEncodeTest, GetFramePixelCount) { - SimpleEncode simple_encode(width_, height_, frame_rate_num_, frame_rate_den_, - target_bitrate_, num_frames_, target_level_, - in_file_path_str_.c_str()); - EXPECT_EQ(simple_encode.GetFramePixelCount(), - static_cast(width_ * height_ * 3 / 2)); -} - -} // namespace -} // namespace vp9 - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/media/libvpx/libvpx/test/sum_squares_test.cc b/media/libvpx/libvpx/test/sum_squares_test.cc --- a/media/libvpx/libvpx/test/sum_squares_test.cc +++ b/media/libvpx/libvpx/test/sum_squares_test.cc @@ -32,12 +32,12 @@ using ::testing::ValuesIn; namespace { const int kNumIterations = 10000; -typedef uint64_t (*SSI16Func)(const int16_t *src, int stride, int size); -typedef std::tuple SumSquaresParam; +using SSI16Func = uint64_t (*)(const int16_t *src, int stride, int size); +using SumSquaresParam = std::tuple; class SumSquaresTest : public ::testing::TestWithParam { public: ~SumSquaresTest() override = default; void SetUp() override { @@ -138,22 +138,22 @@ MSA, SumSquaresTest, ::testing::Values(make_tuple(&vpx_sum_squares_2d_i16_c, &vpx_sum_squares_2d_i16_msa))); #endif // HAVE_MSA -typedef int64_t (*SSEFunc)(const uint8_t *a, int a_stride, const uint8_t *b, - int b_stride, int width, int height); +using SSEFunc = int64_t (*)(const uint8_t *a, int a_stride, const uint8_t *b, + int b_stride, int width, int height); struct TestSSEFuncs { TestSSEFuncs(SSEFunc ref = nullptr, SSEFunc tst = nullptr, int depth = 0) : ref_func(ref), tst_func(tst), bit_depth(depth) {} SSEFunc ref_func; // Pointer to reference function SSEFunc tst_func; // Pointer to tested function int bit_depth; }; -typedef std::tuple SSETestParam; +using SSETestParam = std::tuple; class SSETest : public ::testing::TestWithParam { public: ~SSETest() override = default; void SetUp() override { diff --git a/media/libvpx/libvpx/test/superframe_test.cc b/media/libvpx/libvpx/test/superframe_test.cc --- a/media/libvpx/libvpx/test/superframe_test.cc +++ b/media/libvpx/libvpx/test/superframe_test.cc @@ -18,11 +18,11 @@ namespace { const int kTestMode = 0; -typedef std::tuple SuperframeTestParam; +using SuperframeTestParam = std::tuple; class SuperframeTest : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { protected: diff --git a/media/libvpx/libvpx/test/svc_datarate_test.cc b/media/libvpx/libvpx/test/svc_datarate_test.cc --- a/media/libvpx/libvpx/test/svc_datarate_test.cc +++ b/media/libvpx/libvpx/test/svc_datarate_test.cc @@ -20,22 +20,22 @@ #include "vpx_ports/bitops.h" namespace svc_test { namespace { -typedef enum { +enum INTER_LAYER_PRED { // Inter-layer prediction is on on all frames. INTER_LAYER_PRED_ON, // Inter-layer prediction is off on all frames. INTER_LAYER_PRED_OFF, // Inter-layer prediction is off on non-key frames and non-sync frames. INTER_LAYER_PRED_OFF_NONKEY, // Inter-layer prediction is on on all frames, but constrained such // that any layer S (> 0) can only predict from previous spatial // layer S-1, from the same superframe. INTER_LAYER_PRED_ON_CONSTRAINED -} INTER_LAYER_PRED; +}; class DatarateOnePassCbrSvc : public OnePassCbrSvc { public: explicit DatarateOnePassCbrSvc(const ::libvpx_test::CodecFactory *codec) : OnePassCbrSvc(codec) { @@ -572,11 +572,14 @@ int num_layers_encoded = 0; last_pts_ = pkt->data.frame.pts; const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true : false; if (external_resize_dynamic_drop_layer_) { - ASSERT_FALSE(key_frame && superframe_cnt_ > 1); + // No key frames expected in stream, except for first. + if (cfg_.kf_max_dist > 1000) { + ASSERT_FALSE(key_frame && superframe_cnt_ > 1); + } } if (key_frame) { // For test that inserts layer sync frames: requesting a layer_sync on // the base layer must force key frame. So if any key frame occurs after // first superframe it must due to layer sync on base spatial layer. @@ -808,25 +811,29 @@ } } class ResizingVideoSource : public ::libvpx_test::DummyVideoSource { public: - ResizingVideoSource() { - SetSize(1280, 720); + ResizingVideoSource(int width, int height) { + top_width_ = width; + top_height_ = height; + SetSize(top_width_, top_height_); limit_ = 300; } int external_resize_pattern_ = 1; int force_zero_source_ = 0; + int top_width_; + int top_height_; ~ResizingVideoSource() override = default; protected: void Next() override { ++frame_; unsigned int width = 0; unsigned int height = 0; libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); - ScaleForFrameNumber(frame_, 1280, 720, &width, &height, + ScaleForFrameNumber(frame_, top_width_, top_height_, &width, &height, external_resize_pattern_); SetSize(width, height); FillFrame(); unsigned char *image = img_->planes[0]; for (size_t i = 0; i < raw_sz_; ++i) { @@ -1350,11 +1357,11 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); video.external_resize_pattern_ = 1; video.force_zero_source_ = 0; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; @@ -1391,11 +1398,53 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); + video.external_resize_pattern_ = 2; + video.force_zero_source_ = 0; + cfg_.rc_target_bitrate = 1000; + ResetModel(); + dynamic_drop_layer_ = false; + single_layer_resize_ = false; + denoiser_on_ = 1; + base_speed_setting_ = speed_setting_; + external_resize_dynamic_drop_layer_ = true; + external_resize_pattern_ = video.external_resize_pattern_; + AssignLayerBitrates(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + +// For 1 pass CBR SVC with 3 spatial and 3 temporal layers with external resize +// and denoiser enabled. The external resizer will resize down and back up, +// setting 0/nonzero bitrate on spatial enhancement layers to disable/enable +// layers. Resizing starts on first frame and the pattern is: +// 1/2 -> 1/4 -> 1 -> 1/2 -> 1/4. This test uses 4 threads with small keyframe +// spacing, and top resolution is 1280x960. +TEST_P(DatarateOnePassCbrSvcSingleBR, + OnePassCbrSvc3SL3TL_DenoiseExternalResizePattern2Key4Threads) { + SetSvcConfig(3, 3); + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_min_quantizer = 40; + cfg_.rc_max_quantizer = 63; + cfg_.g_threads = 4; + cfg_.temporal_layering_mode = 3; + cfg_.ts_rate_decimator[0] = 4; + cfg_.ts_rate_decimator[1] = 2; + cfg_.ts_rate_decimator[2] = 1; + cfg_.rc_dropframe_thresh = 1; + cfg_.kf_max_dist = 40; + cfg_.kf_min_dist = 40; + cfg_.rc_resize_allowed = 0; + cfg_.g_w = 1280; + cfg_.g_h = 960; + top_sl_width_ = cfg_.g_w; + top_sl_height_ = cfg_.g_h; + ResizingVideoSource video(1280, 960); video.external_resize_pattern_ = 2; video.force_zero_source_ = 0; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; @@ -1433,11 +1482,11 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); video.external_resize_pattern_ = 1; video.force_zero_source_ = 1; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; diff --git a/media/libvpx/libvpx/test/svc_end_to_end_test.cc b/media/libvpx/libvpx/test/svc_end_to_end_test.cc --- a/media/libvpx/libvpx/test/svc_end_to_end_test.cc +++ b/media/libvpx/libvpx/test/svc_end_to_end_test.cc @@ -20,22 +20,22 @@ #include "vpx_ports/bitops.h" namespace svc_test { namespace { -typedef enum { +enum INTER_LAYER_PRED { // Inter-layer prediction is on on all frames. INTER_LAYER_PRED_ON, // Inter-layer prediction is off on all frames. INTER_LAYER_PRED_OFF, // Inter-layer prediction is off on non-key frames and non-sync frames. INTER_LAYER_PRED_OFF_NONKEY, // Inter-layer prediction is on on all frames, but constrained such // that any layer S (> 0) can only predict from previous spatial // layer S-1, from the same superframe. INTER_LAYER_PRED_ON_CONSTRAINED -} INTER_LAYER_PRED; +}; class ScalePartitionOnePassCbrSvc : public OnePassCbrSvc, public ::testing::TestWithParam { public: diff --git a/media/libvpx/libvpx/test/test.mk b/media/libvpx/libvpx/test/test.mk --- a/media/libvpx/libvpx/test/test.mk +++ b/media/libvpx/libvpx/test/test.mk @@ -68,11 +68,10 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += timestamp_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_datarate_test.cc ifneq ($(CONFIG_REALTIME_ONLY),yes) LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_ext_ratectrl_test.cc endif -LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += ../vp9/simple_encode.h LIBVPX_TEST_SRCS-yes += decode_test_driver.cc LIBVPX_TEST_SRCS-yes += decode_test_driver.h LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += encode_test_driver.cc LIBVPX_TEST_SRCS-yes += encode_test_driver.h @@ -209,14 +208,10 @@ ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_TEMPORAL_DENOISING),yesyes) LIBVPX_TEST_SRCS-yes += vp9_denoiser_test.cc endif LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_arf_freq_test.cc -ifeq ($(CONFIG_VP9_ENCODER),yes) -SIMPLE_ENCODE_TEST_SRCS-$(CONFIG_RATE_CTRL) := simple_encode_test.cc -endif - endif # VP9 ## Multi-codec / unconditional whitebox tests. LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += sad_test.cc diff --git a/media/libvpx/libvpx/test/test_intra_pred_speed.cc b/media/libvpx/libvpx/test/test_intra_pred_speed.cc --- a/media/libvpx/libvpx/test/test_intra_pred_speed.cc +++ b/media/libvpx/libvpx/test/test_intra_pred_speed.cc @@ -26,12 +26,12 @@ // ----------------------------------------------------------------------------- namespace { -typedef void (*VpxPredFunc)(uint8_t *dst, ptrdiff_t y_stride, - const uint8_t *above, const uint8_t *left); +using VpxPredFunc = void (*)(uint8_t *dst, ptrdiff_t y_stride, + const uint8_t *above, const uint8_t *left); const int kBPS = 32; const int kTotalPixels = 32 * kBPS; const int kNumVp9IntraPredFuncs = 13; const char *kVp9IntraPredNames[kNumVp9IntraPredFuncs] = { @@ -61,11 +61,11 @@ DECLARE_ALIGNED(16, Pixel, ref_src[kTotalPixels]); DECLARE_ALIGNED(16, Pixel, left[kBPS]); DECLARE_ALIGNED(16, Pixel, above_mem[2 * kBPS + 16]); }; -typedef IntraPredTestMem Vp9IntraPredTestMem; +using Vp9IntraPredTestMem = IntraPredTestMem; void CheckMd5Signature(const char name[], const char *const signatures[], const void *data, size_t data_size, int elapsed_time, int idx) { libvpx_test::MD5 md5; @@ -362,15 +362,15 @@ // ----------------------------------------------------------------------------- #if CONFIG_VP9_HIGHBITDEPTH namespace { -typedef void (*VpxHighbdPredFunc)(uint16_t *dst, ptrdiff_t y_stride, - const uint16_t *above, const uint16_t *left, - int bd); +using VpxHighbdPredFunc = void (*)(uint16_t *dst, ptrdiff_t y_stride, + const uint16_t *above, const uint16_t *left, + int bd); -typedef IntraPredTestMem Vp9HighbdIntraPredTestMem; +using Vp9HighbdIntraPredTestMem = IntraPredTestMem; void TestHighbdIntraPred(const char name[], VpxHighbdPredFunc const *pred_funcs, const char *const signatures[], int block_size) { const int kNumTests = static_cast( 2.e10 / (block_size * block_size * kNumVp9IntraPredFuncs)); diff --git a/media/libvpx/libvpx/test/test_vector_test.cc b/media/libvpx/libvpx/test/test_vector_test.cc --- a/media/libvpx/libvpx/test/test_vector_test.cc +++ b/media/libvpx/libvpx/test/test_vector_test.cc @@ -33,11 +33,11 @@ const int kThreads = 0; const int kMtMode = 1; const int kFileName = 2; -typedef std::tuple DecodeParam; +using DecodeParam = std::tuple; class TestVectorTest : public ::libvpx_test::DecoderTest, public ::libvpx_test::CodecTestWithParam { protected: TestVectorTest() : DecoderTest(GET_PARAM(0)), md5_file_(nullptr) { diff --git a/media/libvpx/libvpx/test/variance_test.cc b/media/libvpx/libvpx/test/variance_test.cc --- a/media/libvpx/libvpx/test/variance_test.cc +++ b/media/libvpx/libvpx/test/variance_test.cc @@ -25,16 +25,16 @@ #include "vpx_ports/mem.h" #include "vpx_ports/vpx_timer.h" namespace { -typedef unsigned int (*Get4x4SseFunc)(const uint8_t *a, int a_stride, - const uint8_t *b, int b_stride); -typedef void (*GetVarianceFunc)(const uint8_t *src_ptr, int src_stride, - const uint8_t *ref_ptr, int ref_stride, - uint32_t *sse, int *sum); -typedef unsigned int (*SumOfSquaresFunction)(const int16_t *src); +using Get4x4SseFunc = unsigned int (*)(const uint8_t *a, int a_stride, + const uint8_t *b, int b_stride); +using GetVarianceFunc = void (*)(const uint8_t *src_ptr, int src_stride, + const uint8_t *ref_ptr, int ref_stride, + uint32_t *sse, int *sum); +using SumOfSquaresFunction = unsigned int (*)(const int16_t *src); using libvpx_test::ACMRandom; // Truncate high bit depth results by downshifting (with rounding) by: // 2 * (bit_depth - 8) for sse @@ -826,16 +826,16 @@ EXPECT_EQ(var1, var2) << "at position " << x << ", " << y; } } } -typedef MainTestClass VpxSseTest; -typedef MainTestClass VpxMseTest; -typedef MainTestClass VpxVarianceTest; -typedef MainTestClass VpxGetVarianceTest; -typedef SubpelVarianceTest VpxSubpelVarianceTest; -typedef SubpelVarianceTest VpxSubpelAvgVarianceTest; +using VpxSseTest = MainTestClass; +using VpxMseTest = MainTestClass; +using VpxVarianceTest = MainTestClass; +using VpxGetVarianceTest = MainTestClass; +using VpxSubpelVarianceTest = SubpelVarianceTest; +using VpxSubpelAvgVarianceTest = SubpelVarianceTest; TEST_P(VpxSseTest, RefSse) { RefTestSse(); } TEST_P(VpxSseTest, MaxSse) { MaxTestSse(); } TEST_P(VpxMseTest, RefMse) { RefTestMse(); } TEST_P(VpxMseTest, MaxMse) { MaxTestMse(); } @@ -854,23 +854,23 @@ TEST_P(VpxSubpelAvgVarianceTest, Ref) { RefTest(); } INSTANTIATE_TEST_SUITE_P(C, SumOfSquaresTest, ::testing::Values(vpx_get_mb_ss_c)); -typedef TestParams SseParams; +using SseParams = TestParams; INSTANTIATE_TEST_SUITE_P(C, VpxSseTest, ::testing::Values(SseParams(2, 2, &vpx_get4x4sse_cs_c))); -typedef TestParams MseParams; +using MseParams = TestParams; INSTANTIATE_TEST_SUITE_P(C, VpxMseTest, ::testing::Values(MseParams(4, 4, &vpx_mse16x16_c), MseParams(4, 3, &vpx_mse16x8_c), MseParams(3, 4, &vpx_mse8x16_c), MseParams(3, 3, &vpx_mse8x8_c))); -typedef TestParams VarianceParams; +using VarianceParams = TestParams; INSTANTIATE_TEST_SUITE_P( C, VpxVarianceTest, ::testing::Values(VarianceParams(6, 6, &vpx_variance64x64_c), VarianceParams(6, 5, &vpx_variance64x32_c), VarianceParams(5, 6, &vpx_variance32x64_c), @@ -883,21 +883,21 @@ VarianceParams(3, 3, &vpx_variance8x8_c), VarianceParams(3, 2, &vpx_variance8x4_c), VarianceParams(2, 3, &vpx_variance4x8_c), VarianceParams(2, 2, &vpx_variance4x4_c))); -typedef TestParams GetVarianceParams; +using GetVarianceParams = TestParams; INSTANTIATE_TEST_SUITE_P( C, VpxGetVarianceTest, ::testing::Values(GetVarianceParams(4, 4, &vpx_get16x16var_c), GetVarianceParams(3, 3, &vpx_get8x8var_c), GetVarianceParams(4, 4, &vpx_get16x16var_c), GetVarianceParams(3, 3, &vpx_get8x8var_c), GetVarianceParams(4, 4, &vpx_get16x16var_c), GetVarianceParams(3, 3, &vpx_get8x8var_c))); -typedef TestParams SubpelVarianceParams; +using SubpelVarianceParams = TestParams; INSTANTIATE_TEST_SUITE_P( C, VpxSubpelVarianceTest, ::testing::Values( SubpelVarianceParams(6, 6, &vpx_sub_pixel_variance64x64_c, 0), SubpelVarianceParams(6, 5, &vpx_sub_pixel_variance64x32_c, 0), @@ -911,11 +911,11 @@ SubpelVarianceParams(3, 3, &vpx_sub_pixel_variance8x8_c, 0), SubpelVarianceParams(3, 2, &vpx_sub_pixel_variance8x4_c, 0), SubpelVarianceParams(2, 3, &vpx_sub_pixel_variance4x8_c, 0), SubpelVarianceParams(2, 2, &vpx_sub_pixel_variance4x4_c, 0))); -typedef TestParams SubpelAvgVarianceParams; +using SubpelAvgVarianceParams = TestParams; INSTANTIATE_TEST_SUITE_P( C, VpxSubpelAvgVarianceTest, ::testing::Values( SubpelAvgVarianceParams(6, 6, &vpx_sub_pixel_avg_variance64x64_c, 0), SubpelAvgVarianceParams(6, 5, &vpx_sub_pixel_avg_variance64x32_c, 0), @@ -930,15 +930,15 @@ SubpelAvgVarianceParams(3, 2, &vpx_sub_pixel_avg_variance8x4_c, 0), SubpelAvgVarianceParams(2, 3, &vpx_sub_pixel_avg_variance4x8_c, 0), SubpelAvgVarianceParams(2, 2, &vpx_sub_pixel_avg_variance4x4_c, 0))); #if CONFIG_VP9_HIGHBITDEPTH -typedef MainTestClass VpxHBDVarianceTest; -typedef MainTestClass VpxHBDGetVarianceTest; -typedef SubpelVarianceTest VpxHBDSubpelVarianceTest; -typedef SubpelVarianceTest - VpxHBDSubpelAvgVarianceTest; +using VpxHBDVarianceTest = MainTestClass; +using VpxHBDGetVarianceTest = MainTestClass; +using VpxHBDSubpelVarianceTest = SubpelVarianceTest; +using VpxHBDSubpelAvgVarianceTest = + SubpelVarianceTest; TEST_P(VpxHBDVarianceTest, Zero) { ZeroTest(); } TEST_P(VpxHBDVarianceTest, Ref) { RefTest(); } TEST_P(VpxHBDVarianceTest, RefStride) { RefStrideTest(); } TEST_P(VpxHBDVarianceTest, OneQuarter) { OneQuarterTest(); } @@ -946,11 +946,11 @@ TEST_P(VpxHBDGetVarianceTest, RefGetVar) { RefTestGetVar(); } TEST_P(VpxHBDSubpelVarianceTest, Ref) { RefTest(); } TEST_P(VpxHBDSubpelVarianceTest, ExtremeRef) { ExtremeRefTest(); } TEST_P(VpxHBDSubpelAvgVarianceTest, Ref) { RefTest(); } -typedef MainTestClass VpxHBDMseTest; +using VpxHBDMseTest = MainTestClass; TEST_P(VpxHBDMseTest, RefMse) { RefTestMse(); } TEST_P(VpxHBDMseTest, MaxMse) { MaxTestMse(); } TEST_P(VpxHBDMseTest, DISABLED_Speed) { SpeedTest(); } INSTANTIATE_TEST_SUITE_P( C, VpxHBDMseTest, diff --git a/media/libvpx/libvpx/test/vp8_datarate_test.cc b/media/libvpx/libvpx/test/vp8_datarate_test.cc --- a/media/libvpx/libvpx/test/vp8_datarate_test.cc +++ b/media/libvpx/libvpx/test/vp8_datarate_test.cc @@ -32,17 +32,19 @@ SetMode(GET_PARAM(1)); set_cpu_used_ = GET_PARAM(2); ResetModel(); } - virtual void ResetModel() { + void ResetModel() { last_pts_ = 0; bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz; frame_number_ = 0; first_drop_ = 0; bits_total_ = 0; duration_ = 0.0; + // Denoiser is off by default. + denoiser_on_ = 0; denoiser_offon_test_ = 0; denoiser_offon_period_ = -1; gf_boost_ = 0; use_roi_ = false; } @@ -145,13 +147,13 @@ for (int j = 1; j < 5; ++j) { // Run over the denoiser levels. // For the temporal denoiser (#if CONFIG_TEMPORAL_DENOISING) the level j // refers to the 4 denoiser modes: denoiserYonly, denoiserOnYUV, // denoiserOnAggressive, and denoiserOnAdaptive. - denoiser_on_ = j; cfg_.rc_target_bitrate = 300; ResetModel(); + denoiser_on_ = j; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95) << " The datarate for the file exceeds the target!"; ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.4) @@ -166,12 +168,10 @@ cfg_.rc_end_usage = VPX_CBR; ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 30, 1, 0, 299); cfg_.rc_target_bitrate = 300; ResetModel(); - // The denoiser is off by default. - denoiser_on_ = 0; // Set the offon test flag. denoiser_offon_test_ = 1; denoiser_offon_period_ = 100; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95) @@ -179,11 +179,10 @@ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.4) << " The datarate for the file missed the target!"; } virtual void BasicBufferModelTest() { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 1; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; // 2 pass cbr datarate control has a bug hidden by the small # of @@ -210,11 +209,10 @@ << " The datarate for the file missed the target!"; } } virtual void ChangingDropFrameThreshTest() { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_max_quantizer = 36; cfg_.rc_end_usage = VPX_CBR; cfg_.rc_target_bitrate = 200; cfg_.kf_mode = VPX_KF_DISABLED; @@ -239,11 +237,10 @@ last_drop = first_drop_; } } virtual void DropFramesMultiThreadsTest() { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 30; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; cfg_.g_threads = 2; @@ -259,11 +256,10 @@ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.4) << " The datarate for the file missed the target!"; } virtual void MultiThreadsPSNRTest() { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 0; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; cfg_.g_threads = 4; @@ -346,11 +342,10 @@ } TEST_P(DatarateTestRealTime, MultiThreadsPSNR) { MultiThreadsPSNRTest(); } TEST_P(DatarateTestRealTime, RegionOfInterest) { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 0; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; // Encode using multiple threads. @@ -407,11 +402,10 @@ free(roi_.roi_map); } TEST_P(DatarateTestRealTime, GFBoost) { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 0; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; cfg_.g_error_resilient = 0; @@ -430,11 +424,10 @@ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.4) << " The datarate for the file missed the target!"; } TEST_P(DatarateTestRealTime, NV12) { - denoiser_on_ = 0; cfg_.rc_buf_initial_sz = 500; cfg_.rc_dropframe_thresh = 0; cfg_.rc_max_quantizer = 56; cfg_.rc_end_usage = VPX_CBR; cfg_.g_error_resilient = 0; @@ -451,11 +444,65 @@ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.4) << " The datarate for the file missed the target!"; } +class DatarateTestPsnr : public DatarateTestLarge { + public: + DatarateTestPsnr() : DatarateTestLarge() {} + ~DatarateTestPsnr() override = default; + + protected: + void SetUp() override { + InitializeConfig(); + SetMode(libvpx_test::kRealTime); + set_cpu_used_ = 10; + ResetModel(); + frame_flags_ = VPX_EFLAG_CALCULATE_PSNR; + } + void PreEncodeFrameHook(::libvpx_test::VideoSource *video, + ::libvpx_test::Encoder *encoder) override { + DatarateTestLarge::PreEncodeFrameHook(video, encoder); + frame_flags_ ^= VPX_EFLAG_CALCULATE_PSNR; +#if CONFIG_INTERNAL_STATS + // CONFIG_INTERNAL_STATS unconditionally generates PSNR. + expect_psnr_ = true; +#else + expect_psnr_ = (frame_flags_ & VPX_EFLAG_CALCULATE_PSNR) != 0; +#endif // CONFIG_INTERNAL_STATS + if (video->img() == nullptr) { + expect_psnr_ = false; + } + } + void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) override { + libvpx_test::CxDataIterator iter = encoder->GetCxData(); + + bool had_psnr = false; + while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) { + if (pkt->kind == VPX_CODEC_PSNR_PKT) had_psnr = true; + } + + EXPECT_EQ(had_psnr, expect_psnr_); + } + + private: + bool expect_psnr_; +}; + +TEST_P(DatarateTestPsnr, PerFramePsnr) { + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 100); + + ResetModel(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + VP8_INSTANTIATE_TEST_SUITE(DatarateTestLarge, ALL_TEST_MODES, ::testing::Values(0)); VP8_INSTANTIATE_TEST_SUITE(DatarateTestRealTime, ::testing::Values(::libvpx_test::kRealTime), ::testing::Values(-6, -12)); +VP8_INSTANTIATE_TEST_SUITE(DatarateTestPsnr, + ::testing::Values(::libvpx_test::kRealTime), + ::testing::Values(0)); + } // namespace diff --git a/media/libvpx/libvpx/test/vp8_fdct4x4_test.cc b/media/libvpx/libvpx/test/vp8_fdct4x4_test.cc --- a/media/libvpx/libvpx/test/vp8_fdct4x4_test.cc +++ b/media/libvpx/libvpx/test/vp8_fdct4x4_test.cc @@ -23,11 +23,11 @@ #include "vpx/vpx_integer.h" #include "vpx_ports/mem.h" namespace { -typedef void (*FdctFunc)(int16_t *a, int16_t *b, int a_stride); +using FdctFunc = void (*)(int16_t *a, int16_t *b, int a_stride); const int cospi8sqrt2minus1 = 20091; const int sinpi8sqrt2 = 35468; void reference_idct4x4(const int16_t *input, int16_t *output) { diff --git a/media/libvpx/libvpx/test/vp9_arf_freq_test.cc b/media/libvpx/libvpx/test/vp9_arf_freq_test.cc --- a/media/libvpx/libvpx/test/vp9_arf_freq_test.cc +++ b/media/libvpx/libvpx/test/vp9_arf_freq_test.cc @@ -26,26 +26,26 @@ const int kBitrate = 500; #define ARF_NOT_SEEN 1000001 #define ARF_SEEN_ONCE 1000000 -typedef struct { +struct TestVideoParam { const char *filename; unsigned int width; unsigned int height; unsigned int framerate_num; unsigned int framerate_den; unsigned int input_bit_depth; vpx_img_fmt fmt; vpx_bit_depth_t bit_depth; unsigned int profile; -} TestVideoParam; +}; -typedef struct { +struct TestEncodeParam { libvpx_test::TestMode mode; int cpu_used; -} TestEncodeParam; +}; const TestVideoParam kTestVectors[] = { // artificially increase framerate to trigger default check { "hantro_collage_w352h288.yuv", 352, 288, 5000, 1, 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0 }, diff --git a/media/libvpx/libvpx/test/vp9_block_error_test.cc b/media/libvpx/libvpx/test/vp9_block_error_test.cc --- a/media/libvpx/libvpx/test/vp9_block_error_test.cc +++ b/media/libvpx/libvpx/test/vp9_block_error_test.cc @@ -29,21 +29,21 @@ using libvpx_test::ACMRandom; namespace { const int kNumIterations = 1000; -typedef int64_t (*HBDBlockErrorFunc)(const tran_low_t *coeff, - const tran_low_t *dqcoeff, - intptr_t block_size, int64_t *ssz, - int bps); +using HBDBlockErrorFunc = int64_t (*)(const tran_low_t *coeff, + const tran_low_t *dqcoeff, + intptr_t block_size, int64_t *ssz, + int bps); -typedef std::tuple - BlockErrorParam; +using BlockErrorParam = + std::tuple; -typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff, - const tran_low_t *dqcoeff, - intptr_t block_size, int64_t *ssz); +using BlockErrorFunc = int64_t (*)(const tran_low_t *coeff, + const tran_low_t *dqcoeff, + intptr_t block_size, int64_t *ssz); template int64_t BlockError8BitWrapper(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz, int bps) { diff --git a/media/libvpx/libvpx/test/vp9_datarate_test.cc b/media/libvpx/libvpx/test/vp9_datarate_test.cc --- a/media/libvpx/libvpx/test/vp9_datarate_test.cc +++ b/media/libvpx/libvpx/test/vp9_datarate_test.cc @@ -1065,10 +1065,62 @@ ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15) << " The datarate for the file is greater than target by too much!"; } #endif // CONFIG_VP9_TEMPORAL_DENOISING +class DatarateTestVP9Psnr : public DatarateTestVP9, + public ::libvpx_test::CodecTestWithParam { + protected: + DatarateTestVP9Psnr() : DatarateTestVP9(GET_PARAM(0)) {} + ~DatarateTestVP9Psnr() override = default; + + void SetUp() override { + InitializeConfig(); + cfg_.g_lag_in_frames = 0; + SetMode(libvpx_test::kRealTime); + set_cpu_used_ = 10; + ResetModel(); + frame_flags_ = VPX_EFLAG_CALCULATE_PSNR; + expect_psnr_ = true; + } + void PreEncodeFrameHook(::libvpx_test::VideoSource *video, + ::libvpx_test::Encoder *encoder) override { + DatarateTestVP9::PreEncodeFrameHook(video, encoder); + frame_flags_ ^= VPX_EFLAG_CALCULATE_PSNR; +#if CONFIG_INTERNAL_STATS + // CONFIG_INTERNAL_STATS unconditionally generates PSNR. + expect_psnr_ = true; +#else + expect_psnr_ = (frame_flags_ & VPX_EFLAG_CALCULATE_PSNR) != 0; +#endif // CONFIG_INTERNAL_STATS + if (video->img() == nullptr) { + expect_psnr_ = false; + } + } + void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) override { + libvpx_test::CxDataIterator iter = encoder->GetCxData(); + + bool had_psnr = false; + while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) { + if (pkt->kind == VPX_CODEC_PSNR_PKT) had_psnr = true; + } + + EXPECT_EQ(had_psnr, expect_psnr_); + } + + private: + bool expect_psnr_; +}; + +TEST_P(DatarateTestVP9Psnr, PerFramePsnr) { + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, + 30, 1, 0, 100); + + ResetModel(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + VP9_INSTANTIATE_TEST_SUITE(DatarateTestVP9RealTimeMultiBR, ::testing::Range(5, 10), ::testing::Range(0, 4)); VP9_INSTANTIATE_TEST_SUITE(DatarateTestVP9LargeVBR, ::testing::Range(5, 9), ::testing::Range(0, 2)); @@ -1091,6 +1143,9 @@ #if CONFIG_VP9_TEMPORAL_DENOISING VP9_INSTANTIATE_TEST_SUITE(DatarateTestVP9RealTimeDenoiser, ::testing::Range(5, 10)); #endif + +VP9_INSTANTIATE_TEST_SUITE(DatarateTestVP9Psnr, + ::testing::Values(::libvpx_test::kRealTime)); } // namespace diff --git a/media/libvpx/libvpx/test/vp9_denoiser_test.cc b/media/libvpx/libvpx/test/vp9_denoiser_test.cc --- a/media/libvpx/libvpx/test/vp9_denoiser_test.cc +++ b/media/libvpx/libvpx/test/vp9_denoiser_test.cc @@ -30,16 +30,16 @@ namespace { const int kNumPixels = 64 * 64; -typedef int (*Vp9DenoiserFilterFunc)(const uint8_t *sig, int sig_stride, - const uint8_t *mc_avg, int mc_avg_stride, - uint8_t *avg, int avg_stride, - int increase_denoising, BLOCK_SIZE bs, - int motion_magnitude); -typedef std::tuple VP9DenoiserTestParam; +using Vp9DenoiserFilterFunc = int (*)(const uint8_t *sig, int sig_stride, + const uint8_t *mc_avg, int mc_avg_stride, + uint8_t *avg, int avg_stride, + int increase_denoising, BLOCK_SIZE bs, + int motion_magnitude); +using VP9DenoiserTestParam = std::tuple; class VP9DenoiserTest : public ::testing::Test, public ::testing::WithParamInterface { public: diff --git a/media/libvpx/libvpx/test/vp9_end_to_end_test.cc b/media/libvpx/libvpx/test/vp9_end_to_end_test.cc --- a/media/libvpx/libvpx/test/vp9_end_to_end_test.cc +++ b/media/libvpx/libvpx/test/vp9_end_to_end_test.cc @@ -33,17 +33,17 @@ { 34.0, 35.0, 35.0, 35.0, 35.0 }, { 33.0, 34.0, 34.0, 34.0, 34.0 }, { 32.0, 33.0, 33.0, 33.0, 33.0 }, { 28.0, 32.0, 32.0, 32.0, 32.0 }, { 28.4, 31.0, 31.0, 31.0, 31.0 }, { 27.5, 30.0, 30.0, 30.0, 30.0 }, }; -typedef struct { +struct TestVideoParam { const char *filename; unsigned int input_bit_depth; vpx_img_fmt fmt; vpx_bit_depth_t bit_depth; unsigned int profile; -} TestVideoParam; +}; const TestVideoParam kTestVectors[] = { { "park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0 }, { "park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422, VPX_BITS_8, 1 }, { "park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444, VPX_BITS_8, 1 }, diff --git a/media/libvpx/libvpx/test/vp9_ext_ratectrl_test.cc b/media/libvpx/libvpx/test/vp9_ext_ratectrl_test.cc --- a/media/libvpx/libvpx/test/vp9_ext_ratectrl_test.cc +++ b/media/libvpx/libvpx/test/vp9_ext_ratectrl_test.cc @@ -20,11 +20,10 @@ #include "test/util.h" #include "test/yuv_video_source.h" #if CONFIG_VP9_DECODER #include "vpx/vp8dx.h" #endif -#include "vp9/simple_encode.h" #include "vpx/vpx_codec.h" #include "vpx/vpx_encoder.h" #include "vpx/vpx_ext_ratectrl.h" #include "vpx/vpx_image.h" #include "vpx/vpx_tpl.h" diff --git a/media/libvpx/libvpx/test/vp9_intrapred_test.cc b/media/libvpx/libvpx/test/vp9_intrapred_test.cc --- a/media/libvpx/libvpx/test/vp9_intrapred_test.cc +++ b/media/libvpx/libvpx/test/vp9_intrapred_test.cc @@ -26,12 +26,12 @@ using libvpx_test::ACMRandom; const int count_test_block = 100000; -typedef void (*IntraPredFunc)(uint8_t *dst, ptrdiff_t stride, - const uint8_t *above, const uint8_t *left); +using IntraPredFunc = void (*)(uint8_t *dst, ptrdiff_t stride, + const uint8_t *above, const uint8_t *left); struct IntraPredParam { IntraPredParam(IntraPredFunc pred = nullptr, IntraPredFunc ref = nullptr, int block_size_value = 0, int bit_depth_value = 0) : pred_fn(pred), ref_fn(ref), block_size(block_size_value), @@ -133,11 +133,11 @@ params_.ref_fn(ref_dst_, stride_, above_row_, left_col_); ASM_REGISTER_STATE_CHECK( params_.pred_fn(dst_, stride_, above_row_, left_col_)); } -typedef IntraPredTest VP9IntraPredTest; +using VP9IntraPredTest = IntraPredTest; TEST_P(VP9IntraPredTest, IntraPredTests) { // max block size is 32 DECLARE_ALIGNED(16, uint8_t, left_col[2 * 32]); DECLARE_ALIGNED(16, uint8_t, above_data[2 * 32 + 32]); @@ -497,13 +497,14 @@ IntraPredParam(&vpx_dc_predictor_16x16_lsx, &vpx_dc_predictor_16x16_c, 16, 8))); #endif // HAVE_LSX #if CONFIG_VP9_HIGHBITDEPTH -typedef void (*HighbdIntraPred)(uint16_t *dst, ptrdiff_t stride, - const uint16_t *above, const uint16_t *left, - int bps); +using HighbdIntraPred = void (*)(uint16_t *dst, ptrdiff_t stride, + const uint16_t *above, const uint16_t *left, + int bps); + struct HighbdIntraPredParam { HighbdIntraPredParam(HighbdIntraPred pred = nullptr, HighbdIntraPred ref = nullptr, int block_size_value = 0, int bit_depth_value = 0) : pred_fn(pred), ref_fn(ref), block_size(block_size_value), @@ -522,11 +523,11 @@ params_.ref_fn(ref_dst_, stride_, above_row_, left_col_, bit_depth); ASM_REGISTER_STATE_CHECK( params_.pred_fn(dst_, stride_, above_row_, left_col_, bit_depth)); } -typedef IntraPredTest VP9HighbdIntraPredTest; +using VP9HighbdIntraPredTest = IntraPredTest; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VP9HighbdIntraPredTest); TEST_P(VP9HighbdIntraPredTest, HighbdIntraPredTests) { // max block size is 32 DECLARE_ALIGNED(16, uint16_t, left_col[2 * 32]); diff --git a/media/libvpx/libvpx/test/vp9_quantize_test.cc b/media/libvpx/libvpx/test/vp9_quantize_test.cc --- a/media/libvpx/libvpx/test/vp9_quantize_test.cc +++ b/media/libvpx/libvpx/test/vp9_quantize_test.cc @@ -36,25 +36,24 @@ using libvpx_test::Buffer; namespace { const int number_of_iterations = 100; -typedef void (*QuantizeFunc)(const tran_low_t *coeff, intptr_t count, - const macroblock_plane *mb_plane, - tran_low_t *qcoeff, tran_low_t *dqcoeff, - const int16_t *dequant, uint16_t *eob, - const struct ScanOrder *const scan_order); -typedef std::tuple - QuantizeParam; +using QuantizeFunc = void (*)(const tran_low_t *coeff, intptr_t count, + const macroblock_plane *mb_plane, + tran_low_t *qcoeff, tran_low_t *dqcoeff, + const int16_t *dequant, uint16_t *eob, + const struct ScanOrder *const scan_order); +using QuantizeParam = std::tuple; // Wrapper for 32x32 version which does not use count -typedef void (*Quantize32x32Func)(const tran_low_t *coeff, - const macroblock_plane *const mb_plane, - tran_low_t *qcoeff, tran_low_t *dqcoeff, - const int16_t *dequant, uint16_t *eob, - const struct ScanOrder *const scan_order); +using Quantize32x32Func = void (*)(const tran_low_t *coeff, + const macroblock_plane *const mb_plane, + tran_low_t *qcoeff, tran_low_t *dqcoeff, + const int16_t *dequant, uint16_t *eob, + const struct ScanOrder *const scan_order); template void Quant32x32Wrapper(const tran_low_t *coeff, intptr_t count, const macroblock_plane *const mb_plane, tran_low_t *qcoeff, tran_low_t *dqcoeff, @@ -63,15 +62,15 @@ (void)count; fn(coeff, mb_plane, qcoeff, dqcoeff, dequant, eob, scan_order); } // Wrapper for FP version which does not use zbin or quant_shift. -typedef void (*QuantizeFPFunc)(const tran_low_t *coeff, intptr_t count, - const macroblock_plane *const mb_plane, - tran_low_t *qcoeff, tran_low_t *dqcoeff, - const int16_t *dequant, uint16_t *eob, - const struct ScanOrder *const scan_order); +using QuantizeFPFunc = void (*)(const tran_low_t *coeff, intptr_t count, + const macroblock_plane *const mb_plane, + tran_low_t *qcoeff, tran_low_t *dqcoeff, + const int16_t *dequant, uint16_t *eob, + const struct ScanOrder *const scan_order); template void QuantFPWrapper(const tran_low_t *coeff, intptr_t count, const macroblock_plane *const mb_plane, tran_low_t *qcoeff, tran_low_t *dqcoeff, const int16_t *dequant, uint16_t *eob, diff --git a/media/libvpx/libvpx/test/vp9_scale_test.cc b/media/libvpx/libvpx/test/vp9_scale_test.cc --- a/media/libvpx/libvpx/test/vp9_scale_test.cc +++ b/media/libvpx/libvpx/test/vp9_scale_test.cc @@ -24,13 +24,13 @@ #include "vpx_ports/vpx_timer.h" #include "vpx_scale/yv12config.h" namespace libvpx_test { -typedef void (*ScaleFrameFunc)(const YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *dst, - INTERP_FILTER filter_type, int phase_scaler); +using ScaleFrameFunc = void (*)(const YV12_BUFFER_CONFIG *src, + YV12_BUFFER_CONFIG *dst, + INTERP_FILTER filter_type, int phase_scaler); class ScaleTest : public VpxScaleBase, public ::testing::TestWithParam { public: ~ScaleTest() override = default; diff --git a/media/libvpx/libvpx/test/vp9_subtract_test.cc b/media/libvpx/libvpx/test/vp9_subtract_test.cc --- a/media/libvpx/libvpx/test/vp9_subtract_test.cc +++ b/media/libvpx/libvpx/test/vp9_subtract_test.cc @@ -22,14 +22,14 @@ #include "test/util.h" #include "vp9/common/vp9_blockd.h" #include "vpx_mem/vpx_mem.h" #include "vpx_ports/vpx_timer.h" -typedef void (*SubtractFunc)(int rows, int cols, 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); +using SubtractFunc = void (*)(int rows, int cols, 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); namespace vp9 { class VP9SubtractBlockTest : public AbstractBench, public ::testing::TestWithParam { @@ -164,14 +164,14 @@ ::testing::Values(vpx_subtract_block_lsx)); #endif #if CONFIG_VP9_HIGHBITDEPTH -typedef void (*HBDSubtractFunc)(int rows, int cols, 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, int bd); +using HBDSubtractFunc = void (*)(int rows, int cols, 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, int bd); // using Params = std::tuple; class VPXHBDSubtractBlockTest : public ::testing::TestWithParam { diff --git a/media/libvpx/libvpx/test/vpx_scale_test.cc b/media/libvpx/libvpx/test/vpx_scale_test.cc --- a/media/libvpx/libvpx/test/vpx_scale_test.cc +++ b/media/libvpx/libvpx/test/vpx_scale_test.cc @@ -28,13 +28,13 @@ #else const int kNumSizesToTest = 8; #endif const int kSizesToTest[] = { 1, 15, 33, 145, 512, 1025, 3840, 16383 }; -typedef void (*ExtendFrameBorderFunc)(YV12_BUFFER_CONFIG *ybf); -typedef void (*CopyFrameFunc)(const YV12_BUFFER_CONFIG *src_ybf, - YV12_BUFFER_CONFIG *dst_ybf); +using ExtendFrameBorderFunc = void (*)(YV12_BUFFER_CONFIG *ybf); +using CopyFrameFunc = void (*)(const YV12_BUFFER_CONFIG *src_ybf, + YV12_BUFFER_CONFIG *dst_ybf); class ExtendBorderTest : public VpxScaleBase, public ::testing::TestWithParam { public: diff --git a/media/libvpx/libvpx/test/yuv_temporal_filter_test.cc b/media/libvpx/libvpx/test/yuv_temporal_filter_test.cc --- a/media/libvpx/libvpx/test/yuv_temporal_filter_test.cc +++ b/media/libvpx/libvpx/test/yuv_temporal_filter_test.cc @@ -20,11 +20,11 @@ namespace { using ::libvpx_test::ACMRandom; using ::libvpx_test::Buffer; -typedef void (*YUVTemporalFilterFunc)( +using YUVTemporalFilterFunc = void (*)( 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 *const blk_fw, int use_32x32, diff --git a/media/libvpx/libvpx/third_party/nalloc/LICENSE b/media/libvpx/libvpx/third_party/nalloc/LICENSE new file mode 100644 --- /dev/null +++ b/media/libvpx/libvpx/third_party/nalloc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Catena cyber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/media/libvpx/libvpx/third_party/nalloc/README.libvpx b/media/libvpx/libvpx/third_party/nalloc/README.libvpx new file mode 100644 --- /dev/null +++ b/media/libvpx/libvpx/third_party/nalloc/README.libvpx @@ -0,0 +1,11 @@ +Name: nalloc +URL: https://github.com/catenacyber/nallocfuzz +Version: dc351a94bbded5ede5b7550d6d08e78e0cc6dcef +License: MIT +License File: LICENSE + +Description: +Nalloc is a tool to inject allocation failures while fuzzing. + +Local Modifications: +None diff --git a/media/libvpx/libvpx/third_party/nalloc/nalloc.h b/media/libvpx/libvpx/third_party/nalloc/nalloc.h new file mode 100644 --- /dev/null +++ b/media/libvpx/libvpx/third_party/nalloc/nalloc.h @@ -0,0 +1,342 @@ +/* + MIT License + + Copyright (c) 2025 Catena cyber + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#ifndef NALLOC_H_ +#define NALLOC_H_ + +#if defined(__clang__) && defined(__has_feature) +#if __has_feature(address_sanitizer) +#define NALLOC_ASAN 1 +#endif +#if __has_feature(memory_sanitizer) +#define FUZZER_DISABLE_NALLOC 1 +#endif +#endif + +#if defined(FUZZER_DISABLE_NALLOC) +#define nalloc_init(x) +#define nalloc_restrict_file_prefix(x) +#define nalloc_start(x, y) +#define nalloc_end() +#else + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static const uint32_t nalloc_crc32_table[] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +// Nallocfuzz data to take a decision +uint32_t nalloc_random_state = 0; +__thread unsigned int nalloc_running = 0; +bool nalloc_initialized = false; +uint32_t nalloc_runs = 0; + +// Nalloc fuzz parameters +uint32_t nalloc_bitmask = 0xFF; +bool nalloc_random_bitmask = true; +uint32_t nalloc_magic = 0x294cee63; +bool nalloc_verbose = false; + +#ifdef NALLOC_ASAN +extern void __sanitizer_print_stack_trace(void); +#endif + +// Generic init, using env variables to get parameters +void nalloc_init(const char *prog) { + if (nalloc_initialized) { + return; + } + nalloc_initialized = true; + char *bitmask = getenv("NALLOC_FREQ"); + if (bitmask) { + int shift = atoi(bitmask); + if (shift > 0 && shift < 31) { + nalloc_bitmask = 1 << shift; + nalloc_random_bitmask = false; + } else if (shift == 0) { + nalloc_random_bitmask = false; + nalloc_bitmask = 0; + } + } else if (prog == NULL || strstr(prog, "nalloc") == NULL) { + nalloc_random_bitmask = false; + nalloc_bitmask = 0; + return; + } + + char *magic = getenv("NALLOC_MAGIC"); + if (magic) { + nalloc_magic = (uint32_t)strtol(magic, NULL, 0); + } + + char *verbose = getenv("NALLOC_VERBOSE"); + if (verbose) { + nalloc_verbose = true; + } +} + +// add one byte to the CRC +static inline void nalloc_random_update(uint8_t b) { + nalloc_random_state = + ((uint32_t)((uint32_t)nalloc_random_state << 8)) ^ + nalloc_crc32_table[((nalloc_random_state >> 24) ^ b) & 0xFF]; +} + +// Start the failure injections, using a buffer as seed +static int nalloc_start(const uint8_t *data, size_t size) { + if (nalloc_random_bitmask) { + if (nalloc_random_state & 0x10) { + nalloc_bitmask = 0xFFFFFFFF; + } else { + nalloc_bitmask = 1 << (5 + (nalloc_random_state & 0xF)); + } + } else if (nalloc_bitmask == 0) { + // nalloc disabled + return 0; + } + nalloc_random_state = 0; + for (size_t i = 0; i < size; i++) { + nalloc_random_update(data[i]); + } + if (__sync_fetch_and_add(&nalloc_running, 1)) { + __sync_fetch_and_sub(&nalloc_running, 1); + return 0; + } + nalloc_runs++; + return 1; +} + +// Stop the failure injections +static void nalloc_end() { __sync_fetch_and_sub(&nalloc_running, 1); } + +static bool nalloc_backtrace_exclude(size_t size, const char *op) { + if (nalloc_verbose) { + fprintf(stderr, "failed %s(%zu) \n", op, size); +#ifdef NALLOC_ASAN + __sanitizer_print_stack_trace(); +#endif + } + + return false; +} + +// +static bool nalloc_fail(size_t size, const char *op) { + // do not fail before thread init + if (nalloc_runs == 0) { + return false; + } + if (__sync_fetch_and_add(&nalloc_running, 1) != 1) { + // do not fail allocations outside of fuzzer input + // and do not fail inside of this function + __sync_fetch_and_sub(&nalloc_running, 1); + return false; + } + nalloc_random_update((uint8_t)size); + if (size >= 0x100) { + nalloc_random_update((uint8_t)(size >> 8)); + if (size >= 0x10000) { + nalloc_random_update((uint8_t)(size >> 16)); + // bigger may already fail or oom + } + } + if (((nalloc_random_state ^ nalloc_magic) & nalloc_bitmask) == 0) { + if (nalloc_backtrace_exclude(size, op)) { + __sync_fetch_and_sub(&nalloc_running, 1); + return false; + } + __sync_fetch_and_sub(&nalloc_running, 1); + return true; + } + __sync_fetch_and_sub(&nalloc_running, 1); + return false; +} + +// ASAN interceptor for libc routines +#ifdef NALLOC_ASAN +extern void *__interceptor_malloc(size_t); +extern void *__interceptor_calloc(size_t, size_t); +extern void *__interceptor_realloc(void *, size_t); +extern void *__interceptor_reallocarray(void *, size_t, size_t); + +extern ssize_t __interceptor_read(int, void *, size_t); +extern ssize_t __interceptor_write(int, const void *, size_t); +extern ssize_t __interceptor_recv(int, void *, size_t, int); +extern ssize_t __interceptor_send(int, const void *, size_t, int); + +#define nalloc_malloc(s) __interceptor_malloc(s) +#define nalloc_calloc(s, n) __interceptor_calloc(s, n) +#define nalloc_realloc(p, s) __interceptor_realloc(p, s) +#define nalloc_reallocarray(p, s, n) __interceptor_reallocarray(p, s, n) + +#define nalloc_read(f, b, s) __interceptor_read(f, b, s) +#define nalloc_write(f, b, s) __interceptor_write(f, b, s) +#define nalloc_recv(f, b, s, x) __interceptor_recv(f, b, s, x) +#define nalloc_send(f, b, s, x) __interceptor_send(f, b, s, x) + +#else +extern void *__libc_malloc(size_t); +extern void *__libc_calloc(size_t, size_t); +extern void *__libc_realloc(void *, size_t); +extern void *__libc_reallocarray(void *, size_t, size_t); + +extern ssize_t __read(int, void *, size_t); +extern ssize_t __write(int, const void *, size_t); +extern ssize_t __recv(int, void *, size_t, int); +extern ssize_t __send(int, const void *, size_t, int); + +#define nalloc_malloc(s) __libc_malloc(s) +#define nalloc_calloc(s, n) __libc_calloc(s, n) +#define nalloc_realloc(p, s) __libc_realloc(p, s) +#define nalloc_reallocarray(p, s, n) __libc_reallocarray(p, s, n) + +#define nalloc_read(f, b, s) __read(f, b, s) +#define nalloc_write(f, b, s) __write(f, b, s) +#define nalloc_recv(f, b, s, x) __recv(f, b, s, x) +#define nalloc_send(f, b, s, x) __send(f, b, s, x) +#endif + +// nalloc standard function overwrites with pseudo-random failures +ssize_t read(int fd, void *buf, size_t count) { + if (nalloc_fail(count, "read")) { + errno = EIO; + return -1; + } + return nalloc_read(fd, buf, count); +} + +ssize_t write(int fd, const void *buf, size_t count) { + if (nalloc_fail(count, "write")) { + errno = EIO; + return -1; + } + return nalloc_write(fd, buf, count); +} + +ssize_t recv(int fd, void *buf, size_t count, int flags) { + if (nalloc_fail(count, "recv")) { + errno = EIO; + return -1; + } + return nalloc_recv(fd, buf, count, flags); +} + +ssize_t send(int fd, const void *buf, size_t count, int flags) { + if (nalloc_fail(count, "send")) { + errno = EIO; + return -1; + } + return nalloc_send(fd, buf, count, flags); +} + +void *calloc(size_t nmemb, size_t size) { + if (nalloc_fail(size, "calloc")) { + errno = ENOMEM; + return NULL; + } + return nalloc_calloc(nmemb, size); +} + +void *malloc(size_t size) { + if (nalloc_fail(size, "malloc")) { + errno = ENOMEM; + return NULL; + } + return nalloc_malloc(size); +} + +void *realloc(void *ptr, size_t size) { + if (nalloc_fail(size, "realloc")) { + errno = ENOMEM; + return NULL; + } + return nalloc_realloc(ptr, size); +} + +void *reallocarray(void *ptr, size_t nmemb, size_t size) { + if (nalloc_fail(size, "reallocarray")) { + errno = ENOMEM; + return NULL; + } + return nalloc_reallocarray(ptr, nmemb, size); +} + +#ifdef __cplusplus +} // extern "C" { +#endif + +#endif // FUZZER_DISABLE_NALLOC + +#endif // NALLOC_H_ diff --git a/media/libvpx/libvpx/tools.mk b/media/libvpx/libvpx/tools.mk --- a/media/libvpx/libvpx/tools.mk +++ b/media/libvpx/libvpx/tools.mk @@ -89,10 +89,17 @@ INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\ $(addprefix bin/$(p)/,$(TOOLS_BASENAME:.c=.exe))) $(foreach proj,$(call enabled,PROJECTS),\ $(eval $(call vcproj_template,$(proj)))) +# Generate a list of all enabled sources, in particular for exporting to gyp +# based build systems. +tiny_ssim_srcs.txt: + @echo " [CREATE] $@" + @echo $(tiny_ssim.SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ +CLEAN-OBJS += tiny_ssim_srcs.txt + # # Documentation Rules # %.dox: %.c @echo " [DOXY] $@" diff --git a/media/libvpx/libvpx/vp8/common/mfqe.c b/media/libvpx/libvpx/vp8/common/mfqe.c --- a/media/libvpx/libvpx/vp8/common/mfqe.c +++ b/media/libvpx/libvpx/vp8/common/mfqe.c @@ -210,11 +210,11 @@ } else if (mode_info_context->mbmi.mode == SPLITMV) { static int ndx[4][4] = { { 0, 1, 4, 5 }, { 2, 3, 6, 7 }, { 8, 9, 12, 13 }, { 10, 11, 14, 15 } }; int i, j; - vp8_zero(*map); + vp8_zero_array(map, 4); for (i = 0; i < 4; ++i) { map[i] = 1; for (j = 0; j < 4 && map[j]; ++j) { map[i] &= (mode_info_context->bmi[ndx[i][j]].mv.as_mv.row <= 2 && mode_info_context->bmi[ndx[i][j]].mv.as_mv.col <= 2); diff --git a/media/libvpx/libvpx/vp8/common/mips/msa/vp8_macros_msa.h b/media/libvpx/libvpx/vp8/common/mips/msa/vp8_macros_msa.h --- a/media/libvpx/libvpx/vp8/common/mips/msa/vp8_macros_msa.h +++ b/media/libvpx/libvpx/vp8/common/mips/msa/vp8_macros_msa.h @@ -187,11 +187,11 @@ #define SD(val, pdst) \ { \ uint8_t *sd_pdst_m1 = (uint8_t *)(pdst); \ uint32_t sd_val0_m, sd_val1_m; \ \ - sd_val0_m = (uint32_t)((val)&0x00000000FFFFFFFF); \ + sd_val0_m = (uint32_t)((val) & 0x00000000FFFFFFFF); \ sd_val1_m = (uint32_t)(((val) >> 32) & 0x00000000FFFFFFFF); \ \ SW(sd_val0_m, sd_pdst_m1); \ SW(sd_val1_m, sd_pdst_m1 + 4); \ } diff --git a/media/libvpx/libvpx/vp8/decoder/decodeframe.c b/media/libvpx/libvpx/vp8/decoder/decodeframe.c --- a/media/libvpx/libvpx/vp8/decoder/decodeframe.c +++ b/media/libvpx/libvpx/vp8/decoder/decodeframe.c @@ -963,12 +963,12 @@ } else { /* Error concealment is active, clear the frame. */ data = data_end; } } else { - memcpy(&xd->pre, yv12_fb_new, sizeof(YV12_BUFFER_CONFIG)); - memcpy(&xd->dst, yv12_fb_new, sizeof(YV12_BUFFER_CONFIG)); + xd->pre = *yv12_fb_new; + xd->dst = *yv12_fb_new; } } if ((!pbi->decoded_key_frame && pc->frame_type != KEY_FRAME)) { return -1; } @@ -1154,11 +1154,11 @@ * missing */ xd->corrupted |= vp8dx_bool_error(bc); if (pbi->ec_active && xd->corrupted) pc->refresh_entropy_probs = 0; #endif if (pc->refresh_entropy_probs == 0) { - memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); + pc->lfc = pc->fc; } pc->refresh_last_frame = pc->frame_type == KEY_FRAME || vp8_read_bit(bc); #if CONFIG_ERROR_CONCEALMENT @@ -1243,11 +1243,11 @@ /* vpx_log("Decoder: Frame Decoded, Size Roughly:%d bytes * \n",bc->pos+pbi->bc2.pos); */ if (pc->refresh_entropy_probs == 0) { - memcpy(&pc->fc, &pc->lfc, sizeof(pc->fc)); + pc->fc = pc->lfc; pbi->independent_partitions = prev_independent_partitions; } #ifdef PACKET_TESTING { diff --git a/media/libvpx/libvpx/vp8/encoder/encodeframe.c b/media/libvpx/libvpx/vp8/encoder/encodeframe.c --- a/media/libvpx/libvpx/vp8/encoder/encodeframe.c +++ b/media/libvpx/libvpx/vp8/encoder/encodeframe.c @@ -745,12 +745,14 @@ } #endif { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); +#endif #if CONFIG_MULTITHREAD if (vpx_atomic_load_acquire(&cpi->b_multi_threaded)) { int i; @@ -892,12 +894,14 @@ cpi->partition_sz[i + 1] = bc[i].pos; } } #endif +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&emr_timer); cpi->time_encode_mb_row += vpx_usec_timer_elapsed(&emr_timer); +#endif } // Work out the segment probabilities if segmentation is enabled // and needs to be updated if (xd->segmentation_enabled && xd->update_mb_segmentation_map) { diff --git a/media/libvpx/libvpx/vp8/encoder/encodemb.c b/media/libvpx/libvpx/vp8/encoder/encodemb.c --- a/media/libvpx/libvpx/vp8/encoder/encodemb.c +++ b/media/libvpx/libvpx/vp8/encoder/encodemb.c @@ -394,12 +394,12 @@ ENTROPY_CONTEXT_PLANES t_above, t_left; ENTROPY_CONTEXT *ta; ENTROPY_CONTEXT *tl; - memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *x->e_mbd.above_context; + t_left = *x->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED && @@ -435,12 +435,12 @@ if (!x->e_mbd.above_context) return; if (!x->e_mbd.left_context) return; - memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *x->e_mbd.above_context; + t_left = *x->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; has_2nd_order = (x->e_mbd.mode_info_context->mbmi.mode != B_PRED && @@ -468,12 +468,12 @@ if (!x->e_mbd.above_context) return; if (!x->e_mbd.left_context) return; - memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *x->e_mbd.above_context; + t_left = *x->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; for (b = 16; b < 24; ++b) { diff --git a/media/libvpx/libvpx/vp8/encoder/firstpass.c b/media/libvpx/libvpx/vp8/encoder/firstpass.c --- a/media/libvpx/libvpx/vp8/encoder/firstpass.c +++ b/media/libvpx/libvpx/vp8/encoder/firstpass.c @@ -52,11 +52,11 @@ #define GF_RMAX 48.0 #define KF_MB_INTRA_MIN 300 #define GF_MB_INTRA_MIN 200 -#define DOUBLE_DIVIDE_CHECK(X) ((X) < 0 ? (X)-.000001 : (X) + .000001) +#define DOUBLE_DIVIDE_CHECK(X) ((X) < 0 ? (X) - .000001 : (X) + .000001) #define POW1 (double)cpi->oxcf.two_pass_vbrbias / 100.0 #define POW2 (double)cpi->oxcf.two_pass_vbrbias / 100.0 #define NEW_BOOST 1 @@ -793,11 +793,11 @@ * than the full time between subsequent cpi->source_time_stamps */ fps.duration = (double)(cpi->source->ts_end - cpi->source->ts_start); /* don't want to do output stats with a stack variable! */ - memcpy(&cpi->twopass.this_frame_stats, &fps, sizeof(FIRSTPASS_STATS)); + cpi->twopass.this_frame_stats = fps; output_stats(cpi->output_pkt_list, &cpi->twopass.this_frame_stats); accumulate_stats(&cpi->twopass.total_stats, &fps); } /* Copy the previous Last Frame into the GF buffer if specific @@ -1698,11 +1698,11 @@ ((boost_score - old_boost_score) < 2.0)))) { boost_score = old_boost_score; break; } - memcpy(this_frame, &next_frame, sizeof(*this_frame)); + *this_frame = next_frame; old_boost_score = boost_score; } cpi->twopass.gf_decay_rate = @@ -2234,11 +2234,11 @@ this_frame_coded_error = this_frame.coded_error; /* keyframe and section processing ! */ if (cpi->twopass.frames_to_key == 0) { /* Define next KF group and assign bits to it */ - memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + this_frame_copy = this_frame; find_next_key_frame(cpi, &this_frame_copy); /* Special case: Error error_resilient_mode mode does not make much * sense for two pass but with its current meaning this code is * designed to stop outlandish behaviour if someone does set it when @@ -2256,11 +2256,11 @@ } /* Is this a GF / ARF (Note that a KF is always also a GF) */ if (cpi->frames_till_gf_update_due == 0) { /* Define next gf group and assign bits to it */ - memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + this_frame_copy = this_frame; define_gf_group(cpi, &this_frame_copy); /* If we are going to code an altref frame at the end of the group * and the current frame is not a key frame.... If the previous * group used an arf this frame has already benefited from that arf @@ -2271,11 +2271,11 @@ if (cpi->source_alt_ref_pending && (cpi->common.frame_type != KEY_FRAME)) { /* Assign a standard frames worth of bits from those allocated * to the GF group */ int bak = cpi->per_frame_bandwidth; - memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + this_frame_copy = this_frame; assign_std_frame_bits(cpi, &this_frame_copy); cpi->per_frame_bandwidth = bak; } } @@ -2291,16 +2291,16 @@ if (cpi->oxcf.error_resilient_mode) { cpi->frames_till_gf_update_due = cpi->twopass.frames_to_key; if (cpi->common.frame_type != KEY_FRAME) { /* Assign bits from those allocated to the GF group */ - memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + this_frame_copy = this_frame; assign_std_frame_bits(cpi, &this_frame_copy); } } else { /* Assign bits from those allocated to the GF group */ - memcpy(&this_frame_copy, &this_frame, sizeof(this_frame)); + this_frame_copy = this_frame; assign_std_frame_bits(cpi, &this_frame_copy); } } /* Keep a globally available copy of this and the next frame's iiratio. */ @@ -2428,11 +2428,11 @@ double boost_score = 0.0; double old_boost_score = 0.0; double decay_accumulator = 1.0; double next_iiratio; - memcpy(&local_next_frame, next_frame, sizeof(*next_frame)); + local_next_frame = *next_frame; /* Note the starting file position so we can reset to it */ start_pos = cpi->twopass.stats_in; /* Examine how well the key frame predicts subsequent frames */ @@ -2521,11 +2521,11 @@ cpi->frames_till_gf_update_due = 0; cpi->twopass.frames_to_key = 1; /* Take a copy of the initial frame details */ - memcpy(&first_frame, this_frame, sizeof(*this_frame)); + first_frame = *this_frame; cpi->twopass.kf_group_bits = 0; cpi->twopass.kf_group_error_left = 0; kf_mod_err = calculate_modified_err(cpi, this_frame); @@ -2543,11 +2543,11 @@ */ kf_group_intra_err += this_frame->intra_error; kf_group_coded_err += this_frame->coded_error; /* Load the next frame's stats. */ - memcpy(&last_frame, this_frame, sizeof(*this_frame)); + last_frame = *this_frame; input_stats(cpi, this_frame); /* Provided that we are not at the end of the file... */ if (cpi->oxcf.auto_key && lookup_next_frame_stats(cpi, &next_frame) != EOF) { @@ -2606,11 +2606,11 @@ FIRSTPASS_STATS tmp_frame; cpi->twopass.frames_to_key /= 2; /* Copy first frame details */ - memcpy(&tmp_frame, &first_frame, sizeof(first_frame)); + tmp_frame = first_frame; /* Reset to the start of the group */ reset_fpf_position(cpi, start_position); kf_group_err = 0; diff --git a/media/libvpx/libvpx/vp8/encoder/mcomp.c b/media/libvpx/libvpx/vp8/encoder/mcomp.c --- a/media/libvpx/libvpx/vp8/encoder/mcomp.c +++ b/media/libvpx/libvpx/vp8/encoder/mcomp.c @@ -186,18 +186,19 @@ * 32 cols area that is enough for 16x16 macroblock. Later, for SPLITMV, we * could reduce the area. */ /* estimated cost of a motion vector (r,c) */ -#define MVC(r, c) \ - (mvcost \ - ? ((mvcost[0][(r)-rr] + mvcost[1][(c)-rc]) * error_per_bit + 128) >> 8 \ - : 0) +#define MVC(r, c) \ + (mvcost ? ((mvcost[0][(r) - rr] + mvcost[1][(c) - rc]) * error_per_bit + \ + 128) >> \ + 8 \ + : 0) /* pointer to predictor base of a motionvector */ #define PRE(r, c) (y + (((r) >> 2) * y_stride + ((c) >> 2) - (offset))) /* convert motion vector component to offset for svf calc */ -#define SP(x) (((x)&3) << 1) +#define SP(x) (((x) & 3) << 1) /* returns subpixel variance error function. */ #define DIST(r, c) \ vfp->svf(PRE(r, c), y_stride, SP(c), SP(r), z, b->src_stride, &sse) #define IFMVCV(r, c, s, e) \ if (c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; diff --git a/media/libvpx/libvpx/vp8/encoder/onyx_if.c b/media/libvpx/libvpx/vp8/encoder/onyx_if.c --- a/media/libvpx/libvpx/vp8/encoder/onyx_if.c +++ b/media/libvpx/libvpx/vp8/encoder/onyx_if.c @@ -21,10 +21,11 @@ #include "vp8/encoder/quantize.h" #include "vp8/common/alloccommon.h" #include "mcomp.h" #include "firstpass.h" #include "vpx_dsp/psnr.h" +#include "vpx_dsp/vpx_dsp_common.h" #include "vpx_scale/vpx_scale.h" #include "vp8/common/extend.h" #include "ratectrl.h" #include "vp8/common/quant_common.h" #include "segmentation.h" @@ -1259,13 +1260,20 @@ if (q_trans[i] >= x) return i; } return 63; } + +static double clamp_framerate(double framerate) { + if (framerate < .1) + return 30.0; + else + return framerate; +} + void vp8_new_framerate(VP8_COMP *cpi, double framerate) { - if (framerate < .1) framerate = 30; - + framerate = clamp_framerate(framerate); cpi->framerate = framerate; cpi->output_framerate = framerate; const double per_frame_bandwidth = round(cpi->oxcf.target_bandwidth / cpi->output_framerate); cpi->per_frame_bandwidth = (int)VPXMIN(per_frame_bandwidth, INT_MAX); @@ -1872,12 +1880,11 @@ cpi->gf_interval_onepass_cbr = cpi->cyclic_refresh_mode_max_mbs_perframe > 0 ? (2 * (cpi->common.mb_rows * cpi->common.mb_cols) / cpi->cyclic_refresh_mode_max_mbs_perframe) : 10; - cpi->gf_interval_onepass_cbr = - VPXMIN(40, VPXMAX(6, cpi->gf_interval_onepass_cbr)); + cpi->gf_interval_onepass_cbr = clamp(cpi->gf_interval_onepass_cbr, 6, 40); cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr; } if (cpi->cyclic_refresh_mode_enabled) { CHECK_MEM_ERROR(&cpi->common.error, cpi->cyclic_refresh_map, @@ -3138,15 +3145,19 @@ } if (cm->no_lpf) { cm->filter_level = 0; } else { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif vpx_clear_system_state(); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (cpi->sf.auto_filter == 0) { #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity && cm->frame_type != KEY_FRAME) { // Use the denoised buffer for selecting base loop filter level. // Denoised signal for current frame is stored in INTRA_FRAME. @@ -3177,12 +3188,14 @@ if (cm->filter_level > 0) { vp8cx_set_alt_lf_level(cpi, cm->filter_level); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); +#endif } #if CONFIG_MULTITHREAD if (vpx_atomic_load_acquire(&cpi->b_multi_threaded)) { /* signal that we have set filter_level */ @@ -3934,11 +3947,11 @@ if (cm->frame_type == KEY_FRAME) cm->refresh_entropy_probs = 1; } if (cm->refresh_entropy_probs == 0) { /* save a copy for later refresh */ - memcpy(&cm->lfc, &cm->fc, sizeof(cm->fc)); + cm->lfc = cm->fc; } vp8_update_coef_context(cpi); vp8_update_coef_probs(cpi); @@ -4782,14 +4795,18 @@ #endif int vp8_receive_raw_frame(VP8_COMP *cpi, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif int res = 0; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif /* Reinit the lookahead buffer if the frame size changes */ if (sd->y_width != cpi->oxcf.Width || sd->y_height != cpi->oxcf.Height) { assert(cpi->oxcf.lag_in_frames < 2); dealloc_raw_frame_buffers(cpi); @@ -4798,12 +4815,14 @@ if (vp8_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags, cpi->active_map_enabled ? cpi->active_map : NULL)) { res = -1; } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); +#endif return res; } static int frame_is_reference(const VP8_COMP *cpi) { @@ -4820,20 +4839,23 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, size_t *size, unsigned char *dest, unsigned char *dest_end, int64_t *time_stamp, int64_t *time_end, int flush) { VP8_COMMON *cm; - struct vpx_usec_timer tsctimer; struct vpx_usec_timer ticktimer; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer cmptimer; +#endif YV12_BUFFER_CONFIG *force_src_buffer = NULL; if (!cpi) return -1; cm = &cpi->common; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&cmptimer); +#endif cpi->source = NULL; #if !CONFIG_REALTIME_ONLY /* Should we code an alternate reference frame */ @@ -4966,10 +4988,11 @@ // The base stream is being encoded so set skip flag to 0. low_res_frame_info->skip_encoding_base_stream = 0; } } #endif + cpi->ref_framerate = clamp_framerate(cpi->ref_framerate); if (cpi->oxcf.number_of_layers > 1) { unsigned int i; /* Update frame rates for each layer */ assert(cpi->oxcf.number_of_layers <= VPX_TS_MAX_LAYERS); @@ -5003,11 +5026,10 @@ vp8_restore_layer_context(cpi, layer); vp8_new_framerate(cpi, cpi->layer_context[layer].framerate); } if (cpi->compressor_speed == 2) { - vpx_usec_timer_start(&tsctimer); vpx_usec_timer_start(&ticktimer); } cpi->lf_zeromv_pct = (cpi->zeromv_count * 100) / cm->MBs; @@ -5078,11 +5100,10 @@ break; } if (cpi->compressor_speed == 2) { unsigned int duration, duration2; - vpx_usec_timer_mark(&tsctimer); vpx_usec_timer_mark(&ticktimer); duration = (int)(vpx_usec_timer_elapsed(&ticktimer)); duration2 = (unsigned int)((double)duration / 2); @@ -5105,20 +5126,20 @@ } } } if (cm->refresh_entropy_probs == 0) { - memcpy(&cm->fc, &cm->lfc, sizeof(cm->fc)); + cm->fc = cm->lfc; } /* Save the contexts separately for alt ref, gold and last. */ /* (TODO jbb -> Optimize this with pointers to avoid extra copies. ) */ - if (cm->refresh_alt_ref_frame) memcpy(&cpi->lfc_a, &cm->fc, sizeof(cm->fc)); - - if (cm->refresh_golden_frame) memcpy(&cpi->lfc_g, &cm->fc, sizeof(cm->fc)); - - if (cm->refresh_last_frame) memcpy(&cpi->lfc_n, &cm->fc, sizeof(cm->fc)); + if (cm->refresh_alt_ref_frame) cpi->lfc_a = cm->fc; + + if (cm->refresh_golden_frame) cpi->lfc_g = cm->fc; + + if (cm->refresh_last_frame) cpi->lfc_n = cm->fc; /* if it's a dropped frame honor the requests on subsequent frames */ if (*size > 0) { cpi->droppable = !frame_is_reference(cpi); @@ -5131,12 +5152,14 @@ } /* Save layer specific state */ if (cpi->oxcf.number_of_layers > 1) vp8_save_layer_context(cpi); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&cmptimer); cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); +#endif #if CONFIG_MULTITHREAD /* wait for the lpf thread done */ if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) && cpi->b_lpf_running) { vp8_sem_wait(&cpi->h_event_end_lpf); diff --git a/media/libvpx/libvpx/vp8/encoder/onyx_int.h b/media/libvpx/libvpx/vp8/encoder/onyx_int.h --- a/media/libvpx/libvpx/vp8/encoder/onyx_int.h +++ b/media/libvpx/libvpx/vp8/encoder/onyx_int.h @@ -554,14 +554,16 @@ fractional_mv_step_fp *find_fractional_mv_step; vp8_refining_search_fn_t refining_search_sad; vp8_diamond_search_fn_t diamond_search_sad; vp8_variance_fn_ptr_t fn_ptr[BLOCK_MAX_SEGMENTS]; +#if CONFIG_INTERNAL_STATS uint64_t time_receive_data; uint64_t time_compress_data; uint64_t time_pick_lpf; uint64_t time_encode_mb_row; +#endif int base_skip_false_prob[128]; FRAME_CONTEXT lfc_n; /* last frame entropy */ FRAME_CONTEXT lfc_a; /* last alt ref entropy */ diff --git a/media/libvpx/libvpx/vp8/encoder/ratectrl.c b/media/libvpx/libvpx/vp8/encoder/ratectrl.c --- a/media/libvpx/libvpx/vp8/encoder/ratectrl.c +++ b/media/libvpx/libvpx/vp8/encoder/ratectrl.c @@ -257,13 +257,13 @@ } /* Make sure we initialize separate contexts for altref,gold, and normal. * TODO shouldn't need 3 different copies of structure to do this! */ - memcpy(&cpi->lfc_a, &cpi->common.fc, sizeof(cpi->common.fc)); - memcpy(&cpi->lfc_g, &cpi->common.fc, sizeof(cpi->common.fc)); - memcpy(&cpi->lfc_n, &cpi->common.fc, sizeof(cpi->common.fc)); + cpi->lfc_a = cpi->common.fc; + cpi->lfc_g = cpi->common.fc; + cpi->lfc_n = cpi->common.fc; cpi->common.filter_level = cpi->common.base_qindex * 3 / 8; /* Provisional interval before next GF */ if (cpi->auto_gold) { @@ -641,15 +641,14 @@ if ((cpi->last_boost > 150) && (cpi->frames_till_gf_update_due > 0) && (cpi->current_gf_interval >= (MIN_GF_INTERVAL << 1))) { /* % Adjustment limited to the range 1% to 10% */ Adjustment = (cpi->last_boost - 100) >> 5; - if (Adjustment < 1) { - Adjustment = 1; - } else if (Adjustment > 10) { + if (Adjustment > 10) { Adjustment = 10; } + assert(Adjustment >= 1); /* Convert to bits */ Adjustment = (cpi->this_frame_target * Adjustment) / 100; if (Adjustment > (cpi->this_frame_target - min_frame_target)) { diff --git a/media/libvpx/libvpx/vp8/encoder/rdopt.c b/media/libvpx/libvpx/vp8/encoder/rdopt.c --- a/media/libvpx/libvpx/vp8/encoder/rdopt.c +++ b/media/libvpx/libvpx/vp8/encoder/rdopt.c @@ -449,12 +449,12 @@ MACROBLOCKD *x = &mb->e_mbd; ENTROPY_CONTEXT_PLANES t_above, t_left; ENTROPY_CONTEXT *ta; ENTROPY_CONTEXT *tl; - memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *mb->e_mbd.above_context; + t_left = *mb->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; for (b = 0; b < 16; ++b) { @@ -595,12 +595,12 @@ ENTROPY_CONTEXT_PLANES t_above, t_left; ENTROPY_CONTEXT *ta; ENTROPY_CONTEXT *tl; const int *bmode_costs; - memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *mb->e_mbd.above_context; + t_left = *mb->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; intra_prediction_down_copy(xd, xd->dst.y_buffer - xd->dst.y_stride + 16); @@ -687,12 +687,12 @@ MACROBLOCKD *x = &mb->e_mbd; ENTROPY_CONTEXT_PLANES t_above, t_left; ENTROPY_CONTEXT *ta; ENTROPY_CONTEXT *tl; - memcpy(&t_above, mb->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, mb->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *mb->e_mbd.above_context; + t_left = *mb->e_mbd.left_context; ta = (ENTROPY_CONTEXT *)&t_above; tl = (ENTROPY_CONTEXT *)&t_left; for (b = 16; b < 24; ++b) { @@ -960,12 +960,12 @@ vp8_variance_fn_ptr_t *v_fn_ptr; ENTROPY_CONTEXT_PLANES t_above, t_left; ENTROPY_CONTEXT_PLANES t_above_b, t_left_b; - memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = *x->e_mbd.above_context; + t_left = *x->e_mbd.left_context; vp8_zero(t_above_b); vp8_zero(t_left_b); br = 0; @@ -1001,12 +1001,12 @@ int labelyrate; ENTROPY_CONTEXT_PLANES t_above_s, t_left_s; ENTROPY_CONTEXT *ta_s; ENTROPY_CONTEXT *tl_s; - memcpy(&t_above_s, &t_above, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left_s, &t_left, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above_s = t_above; + t_left_s = t_left; ta_s = (ENTROPY_CONTEXT *)&t_above_s; tl_s = (ENTROPY_CONTEXT *)&t_left_s; if (this_mode == NEW4X4) { @@ -1144,17 +1144,17 @@ sbd = distortion; bestlabelyrate = labelyrate; mode_selected = this_mode; best_label_rd = this_rd; - memcpy(&t_above_b, &t_above_s, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left_b, &t_left_s, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above_b = t_above_s; + t_left_b = t_left_s; } } /*for each 4x4 mode*/ - memcpy(&t_above, &t_above_b, sizeof(ENTROPY_CONTEXT_PLANES)); - memcpy(&t_left, &t_left_b, sizeof(ENTROPY_CONTEXT_PLANES)); + t_above = t_above_b; + t_left = t_left_b; labels2mode(x, labels, i, mode_selected, &mode_mv[mode_selected], bsi->ref_mv, x->mvcost); br += sbr; @@ -1734,13 +1734,12 @@ best_mode->yrd = RDCOST(x->rdmult, x->rddiv, (rd->rate2 - rd->rate_uv - other_cost), (rd->distortion2 - rd->distortion_uv)); best_mode->rd = this_rd; - memcpy(&best_mode->mbmode, &x->e_mbd.mode_info_context->mbmi, - sizeof(MB_MODE_INFO)); - memcpy(&best_mode->partition, x->partition_info, sizeof(PARTITION_INFO)); + best_mode->mbmode = x->e_mbd.mode_info_context->mbmi; + best_mode->partition = *x->partition_info; if ((this_mode == B_PRED) || (this_mode == SPLITMV)) { int i; for (i = 0; i < 16; ++i) { best_mode->bmodes[i] = x->e_mbd.block[i].bmi; @@ -2346,12 +2345,11 @@ x->e_mbd.mode_info_context->mbmi.partitioning = 0; return; } /* macroblock modes */ - memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mode.mbmode, - sizeof(MB_MODE_INFO)); + x->e_mbd.mode_info_context->mbmi = best_mode.mbmode; if (best_mode.mbmode.mode == B_PRED) { for (i = 0; i < 16; ++i) { xd->mode_info_context->bmi[i].as_mode = best_mode.bmodes[i].as_mode; } @@ -2360,11 +2358,11 @@ if (best_mode.mbmode.mode == SPLITMV) { for (i = 0; i < 16; ++i) { xd->mode_info_context->bmi[i].mv.as_int = best_mode.bmodes[i].mv.as_int; } - memcpy(x->partition_info, &best_mode.partition, sizeof(PARTITION_INFO)); + *x->partition_info = best_mode.partition; x->e_mbd.mode_info_context->mbmi.mv.as_int = x->partition_info->bmi[15].mv.as_int; } diff --git a/media/libvpx/libvpx/vp8/vp8_cx_iface.c b/media/libvpx/libvpx/vp8/vp8_cx_iface.c --- a/media/libvpx/libvpx/vp8/vp8_cx_iface.c +++ b/media/libvpx/libvpx/vp8/vp8_cx_iface.c @@ -6,10 +6,11 @@ * 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 #include #include #include @@ -55,11 +56,11 @@ static struct vp8_extracfg default_extracfg = { NULL, #if !(CONFIG_REALTIME_ONLY) 0, /* cpu_used */ #else - 4, /* cpu_used */ + 4, /* cpu_used */ #endif 0, /* enable_auto_alt_ref */ 0, /* noise_sensitivity */ 0, /* Sharpness */ 0, /* static_thresh */ @@ -394,12 +395,11 @@ * situation. */ if (mr_cfg) { oxcf->mr_total_resolutions = mr_cfg->mr_total_resolutions; oxcf->mr_encoder_id = mr_cfg->mr_encoder_id; - oxcf->mr_down_sampling_factor.num = mr_cfg->mr_down_sampling_factor.num; - oxcf->mr_down_sampling_factor.den = mr_cfg->mr_down_sampling_factor.den; + oxcf->mr_down_sampling_factor = mr_cfg->mr_down_sampling_factor; oxcf->mr_low_res_mode_info = mr_cfg->mr_low_res_mode_info; } #else (void)mr_cfg; #endif @@ -665,15 +665,26 @@ *mem_loc = (void *)shared_mem_loc; res = VPX_CODEC_OK; } #else (void)cfg; - (void)mem_loc; + *mem_loc = NULL; #endif return res; } +static void vp8e_mr_free_mem(void *mem_loc) { +#if CONFIG_MULTI_RES_ENCODING + LOWER_RES_FRAME_INFO *shared_mem_loc = (LOWER_RES_FRAME_INFO *)mem_loc; + free(shared_mem_loc->mb_info); + free(mem_loc); +#else + (void)mem_loc; + assert(!mem_loc); +#endif +} + static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx, vpx_codec_priv_enc_mr_cfg_t *mr_cfg) { vpx_codec_err_t res = VPX_CODEC_OK; vp8_rtcd(); @@ -730,11 +741,21 @@ priv->timestamp_ratio.num *= TICKS_PER_SEC; reduce_ratio(&priv->timestamp_ratio); set_vp8e_config(&priv->oxcf, priv->cfg, priv->vp8_cfg, mr_cfg); priv->cpi = vp8_create_compressor(&priv->oxcf); - if (!priv->cpi) res = VPX_CODEC_MEM_ERROR; + if (!priv->cpi) { +#if CONFIG_MULTI_RES_ENCODING + // Release ownership of mr_cfg->mr_low_res_mode_info on failure. This + // prevents ownership confusion with the caller and avoids a double + // free when vpx_codec_destroy() is called on this instance. + priv->oxcf.mr_total_resolutions = 0; + priv->oxcf.mr_encoder_id = 0; + priv->oxcf.mr_low_res_mode_info = NULL; +#endif + res = VPX_CODEC_MEM_ERROR; + } } } return res; } @@ -742,14 +763,11 @@ static vpx_codec_err_t vp8e_destroy(vpx_codec_alg_priv_t *ctx) { #if CONFIG_MULTI_RES_ENCODING /* Free multi-encoder shared memory */ if (ctx->oxcf.mr_total_resolutions > 0 && (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions - 1)) { - LOWER_RES_FRAME_INFO *shared_mem_loc = - (LOWER_RES_FRAME_INFO *)ctx->oxcf.mr_low_res_mode_info; - free(shared_mem_loc->mb_info); - free(ctx->oxcf.mr_low_res_mode_info); + vp8e_mr_free_mem(ctx->oxcf.mr_low_res_mode_info); } #endif free(ctx->cx_data); vp8_remove_compressor(&ctx->cpi); @@ -923,11 +941,11 @@ flags |= VPX_EFLAG_FORCE_KF; ctx->fixed_kf_cntr = 1; } } - /* Initialize the encoder instance on the first frame*/ + /* Initialize the encoder instance on the first frame */ if (!res && ctx->cpi) { unsigned int lib_flags; int64_t dst_time_stamp, dst_end_time_stamp; size_t size, cx_data_sz; unsigned char *cx_data; @@ -940,14 +958,24 @@ vpx_clear_system_state(); return res; } ctx->cpi->common.error.setjmp = 1; + // Per-frame PSNR is not supported when g_lag_in_frames is greater than 0. + if ((flags & VPX_EFLAG_CALCULATE_PSNR) && ctx->cfg.g_lag_in_frames != 0) { + vpx_internal_error( + &ctx->cpi->common.error, VPX_CODEC_INCAPABLE, + "Cannot calculate per-frame PSNR when g_lag_in_frames is nonzero"); + } /* Set up internal flags */ - if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) { - ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1; - } +#if CONFIG_INTERNAL_STATS + assert(((VP8_COMP *)ctx->cpi)->b_calculate_psnr == 1); +#else + ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = + (ctx->base.init_flags & VPX_CODEC_USE_PSNR) || + (flags & VPX_EFLAG_CALCULATE_PSNR); +#endif if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION) { ((VP8_COMP *)ctx->cpi)->output_partition = 1; } @@ -992,23 +1020,14 @@ dst_end_time_stamp = pts_end * ctx->timestamp_ratio.num / ctx->timestamp_ratio.den; res = image2yuvconfig(img, &sd); - if (sd.y_width != ctx->cfg.g_w || sd.y_height != ctx->cfg.g_h) { - /* from vpx_encoder.h for g_w/g_h: - "Note that the frames passed as input to the encoder must have this - resolution" - */ - ctx->base.err_detail = "Invalid input frame resolution"; - res = VPX_CODEC_INVALID_PARAM; - } else { - if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, - &sd, dst_time_stamp, dst_end_time_stamp)) { - VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; - res = update_error_state(ctx, &cpi->common.error); - } + if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, &sd, + dst_time_stamp, dst_end_time_stamp)) { + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + res = update_error_state(ctx, &cpi->common.error); } /* reset for next frame */ ctx->next_frame_flag = 0; } @@ -1428,7 +1447,8 @@ vp8e_get_cxdata, /* vpx_codec_get_cx_data_fn_t get_cx_data; */ vp8e_set_config, NULL, vp8e_get_preview, vp8e_mr_alloc_mem, + vp8e_mr_free_mem, } /* encoder functions */ }; diff --git a/media/libvpx/libvpx/vp8/vp8_dx_iface.c b/media/libvpx/libvpx/vp8/vp8_dx_iface.c --- a/media/libvpx/libvpx/vp8/vp8_dx_iface.c +++ b/media/libvpx/libvpx/vp8/vp8_dx_iface.c @@ -745,8 +745,9 @@ NULL, /* vpx_codec_encode_fn_t */ NULL, /* vpx_codec_get_cx_data_fn_t */ NULL, /* vpx_codec_enc_config_set_fn_t */ NULL, /* vpx_codec_get_global_headers_fn_t */ NULL, /* vpx_codec_get_preview_frame_fn_t */ - NULL /* vpx_codec_enc_mr_get_mem_loc_fn_t */ + NULL, /* vpx_codec_enc_mr_get_mem_loc_fn_t */ + NULL /* vpx_codec_enc_mr_free_mem_loc_fn_t */ } }; diff --git a/media/libvpx/libvpx/vp9/common/vp9_blockd.h b/media/libvpx/libvpx/vp9/common/vp9_blockd.h --- a/media/libvpx/libvpx/vp9/common/vp9_blockd.h +++ b/media/libvpx/libvpx/vp9/common/vp9_blockd.h @@ -140,11 +140,11 @@ const int16_t *dequant; int *eob; }; -#define BLOCK_OFFSET(x, i) ((x) + (i)*16) +#define BLOCK_OFFSET(x, i) ((x) + (i) * 16) typedef struct RefBuffer { // TODO(dkovalev): idx is not really required and should be removed, now it // is used in vp9_onyxd_if.c int idx; diff --git a/media/libvpx/libvpx/vp9/common/vp9_entropymode.h b/media/libvpx/libvpx/vp9/common/vp9_entropymode.h --- a/media/libvpx/libvpx/vp9/common/vp9_entropymode.h +++ b/media/libvpx/libvpx/vp9/common/vp9_entropymode.h @@ -22,11 +22,11 @@ #define BLOCK_SIZE_GROUPS 4 #define TX_SIZE_CONTEXTS 2 -#define INTER_OFFSET(mode) ((mode)-NEARESTMV) +#define INTER_OFFSET(mode) ((mode) - NEARESTMV) struct VP9Common; struct tx_probs { vpx_prob p32x32[TX_SIZE_CONTEXTS][TX_SIZES - 1]; diff --git a/media/libvpx/libvpx/vp9/common/vp9_postproc.h b/media/libvpx/libvpx/vp9/common/vp9_postproc.h --- a/media/libvpx/libvpx/vp9/common/vp9_postproc.h +++ b/media/libvpx/libvpx/vp9/common/vp9_postproc.h @@ -28,10 +28,11 @@ int last_frame_valid; MODE_INFO *prev_mip; MODE_INFO *prev_mi; int clamp; uint8_t *limits; + int limits_size; int8_t *generated_noise; }; struct VP9Common; diff --git a/media/libvpx/libvpx/vp9/common/vp9_postproc.c b/media/libvpx/libvpx/vp9/common/vp9_postproc.c --- a/media/libvpx/libvpx/vp9/common/vp9_postproc.c +++ b/media/libvpx/libvpx/vp9/common/vp9_postproc.c @@ -117,12 +117,12 @@ uint16_t *s = src; uint16_t d[16]; for (r = 0; r < rows; r++) { - int sumsq = 0; - int sum = 0; + int64_t sumsq = 0; + int64_t sum = 0; for (i = -8; i <= 6; i++) { sumsq += s[i] * s[i]; sum += s[i]; d[i + 8] = 0; @@ -155,12 +155,12 @@ int r, c, i; const int16_t *rv3 = &vpx_rv[63 & rand()]; // NOLINT for (c = 0; c < cols; c++) { uint16_t *s = &dst[c]; - int sumsq = 0; - int sum = 0; + int64_t sumsq = 0; + int64_t sum = 0; uint16_t d[16]; const int16_t *rv2 = rv3 + ((c * 17) & 127); for (i = -8; i <= 6; i++) { sumsq += s[i * pitch] * s[i * pitch]; @@ -252,12 +252,11 @@ } } else { #endif // CONFIG_VP9_HIGHBITDEPTH int mbr; const int mb_rows = cm->mb_rows; - const int mb_cols = cm->mb_cols; - memset(limits, (unsigned char)ppl, 16 * mb_cols); + memset(limits, (unsigned char)ppl, cm->postproc_state.limits_size); for (mbr = 0; mbr < mb_rows; mbr++) { vpx_post_proc_down_and_across_mb_row( src->y_buffer + 16 * mbr * src->y_stride, dst->y_buffer + 16 * mbr * dst->y_stride, src->y_stride, @@ -296,10 +295,11 @@ vp9_ppflags_t *ppflags, int unscaled_width) { const int q = VPXMIN(105, cm->lf.filter_level * 2); const int flags = ppflags->post_proc_flag; YV12_BUFFER_CONFIG *const ppbuf = &cm->post_proc_buffer; struct postproc_state *const ppstate = &cm->postproc_state; + ppstate->limits_size = unscaled_width; if (!cm->frame_to_show) return -1; if (!flags) { *dest = *cm->frame_to_show; @@ -340,11 +340,11 @@ } // Ensure that postproc is set to all 0s so that post proc // doesn't pull random data in from edge. memset(cm->post_proc_buffer_int.buffer_alloc, 128, - cm->post_proc_buffer.frame_size); + cm->post_proc_buffer_int.frame_size); } } if (vpx_realloc_frame_buffer(&cm->post_proc_buffer, cm->width, cm->height, cm->subsampling_x, cm->subsampling_y, @@ -357,11 +357,11 @@ "Failed to allocate post-processing buffer"); if (flags & (VP9D_DEMACROBLOCK | VP9D_DEBLOCK)) { if (!cm->postproc_state.limits) { cm->postproc_state.limits = - vpx_calloc(unscaled_width, sizeof(*cm->postproc_state.limits)); + vpx_calloc(ppstate->limits_size, sizeof(*cm->postproc_state.limits)); if (!cm->postproc_state.limits) return 1; } } if (flags & VP9D_ADDNOISE) { diff --git a/media/libvpx/libvpx/vp9/common/vp9_rtcd_defs.pl b/media/libvpx/libvpx/vp9/common/vp9_rtcd_defs.pl --- a/media/libvpx/libvpx/vp9/common/vp9_rtcd_defs.pl +++ b/media/libvpx/libvpx/vp9/common/vp9_rtcd_defs.pl @@ -204,17 +204,17 @@ add_proto qw/void vpx_convolve12/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h"; specialize qw/vpx_convolve12 ssse3 avx2 neon neon_dotprod neon_i8mm/; if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") { add_proto qw/void vpx_highbd_convolve12_vert/, "const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h, int bd"; - specialize qw/vpx_highbd_convolve12_vert ssse3 avx2/; + specialize qw/vpx_highbd_convolve12_vert ssse3 avx2 neon sve2/; add_proto qw/void vpx_highbd_convolve12_horiz/, "const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h, int bd"; - specialize qw/vpx_highbd_convolve12_horiz ssse3 avx2/; + specialize qw/vpx_highbd_convolve12_horiz ssse3 avx2 neon sve2/; add_proto qw/void vpx_highbd_convolve12/, "const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h, int bd"; - specialize qw/vpx_highbd_convolve12 ssse3 avx2/; + specialize qw/vpx_highbd_convolve12 ssse3 avx2 neon sve2/; } } if (vpx_config("CONFIG_VP9_HIGHBITDEPTH") eq "yes") { diff --git a/media/libvpx/libvpx/vp9/common/vp9_thread_common.c b/media/libvpx/libvpx/vp9/common/vp9_thread_common.c --- a/media/libvpx/libvpx/vp9/common/vp9_thread_common.c +++ b/media/libvpx/libvpx/vp9/common/vp9_thread_common.c @@ -17,34 +17,17 @@ #include "vp9/common/vp9_entropymode.h" #include "vp9/common/vp9_thread_common.h" #include "vp9/common/vp9_reconinter.h" #include "vp9/common/vp9_loopfilter.h" -#if CONFIG_MULTITHREAD -static INLINE void mutex_lock(pthread_mutex_t *const mutex) { - const int kMaxTryLocks = 4000; - int locked = 0; - int i; - - for (i = 0; i < kMaxTryLocks; ++i) { - if (!pthread_mutex_trylock(mutex)) { - locked = 1; - break; - } - } - - if (!locked) pthread_mutex_lock(mutex); -} -#endif // CONFIG_MULTITHREAD - static INLINE void sync_read(VP9LfSync *const lf_sync, int r, int c) { #if CONFIG_MULTITHREAD const int nsync = lf_sync->sync_range; if (r && !(c & (nsync - 1))) { pthread_mutex_t *const mutex = &lf_sync->mutex[r - 1]; - mutex_lock(mutex); + pthread_mutex_lock(mutex); while (c > lf_sync->cur_sb_col[r - 1] - nsync) { pthread_cond_wait(&lf_sync->cond[r - 1], mutex); } pthread_mutex_unlock(mutex); @@ -70,11 +53,11 @@ } else { cur = sb_cols + nsync; } if (sig) { - mutex_lock(&lf_sync->mutex[r]); + pthread_mutex_lock(&lf_sync->mutex[r]); lf_sync->cur_sb_col[r] = cur; pthread_cond_signal(&lf_sync->cond[r]); pthread_mutex_unlock(&lf_sync->mutex[r]); diff --git a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_neon.c b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_neon.c --- a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_neon.c +++ b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_neon.c @@ -12,10 +12,12 @@ #include #include "./vp9_rtcd.h" #include "./vpx_config.h" #include "vpx/vpx_integer.h" +#include "vpx_dsp/arm/mem_neon.h" +#include "vpx_dsp/arm/transpose_neon.h" #include "vp9/encoder/vp9_encoder.h" #include "vp9/encoder/vp9_temporal_filter.h" #include "vp9/encoder/vp9_temporal_filter_constants.h" // Compute (a-b)**2 for 8 pixels with size 16-bit @@ -868,5 +870,207 @@ highbd_apply_temporal_filter_chroma( u_pre, v_pre, 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); } + +static INLINE uint16x8_t highbd_convolve12_8( + const int16x8_t s0, const int16x8_t s1, const int16x8_t s2, + const int16x8_t s3, const int16x8_t s4, const int16x8_t s5, + const int16x8_t s6, const int16x8_t s7, const int16x8_t s8, + const int16x8_t s9, const int16x8_t sA, const int16x8_t sB, + const int16x8_t filter_0_7, const int16x4_t filter_8_11, uint16x8_t max) { + const int16x4_t filter_0_3 = vget_low_s16(filter_0_7); + const int16x4_t filter_4_7 = vget_high_s16(filter_0_7); + + int32x4_t sum_lo = vmull_lane_s16(vget_low_s16(s0), filter_0_3, 0); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s1), filter_0_3, 1); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s2), filter_0_3, 2); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s3), filter_0_3, 3); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s4), filter_4_7, 0); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s5), filter_4_7, 1); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s6), filter_4_7, 2); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s7), filter_4_7, 3); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s8), filter_8_11, 0); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(s9), filter_8_11, 1); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(sA), filter_8_11, 2); + sum_lo = vmlal_lane_s16(sum_lo, vget_low_s16(sB), filter_8_11, 3); + + int32x4_t sum_hi = vmull_lane_s16(vget_high_s16(s0), filter_0_3, 0); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s1), filter_0_3, 1); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s2), filter_0_3, 2); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s3), filter_0_3, 3); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s4), filter_4_7, 0); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s5), filter_4_7, 1); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s6), filter_4_7, 2); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s7), filter_4_7, 3); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s8), filter_8_11, 0); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(s9), filter_8_11, 1); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(sA), filter_8_11, 2); + sum_hi = vmlal_lane_s16(sum_hi, vget_high_s16(sB), filter_8_11, 3); + + uint16x4_t sum_lo_s16 = vqrshrun_n_s32(sum_lo, FILTER_BITS); + uint16x4_t sum_hi_s16 = vqrshrun_n_s32(sum_hi, FILTER_BITS); + + uint16x8_t sum = vcombine_u16(sum_lo_s16, sum_hi_s16); + return vminq_u16(sum, max); +} + +void vpx_highbd_convolve12_horiz_neon(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, + int w, int h, int bd) { + // Scaling not supported by Neon implementation. + if (x_step_q4 != 16) { + vpx_highbd_convolve12_horiz_c(src, src_stride, dst, dst_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + + assert(w == 32 || w == 16 || w == 8); + assert(h % 4 == 0); + + const int16x8_t filter_0_7 = vld1q_s16(filter[x0_q4]); + const int16x4_t filter_8_11 = vld1_s16(filter[x0_q4] + 8); + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + src -= MAX_FILTER_TAP / 2 - 1; + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int width = w; + + do { + int16x8_t s0[12], s1[12]; + load_s16_8x12(s + 0 * src_stride, 1, &s0[0], &s0[1], &s0[2], &s0[3], + &s0[4], &s0[5], &s0[6], &s0[7], &s0[8], &s0[9], &s0[10], + &s0[11]); + load_s16_8x12(s + 1 * src_stride, 1, &s1[0], &s1[1], &s1[2], &s1[3], + &s1[4], &s1[5], &s1[6], &s1[7], &s1[8], &s1[9], &s1[10], + &s1[11]); + + uint16x8_t d0 = highbd_convolve12_8( + s0[0], s0[1], s0[2], s0[3], s0[4], s0[5], s0[6], s0[7], s0[8], s0[9], + s0[10], s0[11], filter_0_7, filter_8_11, max); + uint16x8_t d1 = highbd_convolve12_8( + s1[0], s1[1], s1[2], s1[3], s1[4], s1[5], s1[6], s1[7], s1[8], s1[9], + s1[10], s1[11], filter_0_7, filter_8_11, max); + + vst1q_u16(d + 0 * dst_stride, d0); + vst1q_u16(d + 1 * dst_stride, d1); + + s += 8; + d += 8; + width -= 8; + } while (width != 0); + src += 2 * src_stride; + dst += 2 * dst_stride; + h -= 2; + } while (h != 0); +} + +void vpx_highbd_convolve12_vert_neon(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, + int w, int h, int bd) { + // Scaling not supported by Neon implementation. + if (y_step_q4 != 16) { + vpx_highbd_convolve12_vert_c(src, src_stride, dst, dst_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + + assert(w == 32 || w == 16 || w == 8); + assert(h == 32 || h == 16 || h == 8); + + const int16x8_t filter_0_7 = vld1q_s16(filter[y0_q4]); + const int16x4_t filter_8_11 = vld1_s16(filter[y0_q4] + 8); + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + + src -= src_stride * (MAX_FILTER_TAP / 2 - 1); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int height = h; + + int16x8_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA; + load_s16_8x11(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, + &s9, &sA); + s += 11 * src_stride; + + do { + int16x8_t sB, sC, sD, sE; + load_s16_8x4(s, src_stride, &sB, &sC, &sD, &sE); + + uint16x8_t d0 = + highbd_convolve12_8(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, + filter_0_7, filter_8_11, max); + uint16x8_t d1 = + highbd_convolve12_8(s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, + filter_0_7, filter_8_11, max); + uint16x8_t d2 = + highbd_convolve12_8(s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, + filter_0_7, filter_8_11, max); + uint16x8_t d3 = + highbd_convolve12_8(s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, + filter_0_7, filter_8_11, max); + + store_u16_8x4(d, dst_stride, d0, d1, d2, d3); + + s0 = s4; + s1 = s5; + s2 = s6; + s3 = s7; + s4 = s8; + s5 = s9; + s6 = sA; + s7 = sB; + s8 = sC; + s9 = sD; + sA = sE; + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height != 0); + src += 8; + dst += 8; + w -= 8; + } while (w != 0); +} + +void vpx_highbd_convolve12_neon(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, int w, + int h, int bd) { + // Scaling not supported by Neon implementation. + if (x_step_q4 != 16 || y_step_q4 != 16) { + vpx_highbd_convolve12_c(src, src_stride, dst, dst_stride, filter, x0_q4, + x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + + assert(w == 32 || w == 16 || w == 8); + assert(h == 32 || h == 16 || h == 8); + + DECLARE_ALIGNED(32, uint16_t, im_block[BW * (BH + MAX_FILTER_TAP)]); + + const int im_stride = BW; + // Account for the vertical pass needing MAX_FILTER_TAP / 2 - 1 lines prior + // and MAX_FILTER_TAP / 2 lines post. (+1 to make total divisible by 2.) + const int im_height = h + MAX_FILTER_TAP; + const ptrdiff_t border_offset = MAX_FILTER_TAP / 2 - 1; + + // Filter starting border_offset rows up. + vpx_highbd_convolve12_horiz_neon( + src - src_stride * border_offset, src_stride, im_block, im_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, im_height, bd); + + vpx_highbd_convolve12_vert_neon(im_block + im_stride * border_offset, + im_stride, dst, dst_stride, filter, x0_q4, + x_step_q4, y0_q4, y_step_q4, w, h, bd); +} diff --git a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_sve2.c b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_sve2.c new file mode 100644 --- /dev/null +++ b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_highbd_temporal_filter_sve2.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2025 The WebM project authors. 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 +#include +#include + +#include "./vp9_rtcd.h" +#include "./vpx_config.h" +#include "vpx/vpx_integer.h" +#include "vpx_dsp/arm/mem_neon.h" +#include "vpx_dsp/arm/transpose_neon.h" +#include "vp9/encoder/vp9_temporal_filter.h" +#include "vpx_dsp/arm/vpx_neon_sve_bridge.h" +#include "vpx_dsp/arm/vpx_neon_sve2_bridge.h" + +DECLARE_ALIGNED(16, static const uint16_t, kDotProdPermuteTbl[32]) = { + // clang-format off + 0, 1, 2, 3, 1, 2, 3, 4, + 2, 3, 4, 5, 3, 4, 5, 6, + 4, 5, 6, 7, 5, 6, 7, 0, + 6, 7, 0, 1, 7, 0, 1, 2, + // clang-format on +}; + +static INLINE uint16x8_t highbd_convolve12_8_h( + const int16x8_t s0, const int16x8_t s1, const int16x8_t s2, + const int16x8_t filter_0_7, const int16x8_t filter_4_11, + const uint16x8x4_t perm_tbl, const uint16x8_t max) { + int16x8_t perm_samples[8]; + + perm_samples[0] = vpx_tbl_s16(s0, perm_tbl.val[0]); + perm_samples[1] = vpx_tbl_s16(s0, perm_tbl.val[1]); + perm_samples[2] = vpx_tbl2_s16(s0, s1, perm_tbl.val[2]); + perm_samples[3] = vpx_tbl2_s16(s0, s1, perm_tbl.val[3]); + perm_samples[4] = vpx_tbl_s16(s1, perm_tbl.val[0]); + perm_samples[5] = vpx_tbl_s16(s1, perm_tbl.val[1]); + perm_samples[6] = vpx_tbl2_s16(s1, s2, perm_tbl.val[2]); + perm_samples[7] = vpx_tbl2_s16(s1, s2, perm_tbl.val[3]); + + int64x2_t sum01 = + vpx_dotq_lane_s16(vdupq_n_s64(0), perm_samples[0], filter_0_7, 0); + sum01 = vpx_dotq_lane_s16(sum01, perm_samples[2], filter_0_7, 1); + sum01 = vpx_dotq_lane_s16(sum01, perm_samples[4], filter_4_11, 1); + + int64x2_t sum23 = + vpx_dotq_lane_s16(vdupq_n_s64(0), perm_samples[1], filter_0_7, 0); + sum23 = vpx_dotq_lane_s16(sum23, perm_samples[3], filter_0_7, 1); + sum23 = vpx_dotq_lane_s16(sum23, perm_samples[5], filter_4_11, 1); + + int64x2_t sum45 = + vpx_dotq_lane_s16(vdupq_n_s64(0), perm_samples[2], filter_0_7, 0); + sum45 = vpx_dotq_lane_s16(sum45, perm_samples[4], filter_0_7, 1); + sum45 = vpx_dotq_lane_s16(sum45, perm_samples[6], filter_4_11, 1); + + int64x2_t sum67 = + vpx_dotq_lane_s16(vdupq_n_s64(0), perm_samples[3], filter_0_7, 0); + sum67 = vpx_dotq_lane_s16(sum67, perm_samples[5], filter_0_7, 1); + sum67 = vpx_dotq_lane_s16(sum67, perm_samples[7], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + int32x4_t sum4567 = vcombine_s32(vmovn_s64(sum45), vmovn_s64(sum67)); + + uint16x8_t res = vcombine_u16(vqrshrun_n_s32(sum0123, FILTER_BITS), + vqrshrun_n_s32(sum4567, FILTER_BITS)); + return vminq_u16(res, max); +} + +void vpx_highbd_convolve12_horiz_sve2(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, + int w, int h, int bd) { + // Scaling not supported by SVE2 implementation. + if (x_step_q4 != 16) { + vpx_highbd_convolve12_horiz_c(src, src_stride, dst, dst_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + + assert(w == 32 || w == 16 || w == 8); + assert(h % 4 == 0); + + const int16x8_t filter_0_7 = vld1q_s16(filter[x0_q4]); + const int16x8_t filter_4_11 = vld1q_s16(filter[x0_q4] + 4); + const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); + uint16x8x4_t permute_tbl = vld1q_u16_x4(kDotProdPermuteTbl); + + // Scale indices by size of the true vector length to avoid reading from an + // 'undefined' portion of a vector on a system with SVE vectors > 128-bit. + permute_tbl.val[2] = vsetq_lane_u16(svcnth(), permute_tbl.val[2], 7); + permute_tbl.val[3] = vsetq_lane_u16(svcnth(), permute_tbl.val[3], 5); + uint16x8_t permute_tbl_3_offsets = + vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL)); + permute_tbl.val[3] = + vaddq_u16(permute_tbl.val[3], permute_tbl_3_offsets); // 2, 3, 6, 7 + + src -= MAX_FILTER_TAP / 2 - 1; + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int width = w; + + do { + int16x8_t s0[3], s1[3]; + + load_s16_8x3(s + 0 * src_stride, 8, &s0[0], &s0[1], &s0[2]); + load_s16_8x3(s + 1 * src_stride, 8, &s1[0], &s1[1], &s1[2]); + + uint16x8_t d0 = highbd_convolve12_8_h(s0[0], s0[1], s0[2], filter_0_7, + filter_4_11, permute_tbl, max); + uint16x8_t d1 = highbd_convolve12_8_h(s1[0], s1[1], s1[2], filter_0_7, + filter_4_11, permute_tbl, max); + + vst1q_u16(d + 0 * dst_stride, d0); + vst1q_u16(d + 1 * dst_stride, d1); + + s += 8; + d += 8; + width -= 8; + } while (width != 0); + src += 2 * src_stride; + dst += 2 * dst_stride; + h -= 2; + } while (h != 0); +} + +static INLINE uint16x4_t highbd_convolve12_4_v(const int16x8_t s0[2], + const int16x8_t s1[2], + const int16x8_t s2[2], + const int16x8_t filter_0_7, + const int16x8_t filter_4_11, + const uint16x4_t max) { + int64x2_t sum01 = vpx_dotq_lane_s16(vdupq_n_s64(0), s0[0], filter_0_7, 0); + sum01 = vpx_dotq_lane_s16(sum01, s1[0], filter_0_7, 1); + sum01 = vpx_dotq_lane_s16(sum01, s2[0], filter_4_11, 1); + + int64x2_t sum23 = vpx_dotq_lane_s16(vdupq_n_s64(0), s0[1], filter_0_7, 0); + sum23 = vpx_dotq_lane_s16(sum23, s1[1], filter_0_7, 1); + sum23 = vpx_dotq_lane_s16(sum23, s2[1], filter_4_11, 1); + + int32x4_t sum0123 = vcombine_s32(vmovn_s64(sum01), vmovn_s64(sum23)); + + uint16x4_t res = vqrshrun_n_s32(sum0123, FILTER_BITS); + + return vmin_u16(res, max); +} + +void vpx_highbd_convolve12_vert_sve2(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, + int w, int h, int bd) { + // Scaling not supported by SVE2 implementation. + if (y_step_q4 != 16) { + vpx_highbd_convolve12_vert_c(src, src_stride, dst, dst_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + assert(w == 32 || w == 16 || w == 8); + assert(h % 4 == 0); + + const int16x8_t filter_0_7 = vld1q_s16(filter[y0_q4]); + const int16x8_t filter_4_11 = vld1q_s16(filter[y0_q4] + 4); + + const uint16x4_t max = vdup_n_u16((1 << bd) - 1); + + src -= src_stride * (MAX_FILTER_TAP / 2 - 1); + + do { + const int16_t *s = (const int16_t *)src; + uint16_t *d = dst; + int height = h; + + int16x4_t s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA; + load_s16_4x11(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, + &s9, &sA); + s += 11 * src_stride; + + int16x8_t s0123[2], s1234[2], s2345[2], s3456[2], s4567[2], s5678[2], + s6789[2], s789A[2]; + transpose_concat_s16_4x4(s0, s1, s2, s3, &s0123[0], &s0123[1]); + transpose_concat_s16_4x4(s1, s2, s3, s4, &s1234[0], &s1234[1]); + transpose_concat_s16_4x4(s2, s3, s4, s5, &s2345[0], &s2345[1]); + transpose_concat_s16_4x4(s3, s4, s5, s6, &s3456[0], &s3456[1]); + transpose_concat_s16_4x4(s4, s5, s6, s7, &s4567[0], &s4567[1]); + transpose_concat_s16_4x4(s5, s6, s7, s8, &s5678[0], &s5678[1]); + transpose_concat_s16_4x4(s6, s7, s8, s9, &s6789[0], &s6789[1]); + transpose_concat_s16_4x4(s7, s8, s9, sA, &s789A[0], &s789A[1]); + + do { + int16x4_t sB, sC, sD, sE; + load_s16_4x4(s, src_stride, &sB, &sC, &sD, &sE); + + int16x8_t s89AB[2], s9ABC[2], sABCD[2], sBCDE[2]; + transpose_concat_s16_4x4(s8, s9, sA, sB, &s89AB[0], &s89AB[1]); + transpose_concat_s16_4x4(s9, sA, sB, sC, &s9ABC[0], &s9ABC[1]); + transpose_concat_s16_4x4(sA, sB, sC, sD, &sABCD[0], &sABCD[1]); + transpose_concat_s16_4x4(sB, sC, sD, sE, &sBCDE[0], &sBCDE[1]); + + uint16x4_t d0 = highbd_convolve12_4_v(s0123, s4567, s89AB, filter_0_7, + filter_4_11, max); + uint16x4_t d1 = highbd_convolve12_4_v(s1234, s5678, s9ABC, filter_0_7, + filter_4_11, max); + uint16x4_t d2 = highbd_convolve12_4_v(s2345, s6789, sABCD, filter_0_7, + filter_4_11, max); + uint16x4_t d3 = highbd_convolve12_4_v(s3456, s789A, sBCDE, filter_0_7, + filter_4_11, max); + + store_u16_4x4(d, dst_stride, d0, d1, d2, d3); + + // Prepare block for next iteration - reusing as much as possible. + // Shuffle everything up four rows. + s0123[0] = s4567[0]; + s0123[1] = s4567[1]; + s1234[0] = s5678[0]; + s1234[1] = s5678[1]; + s2345[0] = s6789[0]; + s2345[1] = s6789[1]; + s3456[0] = s789A[0]; + s3456[1] = s789A[1]; + s4567[0] = s89AB[0]; + s4567[1] = s89AB[1]; + s5678[0] = s9ABC[0]; + s5678[1] = s9ABC[1]; + s6789[0] = sABCD[0]; + s6789[1] = sABCD[1]; + s789A[0] = sBCDE[0]; + s789A[1] = sBCDE[1]; + + s8 = sC; + s9 = sD; + sA = sE; + + s += 4 * src_stride; + d += 4 * dst_stride; + height -= 4; + } while (height != 0); + src += 4; + dst += 4; + w -= 4; + } while (w != 0); +} + +void vpx_highbd_convolve12_sve2(const uint16_t *src, ptrdiff_t src_stride, + uint16_t *dst, ptrdiff_t dst_stride, + const InterpKernel12 *filter, int x0_q4, + int x_step_q4, int y0_q4, int y_step_q4, int w, + int h, int bd) { + // Scaling not supported by SVE2 implementation. + if (x_step_q4 != 16 || y_step_q4 != 16) { + vpx_highbd_convolve12_c(src, src_stride, dst, dst_stride, filter, x0_q4, + x_step_q4, y0_q4, y_step_q4, w, h, bd); + return; + } + + assert(w == 32 || w == 16 || w == 8); + assert(h == 32 || h == 16 || h == 8); + + DECLARE_ALIGNED(32, uint16_t, im_block[BW * (BH + MAX_FILTER_TAP)]); + + const int im_stride = BW; + // Account for the vertical pass needing MAX_FILTER_TAP / 2 - 1 lines prior + // and MAX_FILTER_TAP / 2 lines post. (+1 to make total divisible by 4.) + const int im_height = h + MAX_FILTER_TAP; + const ptrdiff_t border_offset = MAX_FILTER_TAP / 2 - 1; + + // Filter starting border_offset rows up. + vpx_highbd_convolve12_horiz_sve2( + src - src_stride * border_offset, src_stride, im_block, im_stride, filter, + x0_q4, x_step_q4, y0_q4, y_step_q4, w, im_height, bd); + + vpx_highbd_convolve12_vert_sve2(im_block + im_stride * border_offset, + im_stride, dst, dst_stride, filter, x0_q4, + x_step_q4, y0_q4, y_step_q4, w, h, bd); +} diff --git a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_dotprod.c b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_dotprod.c --- a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_dotprod.c +++ b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_dotprod.c @@ -13,10 +13,11 @@ #include "./vp9_rtcd.h" #include "./vpx_config.h" #include "vpx/vpx_integer.h" #include "vpx_dsp/arm/mem_neon.h" +#include "vpx_dsp/arm/transpose_neon.h" #include "vp9/encoder/vp9_temporal_filter.h" DECLARE_ALIGNED(16, static const uint8_t, kDotProdPermuteTbl[48]) = { // clang-format off 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, @@ -143,36 +144,10 @@ // Narrow and re-pack. int16x8_t sum = vcombine_s16(vqmovn_s32(sum0123), vqmovn_s32(sum4567)); return vqrshrun_n_s16(sum, FILTER_BITS); } -static INLINE void transpose_concat_8x4(int8x8_t a0, int8x8_t a1, int8x8_t a2, - int8x8_t a3, int8x16_t *b0, - int8x16_t *b1) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, 04, 05, 06, 07 - // a1: 10, 11, 12, 13, 14, 15, 16, 17 - // a2: 20, 21, 22, 23, 24, 25, 26, 27 - // a3: 30, 31, 32, 33, 34, 35, 36, 37 - // - // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 - - int8x16_t a0q = vcombine_s8(a0, vdup_n_s8(0)); - int8x16_t a1q = vcombine_s8(a1, vdup_n_s8(0)); - int8x16_t a2q = vcombine_s8(a2, vdup_n_s8(0)); - int8x16_t a3q = vcombine_s8(a3, vdup_n_s8(0)); - - int8x16_t a02 = vzipq_s8(a0q, a2q).val[0]; - int8x16_t a13 = vzipq_s8(a1q, a3q).val[0]; - - int8x16x2_t a0123 = vzipq_s8(a02, a13); - - *b0 = a0123.val[0]; - *b1 = a0123.val[1]; -} - void vpx_convolve12_vert_neon_dotprod(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h) { @@ -219,18 +194,18 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. int8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi, s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, s6789_hi, s789A_lo, s789A_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); - transpose_concat_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi); - transpose_concat_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi); - transpose_concat_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi); - transpose_concat_8x4(s7, s8, s9, sA, &s789A_lo, &s789A_hi); + transpose_concat_s8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_s8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_s8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_s8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_s8_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi); + transpose_concat_s8_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi); + transpose_concat_s8_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi); + transpose_concat_s8_8x4(s7, s8, s9, sA, &s789A_lo, &s789A_hi); do { uint8x8_t tB, tC, tD, tE; load_u8_8x4(s, src_stride, &tB, &tC, &tD, &tE); @@ -239,11 +214,11 @@ int8x8_t sD = vreinterpret_s8_u8(vsub_u8(tD, vdup_n_u8(128))); int8x8_t sE = vreinterpret_s8_u8(vsub_u8(tE, vdup_n_u8(128))); int8x16_t s89AB_lo, s89AB_hi, s9ABC_lo, s9ABC_hi, sABCD_lo, sABCD_hi, sBCDE_lo, sBCDE_hi; - transpose_concat_8x4(sB, sC, sD, sE, &sBCDE_lo, &sBCDE_hi); + transpose_concat_s8_8x4(sB, sC, sD, sE, &sBCDE_lo, &sBCDE_hi); // Merge new data into block from previous iteration. int8x16x2_t samples_LUT_lo = { { s789A_lo, sBCDE_lo } }; s89AB_lo = vqtbl2q_s8(samples_LUT_lo, merge_block_tbl.val[0]); s9ABC_lo = vqtbl2q_s8(samples_LUT_lo, merge_block_tbl.val[1]); diff --git a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_i8mm.c b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_i8mm.c --- a/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_i8mm.c +++ b/media/libvpx/libvpx/vp9/encoder/arm/neon/vp9_temporal_filter_neon_i8mm.c @@ -13,10 +13,11 @@ #include "./vp9_rtcd.h" #include "./vpx_config.h" #include "vpx/vpx_integer.h" #include "vpx_dsp/arm/mem_neon.h" +#include "vpx_dsp/arm/transpose_neon.h" #include "vp9/encoder/vp9_temporal_filter.h" DECLARE_ALIGNED(16, static const uint8_t, kMatMulPermuteTbl[32]) = { // clang-format off 0, 1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 9, @@ -137,36 +138,10 @@ // Narrow and re-pack. int16x8_t sum = vcombine_s16(vqmovn_s32(sum0123), vqmovn_s32(sum4567)); return vqrshrun_n_s16(sum, FILTER_BITS); } -static INLINE void transpose_concat_8x4(uint8x8_t a0, uint8x8_t a1, - uint8x8_t a2, uint8x8_t a3, - uint8x16_t *b0, uint8x16_t *b1) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, 04, 05, 06, 07 - // a1: 10, 11, 12, 13, 14, 15, 16, 17 - // a2: 20, 21, 22, 23, 24, 25, 26, 27 - // a3: 30, 31, 32, 33, 34, 35, 36, 37 - // - // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 - - uint8x16_t a0q = vcombine_u8(a0, vdup_n_u8(0)); - uint8x16_t a1q = vcombine_u8(a1, vdup_n_u8(0)); - uint8x16_t a2q = vcombine_u8(a2, vdup_n_u8(0)); - uint8x16_t a3q = vcombine_u8(a3, vdup_n_u8(0)); - - uint8x16_t a02 = vzipq_u8(a0q, a2q).val[0]; - uint8x16_t a13 = vzipq_u8(a1q, a3q).val[0]; - - uint8x16x2_t a0123 = vzipq_u8(a02, a13); - - *b0 = a0123.val[0]; - *b1 = a0123.val[1]; -} - void vpx_convolve12_vert_neon_i8mm(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const InterpKernel12 *filter, int x0_q4, int x_step_q4, int y0_q4, int y_step_q4, int w, int h) { @@ -200,26 +175,26 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. uint8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi, s4567_lo, s4567_hi, s5678_lo, s5678_hi, s6789_lo, s6789_hi, s789A_lo, s789A_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); - transpose_concat_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi); - transpose_concat_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi); - transpose_concat_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi); - transpose_concat_8x4(s7, s8, s9, sA, &s789A_lo, &s789A_hi); + transpose_concat_u8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_u8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_u8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_u8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_u8_8x4(s4, s5, s6, s7, &s4567_lo, &s4567_hi); + transpose_concat_u8_8x4(s5, s6, s7, s8, &s5678_lo, &s5678_hi); + transpose_concat_u8_8x4(s6, s7, s8, s9, &s6789_lo, &s6789_hi); + transpose_concat_u8_8x4(s7, s8, s9, sA, &s789A_lo, &s789A_hi); do { uint8x8_t sB, sC, sD, sE; load_u8_8x4(s, src_stride, &sB, &sC, &sD, &sE); uint8x16_t s89AB_lo, s89AB_hi, s9ABC_lo, s9ABC_hi, sABCD_lo, sABCD_hi, sBCDE_lo, sBCDE_hi; - transpose_concat_8x4(sB, sC, sD, sE, &sBCDE_lo, &sBCDE_hi); + transpose_concat_u8_8x4(sB, sC, sD, sE, &sBCDE_lo, &sBCDE_hi); // Merge new data into block from previous iteration. uint8x16x2_t samples_LUT_lo = { { s789A_lo, sBCDE_lo } }; s89AB_lo = vqtbl2q_u8(samples_LUT_lo, merge_block_tbl.val[0]); s9ABC_lo = vqtbl2q_u8(samples_LUT_lo, merge_block_tbl.val[1]); diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_aq_variance.c b/media/libvpx/libvpx/vp9/encoder/vp9_aq_variance.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_aq_variance.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_aq_variance.c @@ -30,11 +30,11 @@ static const double rate_ratio[MAX_SEGMENTS] = { 2.5, 2.0, 1.5, 1.0, 0.75, 1.0, 1.0, 1.0 }; static const int segment_id[ENERGY_SPAN] = { 0, 1, 1, 2, 3, 4 }; -#define SEGMENT_ID(i) segment_id[(i)-ENERGY_MIN] +#define SEGMENT_ID(i) segment_id[(i) - ENERGY_MIN] DECLARE_ALIGNED(16, static const uint8_t, vp9_64_zeros[64]) = { 0 }; #if CONFIG_VP9_HIGHBITDEPTH DECLARE_ALIGNED(16, static const uint16_t, vp9_highbd_64_zeros[64]) = { 0 }; #endif diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_bitstream.c b/media/libvpx/libvpx/vp9/encoder/vp9_bitstream.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_bitstream.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_bitstream.c @@ -54,10 +54,11 @@ { 2, 2 }, { 6, 3 }, { 0, 1 }, { 7, 3 } }; static void write_intra_mode(vpx_writer *w, PREDICTION_MODE mode, const vpx_prob *probs) { + assert(!is_inter_mode(mode)); vp9_write_token(w, vp9_intra_mode_tree, probs, &intra_mode_encodings[mode]); } static void write_inter_mode(vpx_writer *w, PREDICTION_MODE mode, const vpx_prob *probs) { @@ -1247,10 +1248,11 @@ } else { assert(cm->subsampling_x == 1 && cm->subsampling_y == 1); } } else { assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3); + assert(cm->subsampling_x == 0 && cm->subsampling_y == 0); vpx_wb_write_bit(wb, 0); // unused } } static void write_uncompressed_header(VP9_COMP *cpi, diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_block.h b/media/libvpx/libvpx/vp9/encoder/vp9_block.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_block.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_block.h @@ -17,16 +17,10 @@ #ifdef __cplusplus extern "C" { #endif -typedef struct { - unsigned int sse; - int sum; - unsigned int var; -} Diff; - struct macroblock_plane { DECLARE_ALIGNED(16, int16_t, src_diff[64 * 64]); tran_low_t *qcoeff; tran_low_t *coeff; uint16_t *eobs; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.h b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.h @@ -20,17 +20,10 @@ struct macroblock; struct yv12_buffer_config; struct VP9_COMP; struct ThreadData; -// Constants used in SOURCE_VAR_BASED_PARTITION -#define VAR_HIST_MAX_BG_VAR 1000 -#define VAR_HIST_FACTOR 10 -#define VAR_HIST_BINS (VAR_HIST_MAX_BG_VAR / VAR_HIST_FACTOR + 1) -#define VAR_HIST_LARGE_CUT_OFF 75 -#define VAR_HIST_SMALL_CUT_OFF 45 - void vp9_setup_src_planes(struct macroblock *x, const struct yv12_buffer_config *src, int mi_row, int mi_col); void vp9_encode_frame(struct VP9_COMP *cpi); diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c @@ -1299,12 +1299,17 @@ if (cm->frame_refs[LAST_FRAME - 1].sf.x_scale_fp == REF_INVALID_SCALE || cm->frame_refs[LAST_FRAME - 1].sf.y_scale_fp == REF_INVALID_SCALE) is_key_frame = 1; } - // Always use 4x4 partition for key frame. - const int use_4x4_partition = frame_is_intra_only(cm); + // Allow for sub8x8 (4x4) partition on key frames, but only for hybrid mode + // (i.e., sf->nonrd_keyframe = 0), where for small blocks rd intra pickmode + // (vp9_rd_pick_intra_mode_sb) is used. The nonrd intra pickmode + // (vp9_pick_intra_mode) does not currently support sub8x8 blocks. This causes + // the issue: 44166813. Assert is added in vp9_pick_intra_mode to check this. + const int use_4x4_partition = + frame_is_intra_only(cm) && !cpi->sf.nonrd_keyframe; const int low_res = (cm->width <= 352 && cm->height <= 288); int variance4x4downsample[16]; int segment_id; int sb_offset = (cm->mi_stride >> 3) * (mi_row >> 3) + (mi_col >> 3); @@ -2384,124 +2389,10 @@ set_partial_b64x64_partition(mi_upper_left, mis, bh, bw, row8x8_remaining, col8x8_remaining, bsize, mi_8x8); } } -static const struct { - int row; - int col; -} coord_lookup[16] = { - // 32x32 index = 0 - { 0, 0 }, - { 0, 2 }, - { 2, 0 }, - { 2, 2 }, - // 32x32 index = 1 - { 0, 4 }, - { 0, 6 }, - { 2, 4 }, - { 2, 6 }, - // 32x32 index = 2 - { 4, 0 }, - { 4, 2 }, - { 6, 0 }, - { 6, 2 }, - // 32x32 index = 3 - { 4, 4 }, - { 4, 6 }, - { 6, 4 }, - { 6, 6 }, -}; - -static void set_source_var_based_partition(VP9_COMP *cpi, - const TileInfo *const tile, - MACROBLOCK *const x, - MODE_INFO **mi_8x8, int mi_row, - int mi_col) { - VP9_COMMON *const cm = &cpi->common; - const int mis = cm->mi_stride; - const int row8x8_remaining = tile->mi_row_end - mi_row; - const int col8x8_remaining = tile->mi_col_end - mi_col; - MODE_INFO *mi_upper_left = cm->mi + mi_row * mis + mi_col; - - vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col); - - assert((row8x8_remaining > 0) && (col8x8_remaining > 0)); - - // In-image SB64 - if ((col8x8_remaining >= MI_BLOCK_SIZE) && - (row8x8_remaining >= MI_BLOCK_SIZE)) { - int i, j; - int index; - Diff d32[4]; - const int offset = (mi_row >> 1) * cm->mb_cols + (mi_col >> 1); - int is_larger_better = 0; - int use32x32 = 0; - unsigned int thr = cpi->source_var_thresh; - - memset(d32, 0, sizeof(d32)); - - for (i = 0; i < 4; i++) { - Diff *d16[4]; - - for (j = 0; j < 4; j++) { - int b_mi_row = coord_lookup[i * 4 + j].row; - int b_mi_col = coord_lookup[i * 4 + j].col; - int boffset = b_mi_row / 2 * cm->mb_cols + b_mi_col / 2; - - d16[j] = cpi->source_diff_var + offset + boffset; - - index = b_mi_row * mis + b_mi_col; - mi_8x8[index] = mi_upper_left + index; - mi_8x8[index]->sb_type = BLOCK_16X16; - - // TODO(yunqingwang): If d16[j].var is very large, use 8x8 partition - // size to further improve quality. - } - - is_larger_better = (d16[0]->var < thr) && (d16[1]->var < thr) && - (d16[2]->var < thr) && (d16[3]->var < thr); - - // Use 32x32 partition - if (is_larger_better) { - use32x32 += 1; - - for (j = 0; j < 4; j++) { - d32[i].sse += d16[j]->sse; - d32[i].sum += d16[j]->sum; - } - - d32[i].var = - (unsigned int)(d32[i].sse - - (unsigned int)(((int64_t)d32[i].sum * d32[i].sum) >> - 10)); - - index = coord_lookup[i * 4].row * mis + coord_lookup[i * 4].col; - mi_8x8[index] = mi_upper_left + index; - mi_8x8[index]->sb_type = BLOCK_32X32; - } - } - - if (use32x32 == 4) { - thr <<= 1; - is_larger_better = (d32[0].var < thr) && (d32[1].var < thr) && - (d32[2].var < thr) && (d32[3].var < thr); - - // Use 64x64 partition - if (is_larger_better) { - mi_8x8[0] = mi_upper_left; - mi_8x8[0]->sb_type = BLOCK_64X64; - } - } - } else { // partial in-image SB64 - int bh = num_8x8_blocks_high_lookup[BLOCK_16X16]; - int bw = num_8x8_blocks_wide_lookup[BLOCK_16X16]; - set_partial_b64x64_partition(mi_upper_left, mis, bh, bw, row8x8_remaining, - col8x8_remaining, BLOCK_16X16, mi_8x8); - } -} - static void update_state_rt(VP9_COMP *cpi, ThreadData *td, PICK_MODE_CONTEXT *ctx, int mi_row, int mi_col, int bsize) { VP9_COMMON *const cm = &cpi->common; MACROBLOCK *const x = &td->mb; @@ -3760,229 +3651,17 @@ r0 = cpi->rd.r0; rk = (double)intra_cost / mc_dep_cost; beta = r0 / rk; dr = vp9_get_adaptive_rdmult(cpi, beta); - dr = VPXMIN(dr, orig_rdmult * 3 / 2); - dr = VPXMAX(dr, orig_rdmult * 1 / 2); - + dr = clamp(dr, orig_rdmult * 1 / 2, orig_rdmult * 3 / 2); dr = VPXMAX(1, dr); return dr; } #endif // !CONFIG_REALTIME_ONLY -#if CONFIG_RATE_CTRL -static void assign_partition_info( - const int row_start_4x4, const int col_start_4x4, const int block_width_4x4, - const int block_height_4x4, const int num_unit_rows, - const int num_unit_cols, PARTITION_INFO *partition_info) { - int i, j; - for (i = 0; i < block_height_4x4; ++i) { - for (j = 0; j < block_width_4x4; ++j) { - const int row_4x4 = row_start_4x4 + i; - const int col_4x4 = col_start_4x4 + j; - const int unit_index = row_4x4 * num_unit_cols + col_4x4; - if (row_4x4 >= num_unit_rows || col_4x4 >= num_unit_cols) continue; - partition_info[unit_index].row = row_4x4 << 2; - partition_info[unit_index].column = col_4x4 << 2; - partition_info[unit_index].row_start = row_start_4x4 << 2; - partition_info[unit_index].column_start = col_start_4x4 << 2; - partition_info[unit_index].width = block_width_4x4 << 2; - partition_info[unit_index].height = block_height_4x4 << 2; - } - } -} - -static void assign_motion_vector_info(const int block_width_4x4, - const int block_height_4x4, - const int row_start_4x4, - const int col_start_4x4, - const int num_unit_rows, - const int num_unit_cols, MV *source_mv[2], - MV_REFERENCE_FRAME source_ref_frame[2], - MOTION_VECTOR_INFO *motion_vector_info) { - int i, j; - for (i = 0; i < block_height_4x4; ++i) { - for (j = 0; j < block_width_4x4; ++j) { - const int row_4x4 = row_start_4x4 + i; - const int col_4x4 = col_start_4x4 + j; - const int unit_index = row_4x4 * num_unit_cols + col_4x4; - if (row_4x4 >= num_unit_rows || col_4x4 >= num_unit_cols) continue; - if (source_ref_frame[1] == NO_REF_FRAME) { - assert(source_mv[1]->row == 0 && source_mv[1]->col == 0); - } - motion_vector_info[unit_index].ref_frame[0] = source_ref_frame[0]; - motion_vector_info[unit_index].ref_frame[1] = source_ref_frame[1]; - motion_vector_info[unit_index].mv[0].as_mv.row = source_mv[0]->row; - motion_vector_info[unit_index].mv[0].as_mv.col = source_mv[0]->col; - motion_vector_info[unit_index].mv[1].as_mv.row = source_mv[1]->row; - motion_vector_info[unit_index].mv[1].as_mv.col = source_mv[1]->col; - } - } -} - -static void store_superblock_info( - const PC_TREE *const pc_tree, MODE_INFO **mi_grid_visible, - const int mi_stride, const int square_size_4x4, const int num_unit_rows, - const int num_unit_cols, const int row_start_4x4, const int col_start_4x4, - PARTITION_INFO *partition_info, MOTION_VECTOR_INFO *motion_vector_info) { - const int subblock_square_size_4x4 = square_size_4x4 >> 1; - if (row_start_4x4 >= num_unit_rows || col_start_4x4 >= num_unit_cols) return; - assert(pc_tree->partitioning != PARTITION_INVALID); - // End node, no split. - if (pc_tree->partitioning == PARTITION_NONE || - pc_tree->partitioning == PARTITION_HORZ || - pc_tree->partitioning == PARTITION_VERT || square_size_4x4 == 1) { - const int mi_row = row_start_4x4 >> 1; - const int mi_col = col_start_4x4 >> 1; - const int mi_idx = mi_stride * mi_row + mi_col; - MODE_INFO **mi = mi_grid_visible + mi_idx; - MV *source_mv[2]; - MV_REFERENCE_FRAME source_ref_frame[2]; - - // partition info - const int block_width_4x4 = (pc_tree->partitioning == PARTITION_VERT) - ? square_size_4x4 >> 1 - : square_size_4x4; - const int block_height_4x4 = (pc_tree->partitioning == PARTITION_HORZ) - ? square_size_4x4 >> 1 - : square_size_4x4; - assign_partition_info(row_start_4x4, col_start_4x4, block_width_4x4, - block_height_4x4, num_unit_rows, num_unit_cols, - partition_info); - if (pc_tree->partitioning == PARTITION_VERT) { - assign_partition_info(row_start_4x4, col_start_4x4 + block_width_4x4, - block_width_4x4, block_height_4x4, num_unit_rows, - num_unit_cols, partition_info); - } else if (pc_tree->partitioning == PARTITION_HORZ) { - assign_partition_info(row_start_4x4 + block_height_4x4, col_start_4x4, - block_width_4x4, block_height_4x4, num_unit_rows, - num_unit_cols, partition_info); - } - - // motion vector info - if (pc_tree->partitioning == PARTITION_HORZ) { - int is_valid_second_rectangle = 0; - assert(square_size_4x4 > 1); - // First rectangle. - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->mv[0].as_mv; - source_mv[1] = &mi[0]->mv[1].as_mv; - assign_motion_vector_info(block_width_4x4, block_height_4x4, - row_start_4x4, col_start_4x4, num_unit_rows, - num_unit_cols, source_mv, source_ref_frame, - motion_vector_info); - // Second rectangle. - if (square_size_4x4 == 2) { - is_valid_second_rectangle = 1; - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->bmi[2].as_mv[0].as_mv; - source_mv[1] = &mi[0]->bmi[2].as_mv[1].as_mv; - } else { - const int mi_row_2 = mi_row + (block_height_4x4 >> 1); - const int mi_col_2 = mi_col; - if (mi_row_2 * 2 < num_unit_rows && mi_col_2 * 2 < num_unit_cols) { - const int mi_idx_2 = mi_stride * mi_row_2 + mi_col_2; - is_valid_second_rectangle = 1; - mi = mi_grid_visible + mi_idx_2; - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->mv[0].as_mv; - source_mv[1] = &mi[0]->mv[1].as_mv; - } - } - if (is_valid_second_rectangle) { - assign_motion_vector_info( - block_width_4x4, block_height_4x4, row_start_4x4 + block_height_4x4, - col_start_4x4, num_unit_rows, num_unit_cols, source_mv, - source_ref_frame, motion_vector_info); - } - } else if (pc_tree->partitioning == PARTITION_VERT) { - int is_valid_second_rectangle = 0; - assert(square_size_4x4 > 1); - // First rectangle. - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->mv[0].as_mv; - source_mv[1] = &mi[0]->mv[1].as_mv; - assign_motion_vector_info(block_width_4x4, block_height_4x4, - row_start_4x4, col_start_4x4, num_unit_rows, - num_unit_cols, source_mv, source_ref_frame, - motion_vector_info); - // Second rectangle. - if (square_size_4x4 == 2) { - is_valid_second_rectangle = 1; - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->bmi[1].as_mv[0].as_mv; - source_mv[1] = &mi[0]->bmi[1].as_mv[1].as_mv; - } else { - const int mi_row_2 = mi_row; - const int mi_col_2 = mi_col + (block_width_4x4 >> 1); - if (mi_row_2 * 2 < num_unit_rows && mi_col_2 * 2 < num_unit_cols) { - const int mi_idx_2 = mi_stride * mi_row_2 + mi_col_2; - is_valid_second_rectangle = 1; - mi = mi_grid_visible + mi_idx_2; - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - source_mv[0] = &mi[0]->mv[0].as_mv; - source_mv[1] = &mi[0]->mv[1].as_mv; - } - } - if (is_valid_second_rectangle) { - assign_motion_vector_info( - block_width_4x4, block_height_4x4, row_start_4x4, - col_start_4x4 + block_width_4x4, num_unit_rows, num_unit_cols, - source_mv, source_ref_frame, motion_vector_info); - } - } else { - assert(pc_tree->partitioning == PARTITION_NONE || square_size_4x4 == 1); - source_ref_frame[0] = mi[0]->ref_frame[0]; - source_ref_frame[1] = mi[0]->ref_frame[1]; - if (square_size_4x4 == 1) { - const int sub8x8_row = row_start_4x4 % 2; - const int sub8x8_col = col_start_4x4 % 2; - const int sub8x8_idx = sub8x8_row * 2 + sub8x8_col; - source_mv[0] = &mi[0]->bmi[sub8x8_idx].as_mv[0].as_mv; - source_mv[1] = &mi[0]->bmi[sub8x8_idx].as_mv[1].as_mv; - } else { - source_mv[0] = &mi[0]->mv[0].as_mv; - source_mv[1] = &mi[0]->mv[1].as_mv; - } - assign_motion_vector_info(block_width_4x4, block_height_4x4, - row_start_4x4, col_start_4x4, num_unit_rows, - num_unit_cols, source_mv, source_ref_frame, - motion_vector_info); - } - - return; - } - // recursively traverse partition tree when partition is split. - assert(pc_tree->partitioning == PARTITION_SPLIT); - store_superblock_info(pc_tree->u.split[0], mi_grid_visible, mi_stride, - subblock_square_size_4x4, num_unit_rows, num_unit_cols, - row_start_4x4, col_start_4x4, partition_info, - motion_vector_info); - store_superblock_info(pc_tree->u.split[1], mi_grid_visible, mi_stride, - subblock_square_size_4x4, num_unit_rows, num_unit_cols, - row_start_4x4, col_start_4x4 + subblock_square_size_4x4, - partition_info, motion_vector_info); - store_superblock_info(pc_tree->u.split[2], mi_grid_visible, mi_stride, - subblock_square_size_4x4, num_unit_rows, num_unit_cols, - row_start_4x4 + subblock_square_size_4x4, col_start_4x4, - partition_info, motion_vector_info); - store_superblock_info(pc_tree->u.split[3], mi_grid_visible, mi_stride, - subblock_square_size_4x4, num_unit_rows, num_unit_cols, - row_start_4x4 + subblock_square_size_4x4, - col_start_4x4 + subblock_square_size_4x4, - partition_info, motion_vector_info); -} -#endif // CONFIG_RATE_CTRL - #if !CONFIG_REALTIME_ONLY // TODO(jingning,jimbankoski,rbultje): properly skip partition types that are // unlikely to be selected depending on previous rate-distortion optimization // results, for encoding speed-up. static int rd_pick_partition(VP9_COMP *cpi, ThreadData *td, @@ -4111,10 +3790,18 @@ mi_row + num_8x8_blocks_high_lookup[bsize] <= cm->mi_rows && mi_col + num_8x8_blocks_wide_lookup[bsize] <= cm->mi_cols; if (do_rd_ml_partition_var_pruning) { ml_predict_var_rd_partitioning(cpi, x, pc_tree, bsize, mi_row, mi_col, &partition_none_allowed, &do_split); + // ml_predict_var_rd_partitioning() may pruune out either + // partition_none_allowed or do_split, but we should keep the + // partition_none_allowed for 8x8 blocks unless disable_split_mask is + // off (0). + if (bsize == BLOCK_8X8 && cpi->sf.disable_split_mask && + partition_none_allowed == 0) { + partition_none_allowed = 1; + } } else { vp9_zero(pc_tree->mv); } if (bsize > BLOCK_8X8) { // Store MV result as reference for subblocks. for (i = 0; i < 4; ++i) pc_tree->u.split[i]->mv = pc_tree->mv; @@ -4461,25 +4148,10 @@ encode_sb(cpi, td, tile_info, tp, mi_row, mi_col, output_enabled, bsize, pc_tree); #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, encode_sb_time); #endif -#if CONFIG_RATE_CTRL - if (oxcf->use_simple_encode_api) { - // Store partition, motion vector of the superblock. - if (output_enabled) { - const int num_unit_rows = - get_num_unit_4x4(cpi->frame_info.frame_height); - const int num_unit_cols = get_num_unit_4x4(cpi->frame_info.frame_width); - store_superblock_info(pc_tree, cm->mi_grid_visible, cm->mi_stride, - num_4x4_blocks_wide_lookup[BLOCK_64X64], - num_unit_rows, num_unit_cols, mi_row << 1, - mi_col << 1, cpi->partition_info, - cpi->motion_vector_info); - } - } -#endif // CONFIG_RATE_CTRL } if (bsize == BLOCK_64X64) { assert(tp_orig < *tp); assert(best_rdc.rate < INT_MAX); @@ -5645,15 +5317,10 @@ x->sb_pickmode_part = 1; nonrd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, BLOCK_64X64, &dummy_rdc, 1, INT64_MAX, td->pc_root); break; - case SOURCE_VAR_BASED_PARTITION: - set_source_var_based_partition(cpi, tile_info, x, mi, mi_row, mi_col); - nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, - BLOCK_64X64, 1, &dummy_rdc, td->pc_root); - break; case FIXED_PARTITION: if (!seg_skip) bsize = sf->always_this_block_size; set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize); nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, BLOCK_64X64, 1, &dummy_rdc, td->pc_root); @@ -5708,132 +5375,10 @@ sb_col_in_tile, num_sb_cols); } } // end RTC play code -static INLINE uint32_t variance(const Diff *const d) { - return d->sse - (uint32_t)(((int64_t)d->sum * d->sum) >> 8); -} - -#if CONFIG_VP9_HIGHBITDEPTH -static INLINE uint32_t variance_highbd(Diff *const d) { - const int64_t var = (int64_t)d->sse - (((int64_t)d->sum * d->sum) >> 8); - return (var >= 0) ? (uint32_t)var : 0; -} -#endif // CONFIG_VP9_HIGHBITDEPTH - -static int set_var_thresh_from_histogram(VP9_COMP *cpi) { - const SPEED_FEATURES *const sf = &cpi->sf; - const VP9_COMMON *const cm = &cpi->common; - - const uint8_t *src = cpi->Source->y_buffer; - const uint8_t *last_src = cpi->Last_Source->y_buffer; - const int src_stride = cpi->Source->y_stride; - const int last_stride = cpi->Last_Source->y_stride; - - // Pick cutoff threshold - const int cutoff = (VPXMIN(cm->width, cm->height) >= 720) - ? (cm->MBs * VAR_HIST_LARGE_CUT_OFF / 100) - : (cm->MBs * VAR_HIST_SMALL_CUT_OFF / 100); - DECLARE_ALIGNED(16, int, hist[VAR_HIST_BINS]); - Diff *var16 = cpi->source_diff_var; - - int sum = 0; - int i, j; - - memset(hist, 0, VAR_HIST_BINS * sizeof(hist[0])); - - for (i = 0; i < cm->mb_rows; i++) { - for (j = 0; j < cm->mb_cols; j++) { -#if CONFIG_VP9_HIGHBITDEPTH - if (cm->use_highbitdepth) { - switch (cm->bit_depth) { - case VPX_BITS_8: - vpx_highbd_8_get16x16var(src, src_stride, last_src, last_stride, - &var16->sse, &var16->sum); - var16->var = variance(var16); - break; - case VPX_BITS_10: - vpx_highbd_10_get16x16var(src, src_stride, last_src, last_stride, - &var16->sse, &var16->sum); - var16->var = variance_highbd(var16); - break; - default: - assert(cm->bit_depth == VPX_BITS_12); - vpx_highbd_12_get16x16var(src, src_stride, last_src, last_stride, - &var16->sse, &var16->sum); - var16->var = variance_highbd(var16); - break; - } - } else { - vpx_get16x16var(src, src_stride, last_src, last_stride, &var16->sse, - &var16->sum); - var16->var = variance(var16); - } -#else - vpx_get16x16var(src, src_stride, last_src, last_stride, &var16->sse, - &var16->sum); - var16->var = variance(var16); -#endif // CONFIG_VP9_HIGHBITDEPTH - - if (var16->var >= VAR_HIST_MAX_BG_VAR) - hist[VAR_HIST_BINS - 1]++; - else - hist[var16->var / VAR_HIST_FACTOR]++; - - src += 16; - last_src += 16; - var16++; - } - - src = src - cm->mb_cols * 16 + 16 * src_stride; - last_src = last_src - cm->mb_cols * 16 + 16 * last_stride; - } - - cpi->source_var_thresh = 0; - - if (hist[VAR_HIST_BINS - 1] < cutoff) { - for (i = 0; i < VAR_HIST_BINS - 1; i++) { - sum += hist[i]; - - if (sum > cutoff) { - cpi->source_var_thresh = (i + 1) * VAR_HIST_FACTOR; - return 0; - } - } - } - - return sf->search_type_check_frequency; -} - -static void source_var_based_partition_search_method(VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - SPEED_FEATURES *const sf = &cpi->sf; - - if (cm->frame_type == KEY_FRAME) { - // For key frame, use SEARCH_PARTITION. - sf->partition_search_type = SEARCH_PARTITION; - } else if (cm->intra_only) { - sf->partition_search_type = FIXED_PARTITION; - } else { - if (cm->last_width != cm->width || cm->last_height != cm->height) { - if (cpi->source_diff_var) vpx_free(cpi->source_diff_var); - - CHECK_MEM_ERROR(&cm->error, cpi->source_diff_var, - vpx_calloc(cm->MBs, sizeof(cpi->source_diff_var))); - } - - if (!cpi->frames_till_next_var_check) - cpi->frames_till_next_var_check = set_var_thresh_from_histogram(cpi); - - if (cpi->frames_till_next_var_check > 0) { - sf->partition_search_type = FIXED_PARTITION; - cpi->frames_till_next_var_check--; - } - } -} - static int get_skip_encode_frame(const VP9_COMMON *cm, ThreadData *const td) { unsigned int intra_count = 0, inter_count = 0; int j; for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) { @@ -6137,13 +5682,10 @@ if (cm->frame_type != KEY_FRAME && cpi->rc.frames_since_golden == 0 && !(cpi->oxcf.lag_in_frames > 0 && cpi->oxcf.rc_mode == VPX_VBR) && !cpi->use_svc) cpi->ref_frame_flags &= (~VP9_GOLD_FLAG); - - if (sf->partition_search_type == SOURCE_VAR_BASED_PARTITION) - source_var_based_partition_search_method(cpi); } else if (gf_group_index && gf_group_index < MAX_ARF_GOP_SIZE && cpi->sf.enable_tpl_model) { TplDepFrame *tpl_frame = &cpi->tpl_stats[cpi->twopass.gf_group.index]; TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; @@ -6177,12 +5719,14 @@ // Frame segmentation if (cpi->oxcf.aq_mode == PERCEPTUAL_AQ) build_kmeans_segmentation(cpi); { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); +#endif if (!cpi->row_mt) { cpi->row_mt_sync_read_ptr = vp9_row_mt_sync_read_dummy; cpi->row_mt_sync_write_ptr = vp9_row_mt_sync_write_dummy; // If allowed, encoding tiles in parallel with one thread handling one @@ -6195,12 +5739,14 @@ cpi->row_mt_sync_read_ptr = vp9_row_mt_sync_read; cpi->row_mt_sync_write_ptr = vp9_row_mt_sync_write; vp9_encode_tiles_row_mt(cpi); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&emr_timer); cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer); +#endif } sf->skip_encode_frame = sf->skip_encode_sb ? get_skip_encode_frame(cm, td) : 0; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h @@ -283,11 +283,10 @@ VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode; int row_mt; unsigned int motion_vector_unit_test; int delta_q_uv; - int use_simple_encode_api; // Use SimpleEncode APIs or not } VP9EncoderConfig; static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) { return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0; } @@ -523,147 +522,10 @@ double value; int pos; int group_idx; } KMEANS_DATA; -#if CONFIG_RATE_CTRL -typedef struct PARTITION_INFO { - int row; // row pixel offset of current 4x4 block - int column; // column pixel offset of current 4x4 block - int row_start; // row pixel offset of the start of the prediction block - int column_start; // column pixel offset of the start of the prediction block - int width; // prediction block width - int height; // prediction block height -} PARTITION_INFO; - -typedef struct MOTION_VECTOR_INFO { - MV_REFERENCE_FRAME ref_frame[2]; - int_mv mv[2]; -} MOTION_VECTOR_INFO; - -typedef struct GOP_COMMAND { - int use; // use this command to set gop or not. If not, use vp9's decision. - int show_frame_count; - int use_alt_ref; -} GOP_COMMAND; - -static INLINE void gop_command_on(GOP_COMMAND *gop_command, - int show_frame_count, int use_alt_ref) { - gop_command->use = 1; - gop_command->show_frame_count = show_frame_count; - gop_command->use_alt_ref = use_alt_ref; -} - -static INLINE void gop_command_off(GOP_COMMAND *gop_command) { - gop_command->use = 0; - gop_command->show_frame_count = 0; - gop_command->use_alt_ref = 0; -} - -static INLINE int gop_command_coding_frame_count( - const GOP_COMMAND *gop_command) { - if (gop_command->use == 0) { - assert(0); - return -1; - } - return gop_command->show_frame_count + gop_command->use_alt_ref; -} - -// TODO(angiebird): See if we can merge this one with FrameType in -// simple_encode.h -typedef enum ENCODE_FRAME_TYPE { - ENCODE_FRAME_TYPE_KEY, - ENCODE_FRAME_TYPE_INTER, - ENCODE_FRAME_TYPE_ALTREF, - ENCODE_FRAME_TYPE_OVERLAY, - ENCODE_FRAME_TYPE_GOLDEN, - ENCODE_FRAME_TYPES, -} ENCODE_FRAME_TYPE; - -// TODO(angiebird): Merge this function with get_frame_type_from_update_type() -static INLINE ENCODE_FRAME_TYPE -get_encode_frame_type(FRAME_UPDATE_TYPE update_type) { - switch (update_type) { - case KF_UPDATE: return ENCODE_FRAME_TYPE_KEY; - case ARF_UPDATE: return ENCODE_FRAME_TYPE_ALTREF; - case GF_UPDATE: return ENCODE_FRAME_TYPE_GOLDEN; - case OVERLAY_UPDATE: return ENCODE_FRAME_TYPE_OVERLAY; - case LF_UPDATE: return ENCODE_FRAME_TYPE_INTER; - default: - fprintf(stderr, "Unsupported update_type %d\n", update_type); - abort(); - return ENCODE_FRAME_TYPE_INTER; - } -} - -typedef struct RATE_QSTEP_MODEL { - // The rq model predicts the bit usage as follows. - // rate = bias - ratio * log2(q_step) - int ready; - double bias; - double ratio; -} RATE_QSTEP_MODEL; - -typedef struct ENCODE_COMMAND { - int use_external_quantize_index; - int external_quantize_index; - - int use_external_target_frame_bits; - int target_frame_bits; - double target_frame_bits_error_percent; - - GOP_COMMAND gop_command; -} ENCODE_COMMAND; - -static INLINE void encode_command_set_gop_command( - ENCODE_COMMAND *encode_command, GOP_COMMAND gop_command) { - encode_command->gop_command = gop_command; -} - -static INLINE void encode_command_set_external_quantize_index( - ENCODE_COMMAND *encode_command, int quantize_index) { - encode_command->use_external_quantize_index = 1; - encode_command->external_quantize_index = quantize_index; -} - -static INLINE void encode_command_reset_external_quantize_index( - ENCODE_COMMAND *encode_command) { - encode_command->use_external_quantize_index = 0; - encode_command->external_quantize_index = -1; -} - -static INLINE void encode_command_set_target_frame_bits( - ENCODE_COMMAND *encode_command, int target_frame_bits, - double target_frame_bits_error_percent) { - encode_command->use_external_target_frame_bits = 1; - encode_command->target_frame_bits = target_frame_bits; - encode_command->target_frame_bits_error_percent = - target_frame_bits_error_percent; -} - -static INLINE void encode_command_reset_target_frame_bits( - ENCODE_COMMAND *encode_command) { - encode_command->use_external_target_frame_bits = 0; - encode_command->target_frame_bits = -1; - encode_command->target_frame_bits_error_percent = 0; -} - -static INLINE void encode_command_init(ENCODE_COMMAND *encode_command) { - vp9_zero(*encode_command); - encode_command_reset_external_quantize_index(encode_command); - encode_command_reset_target_frame_bits(encode_command); - gop_command_off(&encode_command->gop_command); -} - -// Returns number of units in size of 4, if not multiple not a multiple of 4, -// round it up. For example, size is 7, return 2. -static INLINE int get_num_unit_4x4(int size) { return (size + 3) >> 2; } -// Returns number of units in size of 16, if not multiple not a multiple of 16, -// round it up. For example, size is 17, return 2. -static INLINE int get_num_unit_16x16(int size) { return (size + 15) >> 4; } -#endif // CONFIG_RATE_CTRL - #if CONFIG_COLLECT_COMPONENT_TIMING #include "vpx_ports/vpx_timer.h" // Adjust the following to add new components. typedef enum { vp9_get_compressed_data_time, @@ -865,14 +727,16 @@ fractional_mv_step_fp *find_fractional_mv_step; struct scale_factors me_sf; vp9_diamond_search_fn_t diamond_search_sad; vp9_variance_fn_ptr_t fn_ptr[BLOCK_SIZES]; +#if CONFIG_INTERNAL_STATS uint64_t time_receive_data; uint64_t time_compress_data; uint64_t time_pick_lpf; uint64_t time_encode_sb_row; +#endif TWO_PASS twopass; // Force recalculation of segment_ids for each mode info uint8_t force_update_segmentation; @@ -936,16 +800,10 @@ int use_svc; SVC svc; - // Store frame variance info in SOURCE_VAR_BASED_PARTITION search type. - Diff *source_diff_var; - // The threshold used in SOURCE_VAR_BASED_PARTITION search type. - unsigned int source_var_thresh; - int frames_till_next_var_check; - int frame_flags; search_site_config ss_cfg; int mbmode_cost[INTRA_MODES]; @@ -1035,19 +893,10 @@ int multi_layer_arf; vpx_roi_map_t roi; LOOPFILTER_CONTROL loopfilter_ctrl; -#if CONFIG_RATE_CTRL - ENCODE_COMMAND encode_command; - PARTITION_INFO *partition_info; - MOTION_VECTOR_INFO *motion_vector_info; - MOTION_VECTOR_INFO *fp_motion_vector_info; - TplDepStats *tpl_stats_info; - - RATE_QSTEP_MODEL rq_model[ENCODE_FRAME_TYPES]; -#endif EXT_RATECTRL ext_ratectrl; int fixed_qp_onepass; // Flag to keep track of dynamic change in deadline mode @@ -1072,151 +921,20 @@ */ uint64_t frame_component_time[kTimingComponents]; #endif } VP9_COMP; -#if CONFIG_RATE_CTRL -// Allocates memory for the partition information. -// The unit size is each 4x4 block. -// Only called once in vp9_create_compressor(). -static INLINE void partition_info_init(struct VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - const int unit_width = get_num_unit_4x4(cpi->frame_info.frame_width); - const int unit_height = get_num_unit_4x4(cpi->frame_info.frame_height); - CHECK_MEM_ERROR(&cm->error, cpi->partition_info, - (PARTITION_INFO *)vpx_calloc(unit_width * unit_height, - sizeof(PARTITION_INFO))); - memset(cpi->partition_info, 0, - unit_width * unit_height * sizeof(PARTITION_INFO)); -} - -// Frees memory of the partition information. -// Only called once in dealloc_compressor_data(). -static INLINE void free_partition_info(struct VP9_COMP *cpi) { - vpx_free(cpi->partition_info); - cpi->partition_info = NULL; -} - -static INLINE void reset_mv_info(MOTION_VECTOR_INFO *mv_info) { - mv_info->ref_frame[0] = NO_REF_FRAME; - mv_info->ref_frame[1] = NO_REF_FRAME; - mv_info->mv[0].as_int = INVALID_MV; - mv_info->mv[1].as_int = INVALID_MV; -} - -// Allocates memory for the motion vector information. -// The unit size is each 4x4 block. -// Only called once in vp9_create_compressor(). -static INLINE void motion_vector_info_init(struct VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - const int unit_width = get_num_unit_4x4(cpi->frame_info.frame_width); - const int unit_height = get_num_unit_4x4(cpi->frame_info.frame_height); - CHECK_MEM_ERROR(&cm->error, cpi->motion_vector_info, - (MOTION_VECTOR_INFO *)vpx_calloc(unit_width * unit_height, - sizeof(MOTION_VECTOR_INFO))); - memset(cpi->motion_vector_info, 0, - unit_width * unit_height * sizeof(MOTION_VECTOR_INFO)); -} - -// Frees memory of the motion vector information. -// Only called once in dealloc_compressor_data(). -static INLINE void free_motion_vector_info(struct VP9_COMP *cpi) { - vpx_free(cpi->motion_vector_info); - cpi->motion_vector_info = NULL; -} - -// Allocates memory for the tpl stats information. -// Only called once in vp9_create_compressor(). -static INLINE void tpl_stats_info_init(struct VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - CHECK_MEM_ERROR( - &cm->error, cpi->tpl_stats_info, - (TplDepStats *)vpx_calloc(MAX_LAG_BUFFERS, sizeof(TplDepStats))); - memset(cpi->tpl_stats_info, 0, MAX_LAG_BUFFERS * sizeof(TplDepStats)); -} - -// Frees memory of the tpl stats information. -// Only called once in dealloc_compressor_data(). -static INLINE void free_tpl_stats_info(struct VP9_COMP *cpi) { - vpx_free(cpi->tpl_stats_info); - cpi->tpl_stats_info = NULL; -} - -// Allocates memory for the first pass motion vector information. -// The unit size is each 16x16 block. -// Only called once in vp9_create_compressor(). -static INLINE void fp_motion_vector_info_init(struct VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - const int unit_width = get_num_unit_16x16(cpi->frame_info.frame_width); - const int unit_height = get_num_unit_16x16(cpi->frame_info.frame_height); - CHECK_MEM_ERROR(&cm->error, cpi->fp_motion_vector_info, - (MOTION_VECTOR_INFO *)vpx_calloc(unit_width * unit_height, - sizeof(MOTION_VECTOR_INFO))); -} - -static INLINE void fp_motion_vector_info_reset( - int frame_width, int frame_height, - MOTION_VECTOR_INFO *fp_motion_vector_info) { - const int unit_width = get_num_unit_16x16(frame_width); - const int unit_height = get_num_unit_16x16(frame_height); - int i; - for (i = 0; i < unit_width * unit_height; ++i) { - reset_mv_info(fp_motion_vector_info + i); - } -} - -// Frees memory of the first pass motion vector information. -// Only called once in dealloc_compressor_data(). -static INLINE void free_fp_motion_vector_info(struct VP9_COMP *cpi) { - vpx_free(cpi->fp_motion_vector_info); - cpi->fp_motion_vector_info = NULL; -} - -// This is the c-version counter part of ImageBuffer -typedef struct IMAGE_BUFFER { - int allocated; - int plane_width[3]; - int plane_height[3]; - uint8_t *plane_buffer[3]; -} IMAGE_BUFFER; - -#define RATE_CTRL_MAX_RECODE_NUM 7 - -typedef struct RATE_QINDEX_HISTORY { - int recode_count; - int q_index_history[RATE_CTRL_MAX_RECODE_NUM]; - int rate_history[RATE_CTRL_MAX_RECODE_NUM]; - int q_index_high; - int q_index_low; -} RATE_QINDEX_HISTORY; - -#endif // CONFIG_RATE_CTRL - typedef struct ENCODE_FRAME_RESULT { int show_idx; FRAME_UPDATE_TYPE update_type; -#if CONFIG_RATE_CTRL - int frame_coding_index; - int ref_frame_coding_indexes[MAX_INTER_REF_FRAMES]; - int ref_frame_valid_list[MAX_INTER_REF_FRAMES]; - double psnr; - uint64_t sse; - FRAME_COUNTS frame_counts; - const PARTITION_INFO *partition_info; - const MOTION_VECTOR_INFO *motion_vector_info; - const TplDepStats *tpl_stats_info; - IMAGE_BUFFER coded_frame; - RATE_QINDEX_HISTORY rq_history; -#endif // CONFIG_RATE_CTRL int quantize_index; } ENCODE_FRAME_RESULT; void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result); void vp9_initialize_enc(void); -void vp9_update_compressor_with_img_fmt(VP9_COMP *cpi, vpx_img_fmt_t img_fmt); struct VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf, BufferPool *const pool); void vp9_remove_compressor(VP9_COMP *cpi); void vp9_change_config(VP9_COMP *cpi, const VP9EncoderConfig *oxcf); @@ -1475,11 +1193,11 @@ static INLINE int log_tile_cols_from_picsize_level(uint32_t width, uint32_t height) { int i; const uint32_t pic_size = width * height; const uint32_t pic_breadth = VPXMAX(width, height); - for (i = LEVEL_1; i < LEVEL_MAX; ++i) { + for (i = 0; i < VP9_LEVELS; ++i) { if (vp9_level_defs[i].max_luma_picture_size >= pic_size && vp9_level_defs[i].max_luma_picture_breadth >= pic_breadth) { return get_msb(vp9_level_defs[i].max_col_tiles); } } diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c @@ -1026,19 +1026,10 @@ cpi->sb_mul_scale = NULL; vpx_free(cpi->mi_ssim_rdmult_scaling_factors); cpi->mi_ssim_rdmult_scaling_factors = NULL; -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - free_partition_info(cpi); - free_motion_vector_info(cpi); - free_fp_motion_vector_info(cpi); - free_tpl_stats_info(cpi); - } -#endif - vp9_free_ref_frame_buffers(cm->buffer_pool); #if CONFIG_VP9_POSTPROC vp9_free_postproc_buffers(cm); #endif vp9_free_context_buffers(cm); @@ -1067,15 +1058,10 @@ vpx_free(lc->rc_twopass_stats_in.buf); lc->rc_twopass_stats_in.buf = NULL; lc->rc_twopass_stats_in.sz = 0; } - if (cpi->source_diff_var != NULL) { - vpx_free(cpi->source_diff_var); - cpi->source_diff_var = NULL; - } - for (i = 0; i < MAX_LAG_BUFFERS; ++i) { vpx_free_frame_buffer(&cpi->svc.scaled_frames[i]); } memset(&cpi->svc.scaled_frames[0], 0, MAX_LAG_BUFFERS * sizeof(cpi->svc.scaled_frames[0])); @@ -1432,11 +1418,18 @@ int min_log2_tile_cols, max_log2_tile_cols; vp9_get_tile_n_bits(cm->mi_cols, &min_log2_tile_cols, &max_log2_tile_cols); cm->log2_tile_cols = clamp(cpi->oxcf.tile_columns, min_log2_tile_cols, max_log2_tile_cols); - cm->log2_tile_rows = cpi->oxcf.tile_rows; + + // Max allowed number of tile_rows is 4 (so log2_tile_rows = 2), and each + // tile_row contains a multiple of superblocks. + const int sb64_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> 3; + const int max_log2_tile_rows = (sb64_rows >= 4) ? 2 + : (sb64_rows >= 2) ? 1 + : 0; + cm->log2_tile_rows = VPXMIN(cpi->oxcf.tile_rows, max_log2_tile_rows); if (cpi->oxcf.target_level == LEVEL_AUTO) { const int level_tile_cols = log_tile_cols_from_picsize_level(cpi->common.width, cpi->common.height); if (cm->log2_tile_cols > level_tile_cols) { @@ -2378,61 +2371,10 @@ } cpi->initial_mbs = cm->MBs; } } -// TODO(angiebird): Check whether we can move this function to vpx_image.c -static INLINE void vpx_img_chroma_subsampling(vpx_img_fmt_t fmt, - unsigned int *subsampling_x, - unsigned int *subsampling_y) { - switch (fmt) { - case VPX_IMG_FMT_I420: - case VPX_IMG_FMT_YV12: - case VPX_IMG_FMT_NV12: - case VPX_IMG_FMT_I422: - case VPX_IMG_FMT_I42016: - case VPX_IMG_FMT_I42216: *subsampling_x = 1; break; - default: *subsampling_x = 0; break; - } - - switch (fmt) { - case VPX_IMG_FMT_I420: - case VPX_IMG_FMT_I440: - case VPX_IMG_FMT_YV12: - case VPX_IMG_FMT_NV12: - case VPX_IMG_FMT_I42016: - case VPX_IMG_FMT_I44016: *subsampling_y = 1; break; - default: *subsampling_y = 0; break; - } -} - -// TODO(angiebird): Check whether we can move this function to vpx_image.c -static INLINE int vpx_img_use_highbitdepth(vpx_img_fmt_t fmt) { - return fmt & VPX_IMG_FMT_HIGHBITDEPTH; -} - -void vp9_update_compressor_with_img_fmt(VP9_COMP *cpi, vpx_img_fmt_t img_fmt) { - const VP9EncoderConfig *oxcf = &cpi->oxcf; - unsigned int subsampling_x, subsampling_y; - const int use_highbitdepth = vpx_img_use_highbitdepth(img_fmt); - vpx_img_chroma_subsampling(img_fmt, &subsampling_x, &subsampling_y); - - update_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y); -#if CONFIG_VP9_TEMPORAL_DENOISING - setup_denoiser_buffer(cpi); -#endif - - assert(cpi->lookahead == NULL); - cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height, subsampling_x, - subsampling_y, -#if CONFIG_VP9_HIGHBITDEPTH - use_highbitdepth, -#endif - oxcf->lag_in_frames); - alloc_raw_frame_buffers(cpi); -} - VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf, BufferPool *const pool) { unsigned int i; VP9_COMP *volatile const cpi = vpx_memalign(32, sizeof(*cpi)); VP9_COMMON *volatile const cm = cpi != NULL ? &cpi->common : NULL; @@ -2710,15 +2652,10 @@ #endif // CONFIG_NON_GREEDY_MV for (i = 0; i < MAX_ARF_GOP_SIZE; ++i) { cpi->tpl_stats[i].tpl_stats_ptr = NULL; } - // Allocate memory to store variances for a frame. - CHECK_MEM_ERROR(&cm->error, cpi->source_diff_var, - vpx_calloc(cm->MBs, sizeof(cpi->source_diff_var))); - cpi->source_var_thresh = 0; - cpi->frames_till_next_var_check = 0; #define BFP(BT, SDF, SDSF, SDAF, VF, SVF, SVAF, SDX4DF, SDSX4DF) \ cpi->fn_ptr[BT].sdf = SDF; \ cpi->fn_ptr[BT].sdsf = SDSF; \ cpi->fn_ptr[BT].sdaf = SDAF; \ cpi->fn_ptr[BT].vf = VF; \ @@ -2803,20 +2740,10 @@ #endif // CONFIG_VP9_HIGHBITDEPTH cpi->td.mb.me_sf = &cpi->me_sf; cm->error.setjmp = 0; -#if CONFIG_RATE_CTRL - encode_command_init(&cpi->encode_command); - if (oxcf->use_simple_encode_api) { - partition_info_init(cpi); - motion_vector_info_init(cpi); - fp_motion_vector_info_init(cpi); - tpl_stats_info_init(cpi); - } -#endif - return cpi; } #if CONFIG_INTERNAL_STATS #define SNPRINT(H, T) snprintf((H) + strlen(H), sizeof(H) - strlen(H), (T)) @@ -3002,13 +2929,15 @@ int vp9_get_psnr(const VP9_COMP *cpi, PSNR_STATS *psnr) { if (is_psnr_calc_enabled(cpi)) { #if CONFIG_VP9_HIGHBITDEPTH vpx_calc_highbd_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, psnr, - cpi->td.mb.e_mbd.bd, cpi->oxcf.input_bit_depth); + cpi->td.mb.e_mbd.bd, cpi->oxcf.input_bit_depth, + cpi->svc.spatial_layer_id); #else - vpx_calc_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, psnr); + vpx_calc_psnr(cpi->raw_source_frame, cpi->common.frame_to_show, psnr, + cpi->svc.spatial_layer_id); #endif return 1; } else { vp9_zero(*psnr); return 0; @@ -3498,15 +3427,19 @@ if (xd->lossless) { lf->filter_level = 0; lf->last_filt_level = 0; } else { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif vpx_clear_system_state(); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (!cpi->rc.is_src_frame_alt_ref) { if ((cpi->common.frame_type == KEY_FRAME) && (!cpi->rc.this_key_frame_forced)) { lf->last_filt_level = 0; @@ -3515,12 +3448,14 @@ lf->last_filt_level = lf->filter_level; } else { lf->filter_level = 0; } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); +#endif } if (lf->filter_level > 0 && is_reference_frame) { vp9_build_mask_frame(cm, lf->filter_level, 0); @@ -4146,18 +4081,16 @@ (cm->mi_stride >> 3) * ((cm->mi_rows >> 3) + 1) * sizeof(*cpi->content_state_sb_fd)); } // Avoid scaling last_source unless its needed. - // Last source is needed if avg_source_sad() is used, or if - // partition_search_type == SOURCE_VAR_BASED_PARTITION, or if noise - // estimation is enabled. + // Last source is needed if avg_source_sad() is used, or if noise estimation + // is enabled. if (cpi->unscaled_last_source != NULL && (cpi->oxcf.content == VP9E_CONTENT_SCREEN || (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_VBR && cpi->oxcf.mode == REALTIME && cpi->oxcf.speed >= 5) || - cpi->sf.partition_search_type == SOURCE_VAR_BASED_PARTITION || (cpi->noise_estimate.enabled && !cpi->oxcf.noise_sensitivity) || cpi->compute_source_sad_onepass)) cpi->Last_Source = vp9_scale_if_required( cm, cpi->unscaled_last_source, &cpi->scaled_last_source, (cpi->oxcf.pass == 0), EIGHTTAP, 0); @@ -4412,154 +4345,12 @@ int qstep = rate_limit ? ((rate_excess + rate_limit / 2) / rate_limit) : INT_MAX; return VPXMIN(qstep, MAX_QSTEP_ADJ); } -#if CONFIG_RATE_CTRL -static void init_rq_history(RATE_QINDEX_HISTORY *rq_history) { - rq_history->recode_count = 0; - rq_history->q_index_high = 255; - rq_history->q_index_low = 0; -} - -static void update_rq_history(RATE_QINDEX_HISTORY *rq_history, int target_bits, - int actual_bits, int q_index) { - rq_history->q_index_history[rq_history->recode_count] = q_index; - rq_history->rate_history[rq_history->recode_count] = actual_bits; - if (actual_bits <= target_bits) { - rq_history->q_index_high = q_index; - } - if (actual_bits >= target_bits) { - rq_history->q_index_low = q_index; - } - rq_history->recode_count += 1; -} - -static int guess_q_index_from_model(const RATE_QSTEP_MODEL *rq_model, - int target_bits) { - // The model predicts bits as follows. - // target_bits = bias - ratio * log2(q_step) - // Given the target_bits, we compute the q_step as follows. - double q_step; - assert(rq_model->ratio > 0); - q_step = pow(2.0, (rq_model->bias - target_bits) / rq_model->ratio); - // TODO(angiebird): Make this function support highbitdepth. - return vp9_convert_q_to_qindex(q_step, VPX_BITS_8); -} - -static int guess_q_index_linear(int prev_q_index, int target_bits, - int actual_bits, int gap) { - int q_index = prev_q_index; - if (actual_bits < target_bits) { - q_index -= gap; - q_index = VPXMAX(q_index, 0); - } else { - q_index += gap; - q_index = VPXMIN(q_index, 255); - } - return q_index; -} - -static double get_bits_percent_diff(int target_bits, int actual_bits) { - double diff; - target_bits = VPXMAX(target_bits, 1); - diff = abs(target_bits - actual_bits) * 1. / target_bits; - return diff * 100; -} - -static int rq_model_predict_q_index(const RATE_QSTEP_MODEL *rq_model, - const RATE_QINDEX_HISTORY *rq_history, - int target_bits) { - int q_index = 128; - if (rq_history->recode_count > 0) { - const int actual_bits = - rq_history->rate_history[rq_history->recode_count - 1]; - const int prev_q_index = - rq_history->q_index_history[rq_history->recode_count - 1]; - const double percent_diff = get_bits_percent_diff(target_bits, actual_bits); - if (percent_diff > 50) { - // Binary search. - // When the actual_bits and target_bits are far apart, binary search - // q_index is faster. - q_index = (rq_history->q_index_low + rq_history->q_index_high) / 2; - } else { - if (rq_model->ready) { - q_index = guess_q_index_from_model(rq_model, target_bits); - } else { - // TODO(angiebird): Find a better way to set the gap. - q_index = - guess_q_index_linear(prev_q_index, target_bits, actual_bits, 20); - } - } - } else { - if (rq_model->ready) { - q_index = guess_q_index_from_model(rq_model, target_bits); - } - } - - assert(rq_history->q_index_low <= rq_history->q_index_high); - if (q_index <= rq_history->q_index_low) { - q_index = rq_history->q_index_low + 1; - } - if (q_index >= rq_history->q_index_high) { - q_index = rq_history->q_index_high - 1; - } - return q_index; -} - -static void rq_model_update(const RATE_QINDEX_HISTORY *rq_history, - int target_bits, RATE_QSTEP_MODEL *rq_model) { - const int recode_count = rq_history->recode_count; - const double delta = 0.00001; - if (recode_count >= 2) { - const int q_index1 = rq_history->q_index_history[recode_count - 2]; - const int q_index2 = rq_history->q_index_history[recode_count - 1]; - const int r1 = rq_history->rate_history[recode_count - 2]; - const int r2 = rq_history->rate_history[recode_count - 1]; - int valid = 0; - // lower q_index should yield higher bit rate - if (q_index1 < q_index2) { - valid = r1 > r2; - } else if (q_index1 > q_index2) { - valid = r1 < r2; - } - // Only update the model when the q_index and rate behave normally. - if (valid) { - // Fit the ratio and bias of rq_model based on last two recode histories. - const double s1 = vp9_convert_qindex_to_q(q_index1, VPX_BITS_8); - const double s2 = vp9_convert_qindex_to_q(q_index2, VPX_BITS_8); - if (fabs(log2(s1) - log2(s2)) > delta) { - rq_model->ratio = (r2 - r1) / (log2(s1) - log2(s2)); - rq_model->bias = r1 + (rq_model->ratio) * log2(s1); - if (rq_model->ratio > delta && rq_model->bias > delta) { - rq_model->ready = 1; - } - } - } - } else if (recode_count == 1) { - if (rq_model->ready) { - // Update the ratio only when the initial model exists and we only have - // one recode history. - const int prev_q = rq_history->q_index_history[recode_count - 1]; - const double prev_q_step = vp9_convert_qindex_to_q(prev_q, VPX_BITS_8); - if (fabs(log2(prev_q_step)) > delta) { - const int actual_bits = rq_history->rate_history[recode_count - 1]; - rq_model->ratio = - rq_model->ratio + (target_bits - actual_bits) / log2(prev_q_step); - } - } - } -} -#endif // CONFIG_RATE_CTRL - static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest, - size_t dest_size -#if CONFIG_RATE_CTRL - , - RATE_QINDEX_HISTORY *rq_history -#endif // CONFIG_RATE_CTRL -) { + size_t dest_size) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; int bottom_index, top_index; int loop_count = 0; @@ -4575,21 +4366,10 @@ int qrange_adj = 1; #endif const int orig_rc_max_frame_bandwidth = rc->max_frame_bandwidth; -#if CONFIG_RATE_CTRL - RATE_QSTEP_MODEL *rq_model; - { - const FRAME_UPDATE_TYPE update_type = - cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index]; - const ENCODE_FRAME_TYPE frame_type = get_encode_frame_type(update_type); - rq_model = &cpi->rq_model[frame_type]; - } - init_rq_history(rq_history); -#endif // CONFIG_RATE_CTRL - if (cm->show_existing_frame) { rc->this_frame_target = 0; if (is_psnr_calc_enabled(cpi)) set_raw_source_frame(cpi); return; } @@ -4674,23 +4454,10 @@ release_scaled_references(cpi); } vp9_scale_references(cpi); } -#if CONFIG_RATE_CTRL - // TODO(angiebird): This is a hack for making sure the encoder use the - // external_quantize_index exactly. Avoid this kind of hack later. - if (cpi->oxcf.use_simple_encode_api) { - if (cpi->encode_command.use_external_target_frame_bits) { - q = rq_model_predict_q_index(rq_model, rq_history, - rc->this_frame_target); - } - if (cpi->encode_command.use_external_quantize_index) { - q = cpi->encode_command.external_quantize_index; - } - } -#endif // CONFIG_RATE_CTRL const GF_GROUP *gf_group = &cpi->twopass.gf_group; int ext_rc_delta_q_uv = 0; if (cpi->ext_ratectrl.ready && (cpi->ext_ratectrl.funcs.rc_type & VPX_RC_QP) != 0 && cpi->ext_ratectrl.funcs.get_encodeframe_decision != NULL) { @@ -4770,43 +4537,10 @@ if (cpi->ext_ratectrl.ready && (cpi->ext_ratectrl.funcs.rc_type & VPX_RC_QP) != 0) { break; } -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - // This part needs to be after save_coding_context() because - // restore_coding_context will be called in the end of this function. - // TODO(angiebird): This is a hack for making sure the encoder use the - // external_quantize_index exactly. Avoid this kind of hack later. - if (cpi->encode_command.use_external_quantize_index) { - break; - } - - if (cpi->encode_command.use_external_target_frame_bits) { - const double percent_diff = get_bits_percent_diff( - rc->this_frame_target, rc->projected_frame_size); - update_rq_history(rq_history, rc->this_frame_target, - rc->projected_frame_size, q); - loop_count += 1; - - rq_model_update(rq_history, rc->this_frame_target, rq_model); - - // Check if we hit the target bitrate. - if (percent_diff <= - cpi->encode_command.target_frame_bits_error_percent || - rq_history->recode_count >= RATE_CTRL_MAX_RECODE_NUM || - rq_history->q_index_low >= rq_history->q_index_high) { - break; - } - - loop = 1; - restore_coding_context(cpi); - continue; - } - } -#endif // CONFIG_RATE_CTRL if (oxcf->rc_mode == VPX_Q) { loop = 0; } else { if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced && @@ -5249,12 +4983,11 @@ VP9_COMMON *const cm = &cpi->common; // Base the filter strength on the current active max Q. const int q = (int)(vp9_convert_qindex_to_q(twopass->active_worst_quality, cm->bit_depth)); - int strength = - VPXMAX(oxcf->arnr_strength >> 2, VPXMIN(oxcf->arnr_strength, (q >> 4))); + int strength = clamp(q >> 4, oxcf->arnr_strength >> 2, oxcf->arnr_strength); // Denoise each of Y,U and V buffers. spatial_denoise_buffer(cpi, src->y_buffer, src->y_stride, src->y_width, src->y_height, strength); @@ -5513,19 +5246,20 @@ #if !CONFIG_REALTIME_ONLY static PSNR_STATS compute_psnr_stats(const YV12_BUFFER_CONFIG *source_frame, const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth, - uint32_t input_bit_depth) { + uint32_t input_bit_depth, + int spatial_layer_id) { PSNR_STATS psnr; #if CONFIG_VP9_HIGHBITDEPTH vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth, - input_bit_depth); + input_bit_depth, spatial_layer_id); #else // CONFIG_VP9_HIGHBITDEPTH (void)bit_depth; (void)input_bit_depth; - vpx_calc_psnr(source_frame, coded_frame, &psnr); + vpx_calc_psnr(source_frame, coded_frame, &psnr, spatial_layer_id); #endif // CONFIG_VP9_HIGHBITDEPTH return psnr; } static void update_encode_frame_result_basic( @@ -5533,73 +5267,10 @@ ENCODE_FRAME_RESULT *encode_frame_result) { encode_frame_result->show_idx = show_idx; encode_frame_result->update_type = update_type; encode_frame_result->quantize_index = quantize_index; } - -#if CONFIG_RATE_CTRL -static void yv12_buffer_to_image_buffer(const YV12_BUFFER_CONFIG *yv12_buffer, - IMAGE_BUFFER *image_buffer) { - const uint8_t *src_buf_ls[3] = { yv12_buffer->y_buffer, yv12_buffer->u_buffer, - yv12_buffer->v_buffer }; - const int src_stride_ls[3] = { yv12_buffer->y_stride, yv12_buffer->uv_stride, - yv12_buffer->uv_stride }; - const int w_ls[3] = { yv12_buffer->y_crop_width, yv12_buffer->uv_crop_width, - yv12_buffer->uv_crop_width }; - const int h_ls[3] = { yv12_buffer->y_crop_height, yv12_buffer->uv_crop_height, - yv12_buffer->uv_crop_height }; - int plane; - for (plane = 0; plane < 3; ++plane) { - const int src_stride = src_stride_ls[plane]; - const int w = w_ls[plane]; - const int h = h_ls[plane]; - const uint8_t *src_buf = src_buf_ls[plane]; - uint8_t *dst_buf = image_buffer->plane_buffer[plane]; - int r; - assert(image_buffer->plane_width[plane] == w); - assert(image_buffer->plane_height[plane] == h); - for (r = 0; r < h; ++r) { - memcpy(dst_buf, src_buf, sizeof(*src_buf) * w); - src_buf += src_stride; - dst_buf += w; - } - } -} - -// This function will update extra information specific for simple_encode APIs -static void update_encode_frame_result_simple_encode( - int ref_frame_flags, FRAME_UPDATE_TYPE update_type, - const YV12_BUFFER_CONFIG *source_frame, const RefCntBuffer *coded_frame_buf, - RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int quantize_index, - uint32_t bit_depth, uint32_t input_bit_depth, const FRAME_COUNTS *counts, - const PARTITION_INFO *partition_info, - const MOTION_VECTOR_INFO *motion_vector_info, - const TplDepStats *tpl_stats_info, - ENCODE_FRAME_RESULT *encode_frame_result) { - PSNR_STATS psnr; - update_encode_frame_result_basic(update_type, coded_frame_buf->frame_index, - quantize_index, encode_frame_result); - compute_psnr_stats(source_frame, &coded_frame_buf->buf, bit_depth, - input_bit_depth); - encode_frame_result->frame_coding_index = coded_frame_buf->frame_coding_index; - - vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs, - encode_frame_result->ref_frame_coding_indexes, - encode_frame_result->ref_frame_valid_list); - - encode_frame_result->psnr = psnr.psnr[0]; - encode_frame_result->sse = psnr.sse[0]; - encode_frame_result->frame_counts = *counts; - encode_frame_result->partition_info = partition_info; - encode_frame_result->motion_vector_info = motion_vector_info; - encode_frame_result->tpl_stats_info = tpl_stats_info; - if (encode_frame_result->coded_frame.allocated) { - yv12_buffer_to_image_buffer(&coded_frame_buf->buf, - &encode_frame_result->coded_frame); - } -} -#endif // CONFIG_RATE_CTRL #endif // !CONFIG_REALTIME_ONLY static void encode_frame_to_data_rate( VP9_COMP *cpi, size_t *size, uint8_t *dest, size_t dest_size, unsigned int *frame_flags, ENCODE_FRAME_RESULT *encode_frame_result) { @@ -5712,22 +5383,17 @@ if (cpi->sf.recode_loop == DISALLOW_RECODE) { if (!encode_without_recode_loop(cpi, size, dest, dest_size)) return; } else { #if !CONFIG_REALTIME_ONLY -#if CONFIG_RATE_CTRL - encode_with_recode_loop(cpi, size, dest, dest_size, - &encode_frame_result->rq_history); -#else // CONFIG_RATE_CTRL #if CONFIG_COLLECT_COMPONENT_TIMING start_timing(cpi, encode_with_recode_loop_time); #endif encode_with_recode_loop(cpi, size, dest, dest_size); #if CONFIG_COLLECT_COMPONENT_TIMING end_timing(cpi, encode_with_recode_loop_time); #endif -#endif // CONFIG_RATE_CTRL #endif // !CONFIG_REALTIME_ONLY } // TODO(jingning): When using show existing frame mode, we assume that the // current ARF will be directly used as the final reconstructed frame. This is @@ -5813,11 +5479,11 @@ } } #if CONFIG_REALTIME_ONLY (void)encode_frame_result; assert(encode_frame_result == NULL); -#else // CONFIG_REALTIME_ONLY +#else // CONFIG_REALTIME_ONLY if (encode_frame_result != NULL) { const RefCntBuffer *coded_frame_buf = get_ref_cnt_buffer(cm, cm->new_fb_idx); RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES]; FRAME_UPDATE_TYPE update_type = @@ -5842,30 +5508,17 @@ // dependent variables more robust. update_encode_frame_result_basic(update_type, coded_frame_buf->frame_index, quantize_index, encode_frame_result); if (cpi->ext_ratectrl.ready && cpi->ext_ratectrl.log_file) { - PSNR_STATS psnr = - compute_psnr_stats(cpi->Source, &coded_frame_buf->buf, cm->bit_depth, - cpi->oxcf.input_bit_depth); + PSNR_STATS psnr = compute_psnr_stats( + cpi->Source, &coded_frame_buf->buf, cm->bit_depth, + cpi->oxcf.input_bit_depth, cpi->svc.spatial_layer_id); fprintf(cpi->ext_ratectrl.log_file, "ENCODE_FRAME_RESULT gop_index %d psnr %f bits %zu\n", cpi->twopass.gf_group.index, psnr.psnr[0], (*size) << 3); } - -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - const int ref_frame_flags = get_ref_frame_flags(cpi); - update_encode_frame_result_simple_encode( - ref_frame_flags, - cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index], - cpi->Source, coded_frame_buf, ref_frame_bufs, quantize_index, - cm->bit_depth, cpi->oxcf.input_bit_depth, cpi->td.counts, - cpi->partition_info, cpi->motion_vector_info, cpi->tpl_stats_info, - encode_frame_result); - } -#endif // CONFIG_RATE_CTRL } #endif // CONFIG_REALTIME_ONLY if (cpi->rc.use_post_encode_drop && cm->base_qindex < cpi->rc.worst_quality && cpi->svc.spatial_layer_id == 0 && post_encode_drop_cbr(cpi, size)) { @@ -6027,47 +5680,65 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, vpx_enc_frame_flags_t frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) { VP9_COMMON *const cm = &cpi->common; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif int res = 0; const int subsampling_x = sd->subsampling_x; const int subsampling_y = sd->subsampling_y; #if CONFIG_VP9_HIGHBITDEPTH const int use_highbitdepth = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0; #else const int use_highbitdepth = 0; #endif + if ((cm->profile == PROFILE_0 || cm->profile == PROFILE_2) && + (subsampling_x != 1 || subsampling_y != 1)) { + vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, + "Non-4:2:0 color format requires profile 1 or 3"); + return -1; + } + if ((cm->profile == PROFILE_1 || cm->profile == PROFILE_3) && + (subsampling_x == 1 && subsampling_y == 1)) { + vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, + "4:2:0 color format requires profile 0 or 2"); + return -1; + } + if (cm->color_space == VPX_CS_SRGB) { + if (cm->profile == PROFILE_0 || cm->profile == PROFILE_2) { + vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, + "SRGB color space requires profile 1 or 3"); + return -1; + } + if (subsampling_x != 0 || subsampling_y != 0) { + vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, + "SRGB color space requires 4:4:4"); + return -1; + } + } + update_initial_width(cpi, use_highbitdepth, subsampling_x, subsampling_y); #if CONFIG_VP9_TEMPORAL_DENOISING setup_denoiser_buffer(cpi); #endif alloc_raw_frame_buffers(cpi); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, use_highbitdepth, frame_flags)) res = -1; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); - - if ((cm->profile == PROFILE_0 || cm->profile == PROFILE_2) && - (subsampling_x != 1 || subsampling_y != 1)) { - vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, - "Non-4:2:0 color format requires profile 1 or 3"); - res = -1; - } - if ((cm->profile == PROFILE_1 || cm->profile == PROFILE_3) && - (subsampling_x == 1 && subsampling_y == 1)) { - vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, - "4:2:0 color format requires profile 0 or 2"); - res = -1; - } +#endif return res; } static int frame_is_reference(const VP9_COMP *cpi) { @@ -6423,16 +6094,10 @@ } } void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) { encode_frame_result->show_idx = -1; // Actual encoding doesn't happen. -#if CONFIG_RATE_CTRL - encode_frame_result->frame_coding_index = -1; - vp9_zero(encode_frame_result->coded_frame); - encode_frame_result->coded_frame.allocated = 0; - init_rq_history(&encode_frame_result->rq_history); -#endif // CONFIG_RATE_CTRL } // Returns if TPL stats need to be calculated. static INLINE int should_run_tpl(VP9_COMP *cpi, int gf_group_index) { RATE_CONTROL *const rc = &cpi->rc; @@ -6458,11 +6123,13 @@ ENCODE_FRAME_RESULT *encode_frame_result) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; BufferPool *const pool = cm->buffer_pool; RATE_CONTROL *const rc = &cpi->rc; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer cmptimer; +#endif YV12_BUFFER_CONFIG *force_src_buffer = NULL; struct lookahead_entry *last_source = NULL; struct lookahead_entry *source = NULL; int arf_src_index; const int gf_group_index = cpi->twopass.gf_group.index; @@ -6474,11 +6141,13 @@ if (is_one_pass_svc(cpi)) { vp9_one_pass_svc_start_layer(cpi); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&cmptimer); +#endif vp9_set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV); // Is multi-arf enabled. // Note that at the moment multi_arf is only configured for 2 pass VBR and @@ -6815,12 +6484,14 @@ } if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) cpi->fixed_qp_onepass = 0; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&cmptimer); cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); +#endif if (cpi->keep_level_stats && oxcf->pass != 1) update_level_info(cpi, size, arf_src_index); #if !CONFIG_REALTIME_ONLY @@ -6852,13 +6523,13 @@ YV12_BUFFER_CONFIG *recon = cpi->common.frame_to_show; YV12_BUFFER_CONFIG *pp = &cm->post_proc_buffer; PSNR_STATS psnr; #if CONFIG_VP9_HIGHBITDEPTH vpx_calc_highbd_psnr(orig, recon, &psnr, cpi->td.mb.e_mbd.bd, - in_bit_depth); + in_bit_depth, cpi->svc.spatial_layer_id); #else - vpx_calc_psnr(orig, recon, &psnr); + vpx_calc_psnr(orig, recon, &psnr, cpi->svc.spatial_layer_id); #endif // CONFIG_VP9_HIGHBITDEPTH adjust_image_stat(psnr.psnr[1], psnr.psnr[2], psnr.psnr[3], psnr.psnr[0], &cpi->psnr); cpi->total_sq_error += psnr.sse[0]; @@ -6890,13 +6561,14 @@ #endif vpx_clear_system_state(); #if CONFIG_VP9_HIGHBITDEPTH vpx_calc_highbd_psnr(orig, pp, &psnr2, cpi->td.mb.e_mbd.bd, - cpi->oxcf.input_bit_depth); + cpi->oxcf.input_bit_depth, + cpi->svc.spatial_layer_id); #else - vpx_calc_psnr(orig, pp, &psnr2); + vpx_calc_psnr(orig, pp, &psnr2, cpi->svc.spatial_layer_id); #endif // CONFIG_VP9_HIGHBITDEPTH cpi->totalp_sq_error += psnr2.sse[0]; cpi->totalp_samples += psnr2.samples[0]; adjust_image_stat(psnr2.psnr[1], psnr2.psnr[2], psnr2.psnr[3], diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_ethread.c b/media/libvpx/libvpx/vp9/encoder/vp9_ethread.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_ethread.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_ethread.c @@ -276,17 +276,17 @@ tile_data->fp_data.sum_mvrs += tile_data_t->fp_data.sum_mvrs; tile_data->fp_data.sum_mvcs += tile_data_t->fp_data.sum_mvcs; tile_data->fp_data.sum_in_vectors += tile_data_t->fp_data.sum_in_vectors; tile_data->fp_data.intra_smooth_count += tile_data_t->fp_data.intra_smooth_count; + const int min_start_row = VPXMIN(tile_data->fp_data.image_data_start_row, + tile_data_t->fp_data.image_data_start_row); tile_data->fp_data.image_data_start_row = - VPXMIN(tile_data->fp_data.image_data_start_row, - tile_data_t->fp_data.image_data_start_row) == INVALID_ROW + (min_start_row == INVALID_ROW) ? VPXMAX(tile_data->fp_data.image_data_start_row, tile_data_t->fp_data.image_data_start_row) - : VPXMIN(tile_data->fp_data.image_data_start_row, - tile_data_t->fp_data.image_data_start_row); + : min_start_row; } #endif // !CONFIG_REALTIME_ONLY // Allocate memory for row synchronization void vp9_row_mt_sync_mem_alloc(VP9RowMTSync *row_mt_sync, VP9_COMMON *cm, diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.h b/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.h @@ -225,58 +225,10 @@ struct VP9EncoderConfig; int vp9_get_frames_to_next_key(const struct VP9EncoderConfig *oxcf, const TWO_PASS *const twopass, int kf_show_idx, int min_gf_interval); -#if CONFIG_RATE_CTRL -/* Call this function to get info about the next group of pictures. - * This function should be called after vp9_create_compressor() when encoding - * starts or after vp9_get_compressed_data() when the encoding process of - * the last group of pictures is just finished. - */ -void vp9_get_next_group_of_picture(const struct VP9_COMP *cpi, - int *first_is_key_frame, int *use_alt_ref, - int *coding_frame_count, int *first_show_idx, - int *last_gop_use_alt_ref); - -/*!\brief Call this function before coding a new group of pictures to get - * information about it. - * \param[in] oxcf Encoder config - * \param[in] twopass Twopass info - * \param[in] frame_info Frame info - * \param[in] rc Rate control state - * \param[in] show_idx Show index of the first frame in the group - * \param[in] multi_layer_arf Is multi-layer alternate reference used - * \param[in] allow_alt_ref Is alternate reference allowed - * \param[in] first_is_key_frame Is the first frame in the group a key frame - * \param[in] last_gop_use_alt_ref Does the last group use alternate reference - * - * \param[out] use_alt_ref Does this group use alternate reference - * - * \return Returns coding frame count - */ -int vp9_get_gop_coding_frame_count(const struct VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, - const FRAME_INFO *frame_info, - const RATE_CONTROL *rc, int show_idx, - int multi_layer_arf, int allow_alt_ref, - int first_is_key_frame, - int last_gop_use_alt_ref, int *use_alt_ref); - -int vp9_get_coding_frame_num(const struct VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, - const FRAME_INFO *frame_info, int multi_layer_arf, - int allow_alt_ref); - -/*!\brief Compute a key frame binary map indicates whether key frames appear - * in the corresponding positions. The passed in key_frame_map must point to an - * integer array with length equal to twopass->first_pass_info.num_frames, - * which is the number of show frames in the video. - */ -void vp9_get_key_frame_map(const struct VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, int *key_frame_map); -#endif // CONFIG_RATE_CTRL FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass); FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *twopass); #ifdef __cplusplus diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.c b/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_firstpass.c @@ -82,11 +82,11 @@ #define MINQ_ADJ_LIMIT 48 #define MINQ_ADJ_LIMIT_CQ 20 #define HIGH_UNDERSHOOT_RATIO 2 #define AV_WQ_FACTOR 4.0 -#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x)-0.000001 : (x) + 0.000001) +#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x) - 0.000001 : (x) + 0.000001) #if ARF_STATS_OUTPUT unsigned int arf_count = 0; #endif @@ -861,35 +861,19 @@ this_tile->fp_data.sum_mvc_abs += fp_acc_data->sum_mvc_abs; this_tile->fp_data.sum_mvrs += fp_acc_data->sum_mvrs; this_tile->fp_data.sum_mvcs += fp_acc_data->sum_mvcs; this_tile->fp_data.sum_in_vectors += fp_acc_data->sum_in_vectors; this_tile->fp_data.intra_smooth_count += fp_acc_data->intra_smooth_count; + const int min_start_row = VPXMIN(this_tile->fp_data.image_data_start_row, + fp_acc_data->image_data_start_row); this_tile->fp_data.image_data_start_row = - VPXMIN(this_tile->fp_data.image_data_start_row, - fp_acc_data->image_data_start_row) == INVALID_ROW + (min_start_row == INVALID_ROW) ? VPXMAX(this_tile->fp_data.image_data_start_row, fp_acc_data->image_data_start_row) - : VPXMIN(this_tile->fp_data.image_data_start_row, - fp_acc_data->image_data_start_row); + : min_start_row; } -#if CONFIG_RATE_CTRL -static void store_fp_motion_vector(VP9_COMP *cpi, const MV *mv, - const int mb_row, const int mb_col, - MV_REFERENCE_FRAME frame_type, - const int mv_idx) { - VP9_COMMON *const cm = &cpi->common; - const int mb_index = mb_row * cm->mb_cols + mb_col; - MOTION_VECTOR_INFO *this_motion_vector_info = - &cpi->fp_motion_vector_info[mb_index]; - this_motion_vector_info->ref_frame[mv_idx] = frame_type; - if (frame_type != INTRA_FRAME) { - this_motion_vector_info->mv[mv_idx].as_mv = *mv; - } -} -#endif // CONFIG_RATE_CTRL - #define NZ_MOTION_PENALTY 128 #define INTRA_MODE_PENALTY 1024 void vp9_first_pass_encode_tile_mb_row(VP9_COMP *cpi, ThreadData *td, FIRSTPASS_DATA *fp_acc_data, TileDataEnc *tile_data, MV *best_ref_mv, @@ -1116,17 +1100,10 @@ // Assume 0,0 motion with no mv overhead. MV mv = { 0, 0 }, tmp_mv = { 0, 0 }; struct buf_2d unscaled_last_source_buf_2d; vp9_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[bsize]; -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - // Store zero mv as default - store_fp_motion_vector(cpi, &mv, mb_row, mb_col, LAST_FRAME, 0); - } -#endif // CONFIG_RAGE_CTRL - xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset; #if CONFIG_VP9_HIGHBITDEPTH if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { motion_error = highbd_get_prediction_error( bsize, &x->plane[0].src, &xd->plane[0].pre[0], xd->bd); @@ -1187,15 +1164,10 @@ mv = tmp_mv; this_motion_error = vp9_get_mvpred_var(x, &tmp_mv, &zero_mv, &v_fn_ptr, 0); } } -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - store_fp_motion_vector(cpi, &mv, mb_row, mb_col, LAST_FRAME, 0); - } -#endif // CONFIG_RAGE_CTRL // Search in an older reference frame. if ((cm->current_video_frame > 1) && gld_yv12 != NULL) { // Assume 0,0 motion with no mv overhead. int gf_motion_error; @@ -1213,16 +1185,10 @@ gf_motion_error = get_prediction_error(bsize, &x->plane[0].src, &xd->plane[0].pre[0]); #endif // CONFIG_VP9_HIGHBITDEPTH first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv, &gf_motion_error); -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - store_fp_motion_vector(cpi, &tmp_mv, mb_row, mb_col, GOLDEN_FRAME, - 1); - } -#endif // CONFIG_RAGE_CTRL if (gf_motion_error < motion_error && gf_motion_error < this_error) ++(fp_acc_data->second_ref_count); // Reset to last frame as reference buffer. @@ -1344,15 +1310,10 @@ fp_acc_data->intra_count_high += 1.0; } } } else { fp_acc_data->sr_coded_error += (int64_t)this_error; -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - store_fp_motion_vector(cpi, NULL, mb_row, mb_col, INTRA_FRAME, 0); - } -#endif // CONFIG_RAGE_CTRL } fp_acc_data->coded_error += (int64_t)this_error; if (mb_col == mb_col_start) { *first_top_mv = last_nonzero_mv; @@ -1378,17 +1339,10 @@ MV zero_mv = { 0, 0 }; MV best_ref_mv; // Tiling is ignored in the first pass. vp9_tile_init(tile, cm, 0, 0); tile_data.firstpass_top_mv = zero_mv; -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - fp_motion_vector_info_reset(cpi->frame_info.frame_width, - cpi->frame_info.frame_height, - cpi->fp_motion_vector_info); - } -#endif for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) { best_ref_mv = zero_mv; vp9_first_pass_encode_tile_mb_row(cpi, &cpi->td, fp_acc_data, &tile_data, &best_ref_mv, mb_row); @@ -1580,13 +1534,13 @@ #if CONFIG_ALWAYS_ADJUST_BPM // based on recent history adjust expectations of bits per macroblock. last_group_rate_err = (double)twopass->rolling_arf_group_actual_bits / DOUBLE_DIVIDE_CHECK((double)twopass->rolling_arf_group_target_bits); - last_group_rate_err = VPXMAX(0.25, VPXMIN(4.0, last_group_rate_err)); + last_group_rate_err = fclamp(last_group_rate_err, 0.25, 4.0); twopass->bpm_factor *= (3.0 + last_group_rate_err) / 4.0; - twopass->bpm_factor = VPXMAX(0.25, VPXMIN(4.0, twopass->bpm_factor)); + twopass->bpm_factor = fclamp(twopass->bpm_factor, 0.25, 4.0); #endif if (target_rate <= 0) { return rc->worst_quality; // Highest value allowed } else { @@ -1606,13 +1560,13 @@ #if !CONFIG_ALWAYS_ADJUST_BPM // based on recent history adjust expectations of bits per macroblock. last_group_rate_err = (double)twopass->rolling_arf_group_actual_bits / DOUBLE_DIVIDE_CHECK((double)twopass->rolling_arf_group_target_bits); - last_group_rate_err = VPXMAX(0.25, VPXMIN(4.0, last_group_rate_err)); + last_group_rate_err = fclamp(last_group_rate_err, 0.25, 4.0); twopass->bpm_factor *= (3.0 + last_group_rate_err) / 4.0; - twopass->bpm_factor = VPXMAX(0.25, VPXMIN(4.0, twopass->bpm_factor)); + twopass->bpm_factor = fclamp(twopass->bpm_factor, 0.25, 4.0); #endif // Try and pick a max Q that will be high enough to encode the // content at the given rate. for (q = rc->best_quality; q < rc->worst_quality; ++q) { @@ -2624,13 +2578,10 @@ * (The following fields will be updated before or after coding each frame.) * rc->frames_to_key * rc->frames_since_key * rc->source_alt_ref_active * - * Special case: if CONFIG_RATE_CTRL is true, the external arf indexes will - * determine the arf position. - * * TODO(angiebird): Separate the dynamic fields and static fields into two * structs. */ static int get_gop_coding_frame_num( int *use_alt_ref, const FRAME_INFO *frame_info, @@ -2744,25 +2695,10 @@ *use_alt_ref &= gop_coding_frames < lag_in_frames; *use_alt_ref &= gop_coding_frames >= rc->min_gf_interval; return gop_coding_frames; } -static RANGE get_active_gf_inverval_range_simple(int min_gf_interval, - int arf_active_or_kf, - int frames_to_key) { - RANGE active_gf_interval; - active_gf_interval.min = min_gf_interval + arf_active_or_kf + 2; - active_gf_interval.max = 16 + arf_active_or_kf; - - if ((active_gf_interval.max <= frames_to_key) && - (active_gf_interval.max >= (frames_to_key - min_gf_interval))) { - active_gf_interval.min = frames_to_key / 2; - active_gf_interval.max = frames_to_key / 2; - } - return active_gf_interval; -} - static RANGE get_active_gf_inverval_range( const FRAME_INFO *frame_info, const RATE_CONTROL *rc, int arf_active_or_kf, int gf_start_show_idx, int active_worst_quality, int last_boosted_qindex) { RANGE active_gf_interval; int int_max_q = (int)(vp9_convert_qindex_to_q(active_worst_quality, @@ -2881,18 +2817,13 @@ rc->gop_global_index = 0; } vpx_clear_system_state(); - if (oxcf->use_simple_encode_api) { - active_gf_interval = get_active_gf_inverval_range_simple( - rc->min_gf_interval, arf_active_or_kf, rc->frames_to_key); - } else { - active_gf_interval = get_active_gf_inverval_range( - frame_info, rc, arf_active_or_kf, gf_start_show_idx, - twopass->active_worst_quality, rc->last_boosted_qindex); - } + active_gf_interval = get_active_gf_inverval_range( + frame_info, rc, arf_active_or_kf, gf_start_show_idx, + twopass->active_worst_quality, rc->last_boosted_qindex); if (cpi->multi_layer_arf) { int arf_layers = get_arf_layers(cpi->multi_layer_arf, oxcf->enable_auto_arf, active_gf_interval.max); gop_intra_factor = 1.0 + 0.25 * arf_layers; @@ -2909,23 +2840,10 @@ if (gop_decision_ready) { gop_coding_frames = gop_decision.gop_coding_frames; use_alt_ref = gop_decision.use_alt_ref; } -#if CONFIG_RATE_CTRL - // If the external gop_command is on, we will override the decisions - // of gop_coding_frames and use_alt_ref. - if (cpi->oxcf.use_simple_encode_api) { - const GOP_COMMAND *gop_command = &cpi->encode_command.gop_command; - assert(allow_alt_ref == 1); - if (gop_command->use) { - gop_coding_frames = gop_command_coding_frame_count(gop_command); - use_alt_ref = gop_command->use_alt_ref; - } - } -#endif - // Was the group length constrained by the requirement for a new KF? rc->constrained_gf_group = (gop_coding_frames >= rc->frames_to_key) ? 1 : 0; // Should we use the alternate reference frame. if (use_alt_ref) { @@ -3498,12 +3416,12 @@ zero_motion_avg = zero_motion_sum / num_frames; motion_compensable_avg = motion_compensable_sum / num_frames; kf_boost_scan_frames = (int)(VPXMAX(64 * zero_motion_avg - 16, 160 * motion_compensable_avg - 112)); kf_boost_scan_frames = - VPXMAX(VPXMIN(kf_boost_scan_frames, MAX_SCAN_FRAMES_FOR_KF_BOOST), - MIN_SCAN_FRAMES_FOR_KF_BOOST); + clamp(kf_boost_scan_frames, MIN_SCAN_FRAMES_FOR_KF_BOOST, + MAX_SCAN_FRAMES_FOR_KF_BOOST); } reset_fpf_position(twopass, start_position); for (i = 0; i < (rc->frames_to_key - 1); ++i) { if (EOF == input_stats(twopass, &next_frame)) break; @@ -3927,150 +3845,10 @@ } } } } -#if CONFIG_RATE_CTRL -void vp9_get_next_group_of_picture(const VP9_COMP *cpi, int *first_is_key_frame, - int *use_alt_ref, int *coding_frame_count, - int *first_show_idx, - int *last_gop_use_alt_ref) { - const GOP_COMMAND *gop_command = &cpi->encode_command.gop_command; - // We make a copy of rc here because we want to get information from the - // encoder without changing its state. - // TODO(angiebird): Avoid copying rc here. - RATE_CONTROL rc = cpi->rc; - const int multi_layer_arf = 0; - const int allow_alt_ref = 1; - // We assume that current_video_frame is updated to the show index of the - // frame we are about to called. Note that current_video_frame is updated at - // the end of encode_frame_to_data_rate(). - // TODO(angiebird): Avoid this kind of fragile style. - *first_show_idx = cpi->common.current_video_frame; - *last_gop_use_alt_ref = rc.source_alt_ref_active; - - *first_is_key_frame = 0; - if (rc.frames_to_key == 0) { - rc.frames_to_key = vp9_get_frames_to_next_key( - &cpi->oxcf, &cpi->twopass, *first_show_idx, rc.min_gf_interval); - rc.frames_since_key = 0; - *first_is_key_frame = 1; - } - - if (gop_command->use) { - *coding_frame_count = gop_command_coding_frame_count(gop_command); - *use_alt_ref = gop_command->use_alt_ref; - assert(gop_command->show_frame_count <= rc.frames_to_key); - } else { - *coding_frame_count = vp9_get_gop_coding_frame_count( - &cpi->oxcf, &cpi->twopass, &cpi->frame_info, &rc, *first_show_idx, - multi_layer_arf, allow_alt_ref, *first_is_key_frame, - *last_gop_use_alt_ref, use_alt_ref); - } -} - -int vp9_get_gop_coding_frame_count(const VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, - const FRAME_INFO *frame_info, - const RATE_CONTROL *rc, int show_idx, - int multi_layer_arf, int allow_alt_ref, - int first_is_key_frame, - int last_gop_use_alt_ref, int *use_alt_ref) { - int frame_count; - double gop_intra_factor; - const int arf_active_or_kf = last_gop_use_alt_ref || first_is_key_frame; - RANGE active_gf_interval; - int arf_layers; - int end_of_sequence = 0; - if (oxcf->use_simple_encode_api) { - active_gf_interval = get_active_gf_inverval_range_simple( - rc->min_gf_interval, arf_active_or_kf, rc->frames_to_key); - } else { - active_gf_interval = get_active_gf_inverval_range( - frame_info, rc, arf_active_or_kf, show_idx, /*active_worst_quality=*/0, - /*last_boosted_qindex=*/0); - } - - arf_layers = get_arf_layers(multi_layer_arf, oxcf->enable_auto_arf, - active_gf_interval.max); - if (multi_layer_arf) { - gop_intra_factor = 1.0 + 0.25 * arf_layers; - } else { - gop_intra_factor = 1.0; - } - - frame_count = get_gop_coding_frame_num( - use_alt_ref, frame_info, twopass, rc, show_idx, &active_gf_interval, - gop_intra_factor, oxcf->lag_in_frames, &end_of_sequence); - *use_alt_ref &= allow_alt_ref; - return frame_count; -} - -// Under CONFIG_RATE_CTRL, once the first_pass_info is ready, the number of -// coding frames (including show frame and alt ref) can be determined. -int vp9_get_coding_frame_num(const VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, - const FRAME_INFO *frame_info, int multi_layer_arf, - int allow_alt_ref) { - const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info; - int coding_frame_num = 0; - RATE_CONTROL rc; - int gop_coding_frame_count; - int gop_show_frames; - int show_idx = 0; - int last_gop_use_alt_ref = 0; - vp9_rc_init(oxcf, 1, &rc); - - while (show_idx < first_pass_info->num_frames) { - int use_alt_ref; - int first_is_key_frame = 0; - if (rc.frames_to_key == 0) { - rc.frames_to_key = vp9_get_frames_to_next_key(oxcf, twopass, show_idx, - rc.min_gf_interval); - rc.frames_since_key = 0; - first_is_key_frame = 1; - } - - gop_coding_frame_count = vp9_get_gop_coding_frame_count( - oxcf, twopass, frame_info, &rc, show_idx, multi_layer_arf, - allow_alt_ref, first_is_key_frame, last_gop_use_alt_ref, &use_alt_ref); - - rc.source_alt_ref_active = use_alt_ref; - last_gop_use_alt_ref = use_alt_ref; - gop_show_frames = gop_coding_frame_count - use_alt_ref; - rc.frames_to_key -= gop_show_frames; - rc.frames_since_key += gop_show_frames; - show_idx += gop_show_frames; - coding_frame_num += gop_show_frames + use_alt_ref; - } - return coding_frame_num; -} - -void vp9_get_key_frame_map(const VP9EncoderConfig *oxcf, - const TWO_PASS *const twopass, int *key_frame_map) { - const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info; - int show_idx = 0; - RATE_CONTROL rc; - vp9_rc_init(oxcf, 1, &rc); - - // key_frame_map points to an int array with size equal to - // first_pass_info->num_frames, which is also the number of show frames in the - // video. - memset(key_frame_map, 0, - sizeof(*key_frame_map) * first_pass_info->num_frames); - while (show_idx < first_pass_info->num_frames) { - int key_frame_group_size; - key_frame_map[show_idx] = 1; - key_frame_group_size = - vp9_get_frames_to_next_key(oxcf, twopass, show_idx, rc.min_gf_interval); - assert(key_frame_group_size > 0); - show_idx += key_frame_group_size; - } - assert(show_idx == first_pass_info->num_frames); -} -#endif // CONFIG_RATE_CTRL - FIRSTPASS_STATS vp9_get_frame_stats(const TWO_PASS *twopass) { return twopass->this_frame_stats; } FIRSTPASS_STATS vp9_get_total_stats(const TWO_PASS *twopass) { return twopass->total_stats; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c b/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c @@ -130,20 +130,28 @@ VP9_ENC_BORDER_IN_PIXELS, 0)) return 1; vpx_free_frame_buffer(&buf->img); buf->img = new_img; } else if (new_dimensions) { + int aligned_width = ALIGN_POWER_OF_TWO(width, 3); buf->img.y_width = src->y_width; buf->img.y_height = src->y_height; buf->img.uv_width = src->uv_width; buf->img.uv_height = src->uv_height; 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; + // Here the new width (src->y_crop_width) is <= the previous width + // (since otherwise it would enter the "larger_dimensions" code), so + // it is safe here to update the stride. + // The stride setting is taken from vpx_alloc_frame_buffer(). + buf->img.y_stride = + ALIGN_POWER_OF_TWO((aligned_width + 2 * buf->img.border), 5); + buf->img.uv_stride = buf->img.y_stride >> subsampling_x; } vp9_copy_and_extend_frame(src, &buf->img); buf->ts_start = ts_start; buf->ts_end = ts_end; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_mcomp.c b/media/libvpx/libvpx/vp9/encoder/vp9_mcomp.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_mcomp.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_mcomp.c @@ -1866,12 +1866,12 @@ baseline_interval_divisor = range / interval; // Check size of proposed first range against magnitude of the centre // value used as a starting point. - range = VPXMAX(range, (5 * VPXMAX(abs(temp_mv.row), abs(temp_mv.col))) / 4); - range = VPXMIN(range, MAX_RANGE); + range = clamp(range, (5 * VPXMAX(abs(temp_mv.row), abs(temp_mv.col))) / 4, + MAX_RANGE); interval = VPXMAX(interval, range / baseline_interval_divisor); // initial search bestsme = exhaustive_mesh_search_new(x, &temp_mv, range, interval, fn_ptr, &temp_mv, @@ -2627,12 +2627,12 @@ baseline_interval_divisor = range / interval; // Check size of proposed first range against magnitude of the centre // value used as a starting point. - range = VPXMAX(range, (5 * VPXMAX(abs(temp_mv.row), abs(temp_mv.col))) / 4); - range = VPXMIN(range, MAX_RANGE); + range = clamp(range, (5 * VPXMAX(abs(temp_mv.row), abs(temp_mv.col))) / 4, + MAX_RANGE); interval = VPXMAX(interval, range / baseline_interval_divisor); // initial search bestsme = exhaustive_mesh_search(x, &f_ref_mv, &temp_mv, range, interval, sadpb, fn_ptr, &temp_mv); diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_pickmode.c b/media/libvpx/libvpx/vp9/encoder/vp9_pickmode.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_pickmode.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_pickmode.c @@ -1177,10 +1177,11 @@ const MODE_INFO *above_mi = xd->above_mi; const MODE_INFO *left_mi = xd->left_mi; const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0); const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0); bmode_costs = cpi->y_mode_costs[A][L]; + assert(bsize >= BLOCK_8X8); (void)ctx; vp9_rd_cost_reset(&best_rdc); vp9_rd_cost_reset(&this_rdc); diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_ratectrl.c b/media/libvpx/libvpx/vp9/encoder/vp9_ratectrl.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_ratectrl.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_ratectrl.c @@ -854,19 +854,23 @@ FRAME_TYPE frame_type = cm->intra_only ? KEY_FRAME : cm->frame_type; bits_per_mb_at_this_q = (int)vp9_rc_bits_per_mb( frame_type, i, correction_factor, cm->bit_depth); } + int diff_bits = (int)VPXMIN( + VPXMAX(((int64_t)target_bits_per_mb - (int64_t)bits_per_mb_at_this_q), + -INT_MAX), + INT_MAX); if (bits_per_mb_at_this_q <= target_bits_per_mb) { - if ((target_bits_per_mb - bits_per_mb_at_this_q) <= last_error) + if (diff_bits <= last_error) q = i; else q = i - 1; break; } else { - last_error = bits_per_mb_at_this_q - target_bits_per_mb; + last_error = -diff_bits; } } while (++i <= active_worst_quality); // Adjustment to q for CBR mode. if (cpi->oxcf.rc_mode == VPX_CBR) return adjust_q_cbr(cpi, q); @@ -1732,18 +1736,10 @@ rc->frame_size_selector != UNSCALED) { rc->this_frame_target = (int)(rc->this_frame_target * rate_thresh_mult[rc->frame_size_selector]); } -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - if (cpi->encode_command.use_external_target_frame_bits) { - rc->this_frame_target = cpi->encode_command.target_frame_bits; - } - } -#endif // CONFIG_RATE_CTRL - // Target rate per SB64 (including partial SB64s. const int64_t sb64_target_rate = ((int64_t)rc->this_frame_target * 64 * 64) / (cm->width * cm->height); rc->sb64_target_rate = (int)VPXMIN(sb64_target_rate, INT_MAX); } @@ -2610,17 +2606,10 @@ } else { double framerate = cpi->framerate; // Set Maximum gf/arf interval rc->max_gf_interval = oxcf->max_gf_interval; rc->min_gf_interval = oxcf->min_gf_interval; -#if CONFIG_RATE_CTRL - if (oxcf->use_simple_encode_api) { - // In this experiment, we avoid framerate being changed dynamically during - // encoding. - framerate = oxcf->init_framerate; - } -#endif // CONFIG_RATE_CTRL if (rc->min_gf_interval == 0) { rc->min_gf_interval = vp9_rc_get_default_min_gf_interval( oxcf->width, oxcf->height, framerate); } if (rc->max_gf_interval == 0) { @@ -3287,11 +3276,10 @@ int target_bits_per_mb; double q2; int enumerator; // Set a larger QP. if (cpi->oxcf.content != VP9E_CONTENT_SCREEN && - cm->width * cm->height >= 1280 * 720 && (rc->buffer_level > (3 * rc->optimal_buffer_level) >> 2) && (cpi->rc.avg_source_sad[0] < sad_thr)) { *q = (*q + cpi->rc.worst_quality) >> 1; force_maxqp = 0; } else { diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_rdopt.c b/media/libvpx/libvpx/vp9/encoder/vp9_rdopt.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_rdopt.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_rdopt.c @@ -1183,11 +1183,11 @@ memcpy(best_dst16 + idy * 8, CONVERT_TO_SHORTPTR(dst_init + idy * dst_stride), num_4x4_blocks_wide * 4 * sizeof(uint16_t)); } } - next_highbd : {} + next_highbd: {} } if (best_rd >= rd_thresh || x->skip_encode) return best_rd; for (idy = 0; idy < num_4x4_blocks_high * 4; ++idy) { memcpy(CONVERT_TO_SHORTPTR(dst_init + idy * dst_stride), @@ -1282,11 +1282,11 @@ memcpy(l, templ, num_4x4_blocks_high * sizeof(templ[0])); for (idy = 0; idy < num_4x4_blocks_high * 4; ++idy) memcpy(best_dst + idy * 8, dst_init + idy * dst_stride, num_4x4_blocks_wide * 4); } - next : {} + next: {} } if (best_rd >= rd_thresh || x->skip_encode) return best_rd; for (idy = 0; idy < num_4x4_blocks_high * 4; ++idy) @@ -2317,12 +2317,11 @@ ref_bsi->rdstat[block][mode_idx].mvs[ref].as_int; } if (!subpelmv && have_ref && ref_bsi->rdstat[block][mode_idx].brdcost < INT64_MAX) { - memcpy(&bsi->rdstat[block][mode_idx], - &ref_bsi->rdstat[block][mode_idx], sizeof(SEG_RDSTAT)); + bsi->rdstat[block][mode_idx] = ref_bsi->rdstat[block][mode_idx]; if (num_4x4_blocks_wide > 1) bsi->rdstat[block + 1][mode_idx].eobs = ref_bsi->rdstat[block + 1][mode_idx].eobs; if (num_4x4_blocks_high > 1) bsi->rdstat[block + 2][mode_idx].eobs = @@ -3620,11 +3619,11 @@ ref_frame_skip_mask[0] |= (1 << INTRA_FRAME); ref_frame_skip_mask[1] |= (1 << INTRA_FRAME); } mode_skip_mask[INTRA_FRAME] |= - (uint16_t) ~(sf->intra_y_mode_mask[max_txsize_lookup[bsize]]); + (uint16_t)~(sf->intra_y_mode_mask[max_txsize_lookup[bsize]]); for (i = 0; i <= LAST_NEW_MV_INDEX; ++i) mode_threshold[i] = 0; for (i = LAST_NEW_MV_INDEX + 1; i < MAX_MODES; ++i) mode_threshold[i] = ((int64_t)rd_threshes[i] * rd_thresh_freq_fact[i]) >> 5; @@ -4891,12 +4890,11 @@ *mi = best_mbmode; x->skip |= best_skip2; if (!is_inter_block(&best_mbmode)) { for (i = 0; i < 4; i++) xd->mi[0]->bmi[i].as_mode = best_bmodes[i].as_mode; } else { - for (i = 0; i < 4; ++i) - memcpy(&xd->mi[0]->bmi[i], &best_bmodes[i], sizeof(b_mode_info)); + for (i = 0; i < 4; ++i) xd->mi[0]->bmi[i] = best_bmodes[i]; mi->mv[0].as_int = xd->mi[0]->bmi[3].as_mv[0].as_int; mi->mv[1].as_int = xd->mi[0]->bmi[3].as_mv[1].as_int; } // If the second reference does not exist, set the corresponding mv to zero. diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.h b/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.h @@ -146,13 +146,10 @@ // Use an arbitrary partitioning scheme based on source variance within // a 64X64 SB. VAR_BASED_PARTITION, - // Use non-fixed partitions based on source variance. - SOURCE_VAR_BASED_PARTITION, - // Make partition decisions with machine learning models. ML_BASED_PARTITION } PARTITION_SEARCH_TYPE; typedef enum { @@ -515,14 +512,10 @@ // 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; - // The frequency that we check if SOURCE_VAR_BASED_PARTITION or - // FIXED_PARTITION search type should be used. - int search_type_check_frequency; - // When partition is pre-set, the inter prediction result from pick_inter_mode // can be reused in final block encoding process. It is enabled only for real- // time mode speed 6. int reuse_inter_pred_sby; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.c b/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_speed_features.c @@ -999,11 +999,10 @@ sf->max_intra_bsize = BLOCK_64X64; sf->reuse_inter_pred_sby = 0; // This setting only takes effect when partition_search_type is set // to FIXED_PARTITION. sf->always_this_block_size = BLOCK_16X16; - sf->search_type_check_frequency = 50; sf->encode_breakout_thresh = 0; // Recode loop tolerance %. sf->recode_tolerance_low = 12; sf->recode_tolerance_high = 25; sf->default_interp_filter = SWITCHABLE; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_temporal_filter.c b/media/libvpx/libvpx/vp9/encoder/vp9_temporal_filter.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_temporal_filter.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_temporal_filter.c @@ -1265,11 +1265,11 @@ // Context dependent two pass adjustment to strength. if (oxcf->pass == 2) { base_strength = oxcf->arnr_strength + cpi->twopass.arnr_strength_adjustment; // Clip to allowed range. - base_strength = VPXMIN(6, VPXMAX(0, base_strength)); + base_strength = clamp(base_strength, 0, 6); } else { base_strength = oxcf->arnr_strength; } // Adjust the strength based on active max q. diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_tpl_model.c b/media/libvpx/libvpx/vp9/encoder/vp9_tpl_model.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_tpl_model.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_tpl_model.c @@ -1675,52 +1675,10 @@ cpi->tpl_stats[frame].is_valid = 0; } free_tpl_frame_stats_list(&cpi->tpl_gop_stats); } -#if CONFIG_RATE_CTRL -static void accumulate_frame_tpl_stats(VP9_COMP *cpi) { - VP9_COMMON *const cm = &cpi->common; - const GF_GROUP *gf_group = &cpi->twopass.gf_group; - int show_frame_count = 0; - int frame_idx; - // Accumulate tpl stats for each frame in the current group of picture. - for (frame_idx = 1; frame_idx < gf_group->gf_group_size; ++frame_idx) { - TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx]; - TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr; - const int tpl_stride = tpl_frame->stride; - int64_t intra_cost_base = 0; - int64_t inter_cost_base = 0; - int64_t mc_dep_cost_base = 0; - int64_t mc_ref_cost_base = 0; - int64_t mc_flow_base = 0; - int row, col; - - if (!tpl_frame->is_valid) continue; - - for (row = 0; row < cm->mi_rows && tpl_frame->is_valid; ++row) { - for (col = 0; col < cm->mi_cols; ++col) { - TplDepStats *this_stats = &tpl_stats[row * tpl_stride + col]; - intra_cost_base += this_stats->intra_cost; - inter_cost_base += this_stats->inter_cost; - mc_dep_cost_base += this_stats->mc_dep_cost; - mc_ref_cost_base += this_stats->mc_ref_cost; - mc_flow_base += this_stats->mc_flow; - } - } - - cpi->tpl_stats_info[show_frame_count].intra_cost = intra_cost_base; - cpi->tpl_stats_info[show_frame_count].inter_cost = inter_cost_base; - cpi->tpl_stats_info[show_frame_count].mc_dep_cost = mc_dep_cost_base; - cpi->tpl_stats_info[show_frame_count].mc_ref_cost = mc_ref_cost_base; - cpi->tpl_stats_info[show_frame_count].mc_flow = mc_flow_base; - - ++show_frame_count; - } -} -#endif // CONFIG_RATE_CTRL - void vp9_estimate_tpl_qp_gop(VP9_COMP *cpi) { VP9_COMMON *cm = &cpi->common; int gop_length = cpi->twopass.gf_group.gf_group_size; int bottom_index, top_index; int idx; @@ -1828,12 +1786,6 @@ cpi->tpl_ready = 1; #if DUMP_TPL_STATS dump_tpl_stats(cpi, tpl_group_frames, gf_group, gf_picture, cpi->tpl_bsize); #endif // DUMP_TPL_STATS #endif // CONFIG_NON_GREEDY_MV - -#if CONFIG_RATE_CTRL - if (cpi->oxcf.use_simple_encode_api) { - accumulate_frame_tpl_stats(cpi); - } -#endif // CONFIG_RATE_CTRL } diff --git a/media/libvpx/libvpx/vp9/simple_encode.h b/media/libvpx/libvpx/vp9/simple_encode.h deleted file mode 100644 --- a/media/libvpx/libvpx/vp9/simple_encode.h +++ /dev/null @@ -1,584 +0,0 @@ -/* - * Copyright (c) 2019 The WebM project authors. 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. - */ - -#ifndef VPX_VP9_SIMPLE_ENCODE_H_ -#define VPX_VP9_SIMPLE_ENCODE_H_ - -#include -#include -#include -#include -#include - -namespace vp9 { - -enum StatusCode { - StatusOk = 0, - StatusError, -}; - -// TODO(angiebird): Add description for each frame type. -enum FrameType { - kFrameTypeKey = 0, - kFrameTypeInter = 1, - kFrameTypeAltRef = 2, - kFrameTypeOverlay = 3, - kFrameTypeGolden = 4, -}; - -// TODO(angiebird): Add description for each reference frame type. -// This enum numbers have to be contiguous and start from zero except -// kNoneRefFrame. -enum RefFrameType { - kRefFrameTypeLast = 0, - kRefFrameTypePast = 1, - kRefFrameTypeFuture = 2, - kRefFrameTypeMax = 3, - kRefFrameTypeNone = -1, -}; - -enum VP9_LEVEL { - LEVEL_UNKNOWN = 0, - LEVEL_AUTO = 1, - LEVEL_1 = 10, - LEVEL_1_1 = 11, - LEVEL_2 = 20, - LEVEL_2_1 = 21, - LEVEL_3 = 30, - LEVEL_3_1 = 31, - LEVEL_4 = 40, - LEVEL_4_1 = 41, - LEVEL_5 = 50, - LEVEL_5_1 = 51, - LEVEL_5_2 = 52, - LEVEL_6 = 60, - LEVEL_6_1 = 61, - LEVEL_6_2 = 62, - LEVEL_MAX = 255 -}; - -enum GopMapFlag { - kGopMapFlagStart = - 1 << 0, // Indicate this location is the start of a group of pictures. - kGopMapFlagUseAltRef = - 1 << 1, // Indicate this group of pictures will use an alt ref. Only set - // this flag when kGopMapFlagStart is set. -}; - -// The frame is split to 4x4 blocks. -// This structure contains the information of each 4x4 block. -struct PartitionInfo { - int row; // row pixel offset of current 4x4 block - int column; // column pixel offset of current 4x4 block - int row_start; // row pixel offset of the start of the prediction block - int column_start; // column pixel offset of the start of the prediction block - int width; // prediction block width - int height; // prediction block height -}; - -constexpr int kMotionVectorSubPixelPrecision = 8; -constexpr int kMotionVectorFullPixelPrecision = 1; - -// In the first pass. The frame is split to 16x16 blocks. -// This structure contains the information of each 16x16 block. -// In the second pass. The frame is split to 4x4 blocks. -// This structure contains the information of each 4x4 block. -struct MotionVectorInfo { - // Number of valid motion vectors, always 0 if this block is in the key frame. - // For inter frames, it could be 1 or 2. - int mv_count; - // The reference frame for motion vectors. If the second motion vector does - // not exist (mv_count = 1), the reference frame is kNoneRefFrame. - // Otherwise, the reference frame is either kRefFrameTypeLast, or - // kRefFrameTypePast, or kRefFrameTypeFuture. - RefFrameType ref_frame[2]; - // The row offset of motion vectors in the unit of pixel. - // If the second motion vector does not exist, the value is 0. - double mv_row[2]; - // The column offset of motion vectors in the unit of pixel. - // If the second motion vector does not exist, the value is 0. - double mv_column[2]; -}; - -// Accumulated tpl stats of all blocks in one frame. -// For each frame, the tpl stats are computed per 32x32 block. -struct TplStatsInfo { - // Intra complexity: the sum of absolute transform difference (SATD) of - // intra predicted residuals. - int64_t intra_cost; - // Inter complexity: the SATD of inter predicted residuals. - int64_t inter_cost; - // Motion compensated information flow. It measures how much information - // is propagated from the current frame to other frames. - int64_t mc_flow; - // Motion compensated dependency cost. It equals to its own intra_cost - // plus the mc_flow. - int64_t mc_dep_cost; - // Motion compensated reference cost. - int64_t mc_ref_cost; -}; - -struct RefFrameInfo { - int coding_indexes[kRefFrameTypeMax]; - - // Indicate whether the reference frames are available or not. - // When the reference frame type is not valid, it means either the to-be-coded - // frame is a key frame or the reference frame already appears in other - // reference frame type. vp9 always keeps three types of reference frame - // available. However, the duplicated reference frames will not be - // chosen by the encoder. The priorities of choosing reference frames are - // kRefFrameTypeLast > kRefFrameTypePast > kRefFrameTypeFuture. - // For example, if kRefFrameTypeLast and kRefFrameTypePast both point to the - // same frame, kRefFrameTypePast will be set to invalid. - // 1: the ref frame type is available 0: the ref frame type is not available - int valid_list[kRefFrameTypeMax]; -}; - -bool operator==(const RefFrameInfo &a, const RefFrameInfo &b); - -struct EncodeFrameInfo { - int show_idx; - - // Each show or no show frame is assigned with a coding index based on its - // coding order (starting from zero) in the coding process of the entire - // video. The coding index for each frame is unique. - int coding_index; - RefFrameInfo ref_frame_info; - FrameType frame_type; -}; - -// This structure is a copy of vp9 |nmv_component_counts|. -struct NewMotionvectorComponentCounts { - std::vector sign; - std::vector classes; - std::vector class0; - std::vector> bits; - std::vector> class0_fp; - std::vector fp; - std::vector class0_hp; - std::vector hp; -}; - -// This structure is a copy of vp9 |nmv_context_counts|. -struct NewMotionVectorContextCounts { - std::vector joints; - std::vector comps; -}; - -using UintArray2D = std::vector>; -using UintArray3D = std::vector>>; -using UintArray5D = std::vector< - std::vector>>>>; -using UintArray6D = std::vector>>>>>; - -// This structure is a copy of vp9 |tx_counts|. -struct TransformSizeCounts { - // Transform size found in blocks of partition size 32x32. - // First dimension: transform size contexts (2). - // Second dimension: transform size type (3: 32x32, 16x16, 8x8) - UintArray2D p32x32; - // Transform size found in blocks of partition size 16x16. - // First dimension: transform size contexts (2). - // Second dimension: transform size type (2: 16x16, 8x8) - UintArray2D p16x16; - // Transform size found in blocks of partition size 8x8. - // First dimension: transform size contexts (2). - // Second dimension: transform size type (1: 8x8) - UintArray2D p8x8; - // Overall transform size count. - std::vector tx_totals; -}; - -// This structure is a copy of vp9 |FRAME_COUNTS|. -struct FrameCounts { - // Intra prediction mode for luma plane. First dimension: block size (4). - // Second dimension: intra prediction mode (10). - UintArray2D y_mode; - // Intra prediction mode for chroma plane. First and second dimension: - // intra prediction mode (10). - UintArray2D uv_mode; - // Partition type. First dimension: partition contexts (16). - // Second dimension: partition type (4). - UintArray2D partition; - // Transform coefficient. - UintArray6D coef; - // End of block (the position of the last non-zero transform coefficient) - UintArray5D eob_branch; - // Interpolation filter type. First dimension: switchable filter contexts (4). - // Second dimension: filter types (3). - UintArray2D switchable_interp; - // Inter prediction mode (the motion vector type). - // First dimension: inter mode contexts (7). - // Second dimension: mode type (4). - UintArray2D inter_mode; - // Block is intra or inter predicted. First dimension: contexts (4). - // Second dimension: type (0 for intra, 1 for inter). - UintArray2D intra_inter; - // Block is compound predicted (predicted from average of two blocks). - // First dimension: contexts (5). - // Second dimension: type (0 for single, 1 for compound prediction). - UintArray2D comp_inter; - // Type of the reference frame. Only one reference frame. - // First dimension: context (5). Second dimension: context (2). - // Third dimension: count (2). - UintArray3D single_ref; - // Type of the two reference frames. - // First dimension: context (5). Second dimension: count (2). - UintArray2D comp_ref; - // Block skips transform and quantization, uses prediction as reconstruction. - // First dimension: contexts (3). Second dimension: type (0 not skip, 1 skip). - UintArray2D skip; - // Transform size. - TransformSizeCounts tx; - // New motion vector. - NewMotionVectorContextCounts mv; -}; - -struct ImageBuffer { - // The image data is stored in raster order, - // i.e. image[plane][r][c] = - // plane_buffer[plane][r * plane_width[plane] + plane_height[plane]]. - std::unique_ptr plane_buffer[3]; - int plane_width[3]; - int plane_height[3]; -}; - -void output_image_buffer(const ImageBuffer &image_buffer, std::FILE *out_file); - -struct EncodeFrameResult { - int show_idx; - FrameType frame_type; - int coding_idx; - RefFrameInfo ref_frame_info; - size_t coding_data_bit_size; - size_t coding_data_byte_size; - // The EncodeFrame will allocate a buffer, write the coding data into the - // buffer and give the ownership of the buffer to coding_data. - std::unique_ptr coding_data; - size_t max_coding_data_byte_size; - double psnr; - uint64_t sse; - int quantize_index; - FrameCounts frame_counts; - int num_rows_4x4; // number of row units, in size of 4. - int num_cols_4x4; // number of column units, in size of 4. - // A vector of the partition information of the frame. - // The number of elements is |num_rows_4x4| * |num_cols_4x4|. - // The frame is divided 4x4 blocks of |num_rows_4x4| rows and - // |num_cols_4x4| columns. - // Each 4x4 block contains the current pixel position (|row|, |column|), - // the start pixel position of the partition (|row_start|, |column_start|), - // and the |width|, |height| of the partition. - // The current pixel position can be the same as the start pixel position - // if the 4x4 block is the top-left block in the partition. Otherwise, they - // are different. - // Within the same partition, all 4x4 blocks have the same |row_start|, - // |column_start|, |width| and |height|. - // For example, if the frame is partitioned to a 32x32 block, - // starting at (0, 0). Then, there're 64 4x4 blocks within this partition. - // They all have the same |row_start|, |column_start|, |width|, |height|, - // which can be used to figure out the start of the current partition and - // the start of the next partition block. - // Horizontal next: |column_start| + |width|, - // Vertical next: |row_start| + |height|. - std::vector partition_info; - // A vector of the motion vector information of the frame. - // The number of elements is |num_rows_4x4| * |num_cols_4x4|. - // The frame is divided into 4x4 blocks of |num_rows_4x4| rows and - // |num_cols_4x4| columns. - // Each 4x4 block contains 0 motion vector if this is an intra predicted - // frame (for example, the key frame). If the frame is inter predicted, - // each 4x4 block contains either 1 or 2 motion vectors. - // Similar to partition info, all 4x4 blocks inside the same partition block - // share the same motion vector information. - std::vector motion_vector_info; - // A vector of the tpl stats information. - // The tpl stats measure the complexity of a frame, as well as the - // information propagated along the motion trajectory between frames, in - // the reference frame structure. - // The tpl stats could be used as a more accurate spatial and temporal - // complexity measure in addition to the first pass stats. - // The vector contains tpl stats for all show frames in a GOP. - // The tpl stats stored in the vector is according to the encoding order. - // For example, suppose there are N show frames for the current GOP. - // Then tpl_stats_info[0] stores the information of the first frame to be - // encoded for this GOP, i.e., the AltRef frame. - std::vector tpl_stats_info; - ImageBuffer coded_frame; - - // recode_count, q_index_history and rate_history are only available when - // EncodeFrameWithTargetFrameBits() is used. - int recode_count; - std::vector q_index_history; - std::vector rate_history; -}; - -struct GroupOfPicture { - // This list will be updated internally in StartEncode() and - // EncodeFrame()/EncodeFrameWithQuantizeIndex(). - // In EncodeFrame()/EncodeFrameWithQuantizeIndex(), the update will only be - // triggered when the coded frame is the last one in the previous group of - // pictures. - std::vector encode_frame_list; - - // Indicates the index of the next coding frame in encode_frame_list. - // In other words, EncodeFrameInfo of the next coding frame can be - // obtained with encode_frame_list[next_encode_frame_index]. - // Internally, next_encode_frame_index will be set to zero after the last - // frame of the group of pictures is coded. Otherwise, next_encode_frame_index - // will be increased after each EncodeFrame()/EncodeFrameWithQuantizeIndex() - // call. - int next_encode_frame_index; - - // Number of show frames in this group of pictures. - int show_frame_count; - - // The show index/timestamp of the earliest show frame in the group of - // pictures. - int start_show_index; - - // The coding index of the first coding frame in the group of pictures. - int start_coding_index; - - // Indicates whether this group of pictures starts with a key frame. - int first_is_key_frame; - - // Indicates whether this group of pictures uses an alt ref. - int use_alt_ref; - - // Indicates whether previous group of pictures used an alt ref. - int last_gop_use_alt_ref; -}; - -class SimpleEncode { - public: - // When outfile_path is set, the encoder will output the bitstream in ivf - // format. - SimpleEncode(int frame_width, int frame_height, int frame_rate_num, - int frame_rate_den, int target_bitrate, int num_frames, - int target_level, const char *infile_path, - const char *outfile_path = nullptr); - ~SimpleEncode(); - SimpleEncode(SimpleEncode &) = delete; - SimpleEncode &operator=(const SimpleEncode &) = delete; - - // Adjusts the encoder's coding speed. - // If this function is not called, the encoder will use default encode_speed - // 0. Call this function before ComputeFirstPassStats() if needed. - // The encode_speed is equivalent to --cpu-used of the vpxenc command. - // The encode_speed's range should be [0, 9]. - // Setting the encode_speed to a higher level will yield faster coding - // at the cost of lower compression efficiency. - void SetEncodeSpeed(int encode_speed); - - // Set encoder config - // The following configs in VP9EncoderConfig are allowed to change in this - // function. See https://ffmpeg.org/ffmpeg-codecs.html#libvpx for each - // config's meaning. - // Configs in VP9EncoderConfig: Equivalent configs in ffmpeg: - // 1 key_freq -g - // 2 two_pass_vbrmin_section -minrate * 100LL / bit_rate - // 3 two_pass_vbrmax_section -maxrate * 100LL / bit_rate - // 4 under_shoot_pct -undershoot-pct - // 5 over_shoot_pct -overshoot-pct - // 6 max_threads -threads - // 7 frame_parallel_decoding_mode -frame-parallel - // 8 tile_column -tile-columns - // 9 arnr_max_frames -arnr-maxframes - // 10 arnr_strength -arnr-strength - // 11 lag_in_frames -rc_lookahead - // 12 encode_breakout -static-thresh - // 13 enable_tpl_model -enable-tpl - // 14 enable_auto_arf -auto-alt-ref - // 15 rc_mode - // Possible Settings: - // 0 - Variable Bit Rate (VPX_VBR) -b:v - // 1 - Constant Bit Rate (VPX_CBR) -b:v -minrate - // -maxrate - // two_pass_vbrmin_section == 100 i.e. bit_rate == minrate == maxrate - // two_pass_vbrmax_section == 100 - // 2 - Constrained Quality (VPX_CQ) -crf -b:v bit_rate - // 3 - Constant Quality (VPX_Q) -crf -b:v 0 - // See https://trac.ffmpeg.org/wiki/Encode/VP9 for more details. - // 16 cq_level see rc_mode for details. - StatusCode SetEncodeConfig(const char *name, const char *value); - - // A debug function that dumps configs from VP9EncoderConfig - // pass = 1: first pass, pass = 2: second pass - // fp: file pointer for dumping config - StatusCode DumpEncodeConfigs(int pass, FILE *fp); - - // Makes encoder compute the first pass stats and store it at - // impl_ptr_->first_pass_stats. key_frame_map_ is also computed based on the - // first pass stats. - void ComputeFirstPassStats(); - - // Outputs the first pass stats represented by a 2-D vector. - // One can use the frame index at first dimension to retrieve the stats for - // each video frame. The stats of each video frame is a vector of 25 double - // values. For details, please check FIRSTPASS_STATS in vp9_firstpass.h - std::vector> ObserveFirstPassStats(); - - // Outputs the first pass motion vectors represented by a 2-D vector. - // One can use the frame index at first dimension to retrieve the mvs for - // each video frame. The frame is divided into 16x16 blocks. The number of - // elements is round_up(|num_rows_4x4| / 4) * round_up(|num_cols_4x4| / 4). - std::vector> ObserveFirstPassMotionVectors(); - - // Ouputs a copy of key_frame_map_, a binary vector with size equal to the - // number of show frames in the video. For each entry in the vector, 1 - // indicates the position is a key frame and 0 indicates it's not a key frame. - // This function should be called after ComputeFirstPassStats() - std::vector ObserveKeyFrameMap() const; - - // Sets group of pictures map for coding the entire video. - // Each entry in the gop_map corresponds to a show frame in the video. - // Therefore, the size of gop_map should equal to the number of show frames in - // the entire video. - // If a given entry's kGopMapFlagStart is set, it means this is the start of a - // gop. Once kGopMapFlagStart is set, one can set kGopMapFlagUseAltRef to - // indicate whether this gop use altref. - // If a given entry is zero, it means it's in the middle of a gop. - // This function should be called only once after ComputeFirstPassStats(), - // before StartEncode(). - // This API will check and modify the gop_map to satisfy the following - // constraints. - // 1) Each key frame position should be at the start of a gop. - // 2) The last gop should not use an alt ref. - void SetExternalGroupOfPicturesMap(int *gop_map, int gop_map_size); - - // Observe the group of pictures map set through - // SetExternalGroupOfPicturesMap(). This function should be called after - // SetExternalGroupOfPicturesMap(). - std::vector ObserveExternalGroupOfPicturesMap(); - - // Initializes the encoder for actual encoding. - // This function should be called after ComputeFirstPassStats(). - void StartEncode(); - - // Frees the encoder. - // This function should be called after StartEncode() or EncodeFrame(). - void EndEncode(); - - // The key frame group size includes one key frame plus the number of - // following inter frames. Note that the key frame group size only counts the - // show frames. The number of no show frames like alternate refereces are not - // counted. - int GetKeyFrameGroupSize() const; - - // Provides the group of pictures that the next coding frame is in. - // Only call this function between StartEncode() and EndEncode() - GroupOfPicture ObserveGroupOfPicture() const; - - // Gets encode_frame_info for the next coding frame. - // Only call this function between StartEncode() and EndEncode() - EncodeFrameInfo GetNextEncodeFrameInfo() const; - - // Encodes a frame - // This function should be called after StartEncode() and before EndEncode(). - void EncodeFrame(EncodeFrameResult *encode_frame_result); - - // Encodes a frame with a specific quantize index. - // This function should be called after StartEncode() and before EndEncode(). - void EncodeFrameWithQuantizeIndex(EncodeFrameResult *encode_frame_result, - int quantize_index); - - // Encode a frame with target frame bits usage. - // The encoder will find a quantize index to make the actual frame bits usage - // match the target. EncodeFrameWithTargetFrameBits() will recode the frame - // up to 7 times to find a q_index to make the actual_frame_bits satisfy the - // following inequality. |actual_frame_bits - target_frame_bits| * 100 / - // target_frame_bits - // <= percent_diff. - void EncodeFrameWithTargetFrameBits(EncodeFrameResult *encode_frame_result, - int target_frame_bits, - double percent_diff); - - // Gets the number of coding frames for the video. The coding frames include - // show frame and no show frame. - // This function should be called after ComputeFirstPassStats(). - int GetCodingFrameNum() const; - - // Gets the total number of pixels of YUV planes per frame. - uint64_t GetFramePixelCount() const; - - private: - // Compute the key frame locations of the video based on first pass stats. - // The results are returned as a binary vector with 1s indicating keyframes - // and 0s indicating non keyframes. - // It has to be called after impl_ptr_->first_pass_stats is computed. - std::vector ComputeKeyFrameMap() const; - - // Updates key_frame_group_size_, reset key_frame_group_index_ and init - // ref_frame_info_. - void UpdateKeyFrameGroup(int key_frame_show_index); - - // Update key_frame_group_index_. - void PostUpdateKeyFrameGroupIndex(FrameType frame_type); - - void PostUpdateState(const EncodeFrameResult &encode_frame_result); - - class EncodeImpl; - - int frame_width_; // frame width in pixels. - int frame_height_; // frame height in pixels. - int frame_rate_num_; - int frame_rate_den_; - int target_bitrate_; - int num_frames_; - int encode_speed_; - int target_level_; - - std::FILE *in_file_; - std::FILE *out_file_; - std::unique_ptr impl_ptr_; - - std::vector key_frame_map_; - std::vector gop_map_; - GroupOfPicture group_of_picture_; - - // The key frame group size includes one key frame plus the number of - // following inter frames. Note that the key frame group size only counts the - // show frames. The number of no show frames like alternate references are not - // counted. - int key_frame_group_size_; - - // The index for the to-be-coded show frame in the key frame group. - int key_frame_group_index_; - - // Each show or no show frame is assigned with a coding index based on its - // coding order (starting from zero) in the coding process of the entire - // video. The coding index of the to-be-coded frame. - int frame_coding_index_; - - // Number of show frames we have coded so far. - int show_frame_count_; - - // TODO(angiebird): Do we need to reset ref_frames_info_ when the next key - // frame appears? - // Reference frames info of the to-be-coded frame. - RefFrameInfo ref_frame_info_; - - // A 2-D vector of motion vector information of the frame collected - // from the first pass. The first dimension is the frame index. - // Each frame is divided into 16x16 blocks. The number of elements is - // round_up(|num_rows_4x4| / 4) * round_up(|num_cols_4x4| / 4). - // Each 16x16 block contains 0 motion vector if this is an intra predicted - // frame (for example, the key frame). If the frame is inter predicted, - // each 16x16 block contains either 1 or 2 motion vectors. - // The first motion vector is always from the LAST_FRAME. - // The second motion vector is always from the GOLDEN_FRAME. - std::vector> fp_motion_vector_info_; -}; - -} // namespace vp9 - -#endif // VPX_VP9_SIMPLE_ENCODE_H_ diff --git a/media/libvpx/libvpx/vp9/simple_encode.cc b/media/libvpx/libvpx/vp9/simple_encode.cc deleted file mode 100644 --- a/media/libvpx/libvpx/vp9/simple_encode.cc +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * Copyright (c) 2019 The WebM project authors. 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 - -#include -#include - -#include "./ivfenc.h" -#include "vp9/common/vp9_entropymode.h" -#include "vp9/common/vp9_enums.h" -#include "vp9/common/vp9_onyxc_int.h" -#include "vp9/vp9_iface_common.h" -#include "vp9/encoder/vp9_encoder.h" -#include "vp9/encoder/vp9_firstpass.h" -#include "vp9/simple_encode.h" -#include "vp9/vp9_cx_iface.h" - -namespace vp9 { - -static int get_plane_height(vpx_img_fmt_t img_fmt, int frame_height, - int plane) { - assert(plane < 3); - if (plane == 0) { - return frame_height; - } - switch (img_fmt) { - case VPX_IMG_FMT_I420: - case VPX_IMG_FMT_I440: - case VPX_IMG_FMT_YV12: - case VPX_IMG_FMT_I42016: - case VPX_IMG_FMT_I44016: return (frame_height + 1) >> 1; - default: return frame_height; - } -} - -static int get_plane_width(vpx_img_fmt_t img_fmt, int frame_width, int plane) { - assert(plane < 3); - if (plane == 0) { - return frame_width; - } - switch (img_fmt) { - case VPX_IMG_FMT_I420: - case VPX_IMG_FMT_YV12: - case VPX_IMG_FMT_I422: - case VPX_IMG_FMT_I42016: - case VPX_IMG_FMT_I42216: return (frame_width + 1) >> 1; - default: return frame_width; - } -} - -// TODO(angiebird): Merge this function with vpx_img_plane_width() -static int img_plane_width(const vpx_image_t *img, int plane) { - if (plane > 0 && img->x_chroma_shift > 0) - return (img->d_w + 1) >> img->x_chroma_shift; - else - return img->d_w; -} - -// TODO(angiebird): Merge this function with vpx_img_plane_height() -static int img_plane_height(const vpx_image_t *img, int plane) { - if (plane > 0 && img->y_chroma_shift > 0) - return (img->d_h + 1) >> img->y_chroma_shift; - else - return img->d_h; -} - -// TODO(angiebird): Merge this function with vpx_img_read() -static int img_read(vpx_image_t *img, FILE *file) { - int plane; - - for (plane = 0; plane < 3; ++plane) { - unsigned char *buf = img->planes[plane]; - const int stride = img->stride[plane]; - const int w = img_plane_width(img, plane) * - ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); - const int h = img_plane_height(img, plane); - int y; - - for (y = 0; y < h; ++y) { - if (fread(buf, 1, w, file) != (size_t)w) return 0; - buf += stride; - } - } - - return 1; -} - -// Assume every config in VP9EncoderConfig is less than 100 characters. -#define ENCODE_CONFIG_BUF_SIZE 100 -struct EncodeConfig { - char name[ENCODE_CONFIG_BUF_SIZE]; - char value[ENCODE_CONFIG_BUF_SIZE]; -}; - -class SimpleEncode::EncodeImpl { - public: - VP9_COMP *cpi; - vpx_img_fmt_t img_fmt; - vpx_image_t tmp_img; - std::vector first_pass_stats; - std::vector encode_config_list; -}; - -static VP9_COMP *init_encoder(const VP9EncoderConfig *oxcf, - vpx_img_fmt_t img_fmt) { - VP9_COMP *cpi; - BufferPool *buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(*buffer_pool)); - if (!buffer_pool) return NULL; - vp9_initialize_enc(); - cpi = vp9_create_compressor(oxcf, buffer_pool); - vp9_update_compressor_with_img_fmt(cpi, img_fmt); - return cpi; -} - -static void free_encoder(VP9_COMP *cpi) { - BufferPool *buffer_pool = cpi->common.buffer_pool; - vp9_remove_compressor(cpi); - // buffer_pool needs to be free after cpi because buffer_pool contains - // allocated buffers that will be free in vp9_remove_compressor() - vpx_free(buffer_pool); -} - -static INLINE vpx_rational_t make_vpx_rational(int num, int den) { - vpx_rational_t v; - v.num = num; - v.den = den; - return v; -} - -static INLINE FrameType -get_frame_type_from_update_type(FRAME_UPDATE_TYPE update_type) { - switch (update_type) { - case KF_UPDATE: return kFrameTypeKey; - case ARF_UPDATE: return kFrameTypeAltRef; - case GF_UPDATE: return kFrameTypeGolden; - case OVERLAY_UPDATE: return kFrameTypeOverlay; - case LF_UPDATE: return kFrameTypeInter; - default: - fprintf(stderr, "Unsupported update_type %d\n", update_type); - abort(); - } -} - -static void update_partition_info(const PARTITION_INFO *input_partition_info, - const int num_rows_4x4, - const int num_cols_4x4, - PartitionInfo *output_partition_info) { - const int num_units_4x4 = num_rows_4x4 * num_cols_4x4; - for (int i = 0; i < num_units_4x4; ++i) { - output_partition_info[i].row = input_partition_info[i].row; - output_partition_info[i].column = input_partition_info[i].column; - output_partition_info[i].row_start = input_partition_info[i].row_start; - output_partition_info[i].column_start = - input_partition_info[i].column_start; - output_partition_info[i].width = input_partition_info[i].width; - output_partition_info[i].height = input_partition_info[i].height; - } -} - -// translate MV_REFERENCE_FRAME to RefFrameType -static RefFrameType mv_ref_frame_to_ref_frame_type( - MV_REFERENCE_FRAME mv_ref_frame) { - switch (mv_ref_frame) { - case LAST_FRAME: return kRefFrameTypeLast; - case GOLDEN_FRAME: return kRefFrameTypePast; - case ALTREF_FRAME: return kRefFrameTypeFuture; - default: return kRefFrameTypeNone; - } -} - -static void update_motion_vector_info( - const MOTION_VECTOR_INFO *input_motion_vector_info, const int num_rows_4x4, - const int num_cols_4x4, MotionVectorInfo *output_motion_vector_info, - int motion_vector_scale) { - const int num_units_4x4 = num_rows_4x4 * num_cols_4x4; - for (int i = 0; i < num_units_4x4; ++i) { - const MV_REFERENCE_FRAME *in_ref_frame = - input_motion_vector_info[i].ref_frame; - output_motion_vector_info[i].mv_count = - (in_ref_frame[0] == INTRA_FRAME) - ? 0 - : ((in_ref_frame[1] == NO_REF_FRAME) ? 1 : 2); - if (in_ref_frame[0] == NO_REF_FRAME) { - fprintf(stderr, "in_ref_frame[0] shouldn't be NO_REF_FRAME\n"); - abort(); - } - output_motion_vector_info[i].ref_frame[0] = - mv_ref_frame_to_ref_frame_type(in_ref_frame[0]); - output_motion_vector_info[i].ref_frame[1] = - mv_ref_frame_to_ref_frame_type(in_ref_frame[1]); - output_motion_vector_info[i].mv_row[0] = - (double)input_motion_vector_info[i].mv[0].as_mv.row / - motion_vector_scale; - output_motion_vector_info[i].mv_column[0] = - (double)input_motion_vector_info[i].mv[0].as_mv.col / - motion_vector_scale; - output_motion_vector_info[i].mv_row[1] = - (double)input_motion_vector_info[i].mv[1].as_mv.row / - motion_vector_scale; - output_motion_vector_info[i].mv_column[1] = - (double)input_motion_vector_info[i].mv[1].as_mv.col / - motion_vector_scale; - } -} - -static void update_tpl_stats_info(const TplDepStats *input_tpl_stats_info, - const int show_frame_count, - TplStatsInfo *output_tpl_stats_info) { - int frame_idx; - for (frame_idx = 0; frame_idx < show_frame_count; ++frame_idx) { - output_tpl_stats_info[frame_idx].intra_cost = - input_tpl_stats_info[frame_idx].intra_cost; - output_tpl_stats_info[frame_idx].inter_cost = - input_tpl_stats_info[frame_idx].inter_cost; - output_tpl_stats_info[frame_idx].mc_flow = - input_tpl_stats_info[frame_idx].mc_flow; - output_tpl_stats_info[frame_idx].mc_dep_cost = - input_tpl_stats_info[frame_idx].mc_dep_cost; - output_tpl_stats_info[frame_idx].mc_ref_cost = - input_tpl_stats_info[frame_idx].mc_ref_cost; - } -} - -static void update_frame_counts(const FRAME_COUNTS *input_counts, - FrameCounts *output_counts) { - // Init array sizes. - output_counts->y_mode.resize(BLOCK_SIZE_GROUPS); - for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) { - output_counts->y_mode[i].resize(INTRA_MODES); - } - - output_counts->uv_mode.resize(INTRA_MODES); - for (int i = 0; i < INTRA_MODES; ++i) { - output_counts->uv_mode[i].resize(INTRA_MODES); - } - - output_counts->partition.resize(PARTITION_CONTEXTS); - for (int i = 0; i < PARTITION_CONTEXTS; ++i) { - output_counts->partition[i].resize(PARTITION_TYPES); - } - - output_counts->coef.resize(TX_SIZES); - output_counts->eob_branch.resize(TX_SIZES); - for (int i = 0; i < TX_SIZES; ++i) { - output_counts->coef[i].resize(PLANE_TYPES); - output_counts->eob_branch[i].resize(PLANE_TYPES); - for (int j = 0; j < PLANE_TYPES; ++j) { - output_counts->coef[i][j].resize(REF_TYPES); - output_counts->eob_branch[i][j].resize(REF_TYPES); - for (int k = 0; k < REF_TYPES; ++k) { - output_counts->coef[i][j][k].resize(COEF_BANDS); - output_counts->eob_branch[i][j][k].resize(COEF_BANDS); - for (int l = 0; l < COEF_BANDS; ++l) { - output_counts->coef[i][j][k][l].resize(COEFF_CONTEXTS); - output_counts->eob_branch[i][j][k][l].resize(COEFF_CONTEXTS); - for (int m = 0; m < COEFF_CONTEXTS; ++m) { - output_counts->coef[i][j][k][l][m].resize(UNCONSTRAINED_NODES + 1); - } - } - } - } - } - - output_counts->switchable_interp.resize(SWITCHABLE_FILTER_CONTEXTS); - for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) { - output_counts->switchable_interp[i].resize(SWITCHABLE_FILTERS); - } - - output_counts->inter_mode.resize(INTER_MODE_CONTEXTS); - for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) { - output_counts->inter_mode[i].resize(INTER_MODES); - } - - output_counts->intra_inter.resize(INTRA_INTER_CONTEXTS); - for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) { - output_counts->intra_inter[i].resize(2); - } - - output_counts->comp_inter.resize(COMP_INTER_CONTEXTS); - for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) { - output_counts->comp_inter[i].resize(2); - } - - output_counts->single_ref.resize(REF_CONTEXTS); - for (int i = 0; i < REF_CONTEXTS; ++i) { - output_counts->single_ref[i].resize(2); - for (int j = 0; j < 2; ++j) { - output_counts->single_ref[i][j].resize(2); - } - } - - output_counts->comp_ref.resize(REF_CONTEXTS); - for (int i = 0; i < REF_CONTEXTS; ++i) { - output_counts->comp_ref[i].resize(2); - } - - output_counts->skip.resize(SKIP_CONTEXTS); - for (int i = 0; i < SKIP_CONTEXTS; ++i) { - output_counts->skip[i].resize(2); - } - - output_counts->tx.p32x32.resize(TX_SIZE_CONTEXTS); - output_counts->tx.p16x16.resize(TX_SIZE_CONTEXTS); - output_counts->tx.p8x8.resize(TX_SIZE_CONTEXTS); - for (int i = 0; i < TX_SIZE_CONTEXTS; i++) { - output_counts->tx.p32x32[i].resize(TX_SIZES); - output_counts->tx.p16x16[i].resize(TX_SIZES - 1); - output_counts->tx.p8x8[i].resize(TX_SIZES - 2); - } - output_counts->tx.tx_totals.resize(TX_SIZES); - - output_counts->mv.joints.resize(MV_JOINTS); - output_counts->mv.comps.resize(2); - for (int i = 0; i < 2; ++i) { - output_counts->mv.comps[i].sign.resize(2); - output_counts->mv.comps[i].classes.resize(MV_CLASSES); - output_counts->mv.comps[i].class0.resize(CLASS0_SIZE); - output_counts->mv.comps[i].bits.resize(MV_OFFSET_BITS); - for (int j = 0; j < MV_OFFSET_BITS; ++j) { - output_counts->mv.comps[i].bits[j].resize(2); - } - output_counts->mv.comps[i].class0_fp.resize(CLASS0_SIZE); - for (int j = 0; j < CLASS0_SIZE; ++j) { - output_counts->mv.comps[i].class0_fp[j].resize(MV_FP_SIZE); - } - output_counts->mv.comps[i].fp.resize(MV_FP_SIZE); - output_counts->mv.comps[i].class0_hp.resize(2); - output_counts->mv.comps[i].hp.resize(2); - } - - // Populate counts. - for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) { - for (int j = 0; j < INTRA_MODES; ++j) { - output_counts->y_mode[i][j] = input_counts->y_mode[i][j]; - } - } - for (int i = 0; i < INTRA_MODES; ++i) { - for (int j = 0; j < INTRA_MODES; ++j) { - output_counts->uv_mode[i][j] = input_counts->uv_mode[i][j]; - } - } - for (int i = 0; i < PARTITION_CONTEXTS; ++i) { - for (int j = 0; j < PARTITION_TYPES; ++j) { - output_counts->partition[i][j] = input_counts->partition[i][j]; - } - } - for (int i = 0; i < TX_SIZES; ++i) { - for (int j = 0; j < PLANE_TYPES; ++j) { - for (int k = 0; k < REF_TYPES; ++k) { - for (int l = 0; l < COEF_BANDS; ++l) { - for (int m = 0; m < COEFF_CONTEXTS; ++m) { - output_counts->eob_branch[i][j][k][l][m] = - input_counts->eob_branch[i][j][k][l][m]; - for (int n = 0; n < UNCONSTRAINED_NODES + 1; n++) { - output_counts->coef[i][j][k][l][m][n] = - input_counts->coef[i][j][k][l][m][n]; - } - } - } - } - } - } - for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) { - for (int j = 0; j < SWITCHABLE_FILTERS; ++j) { - output_counts->switchable_interp[i][j] = - input_counts->switchable_interp[i][j]; - } - } - for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) { - for (int j = 0; j < INTER_MODES; ++j) { - output_counts->inter_mode[i][j] = input_counts->inter_mode[i][j]; - } - } - for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) { - for (int j = 0; j < 2; ++j) { - output_counts->intra_inter[i][j] = input_counts->intra_inter[i][j]; - } - } - for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) { - for (int j = 0; j < 2; ++j) { - output_counts->comp_inter[i][j] = input_counts->comp_inter[i][j]; - } - } - for (int i = 0; i < REF_CONTEXTS; ++i) { - for (int j = 0; j < 2; ++j) { - for (int k = 0; k < 2; ++k) { - output_counts->single_ref[i][j][k] = input_counts->single_ref[i][j][k]; - } - } - } - for (int i = 0; i < REF_CONTEXTS; ++i) { - for (int j = 0; j < 2; ++j) { - output_counts->comp_ref[i][j] = input_counts->comp_ref[i][j]; - } - } - for (int i = 0; i < SKIP_CONTEXTS; ++i) { - for (int j = 0; j < 2; ++j) { - output_counts->skip[i][j] = input_counts->skip[i][j]; - } - } - for (int i = 0; i < TX_SIZE_CONTEXTS; i++) { - for (int j = 0; j < TX_SIZES; j++) { - output_counts->tx.p32x32[i][j] = input_counts->tx.p32x32[i][j]; - } - for (int j = 0; j < TX_SIZES - 1; j++) { - output_counts->tx.p16x16[i][j] = input_counts->tx.p16x16[i][j]; - } - for (int j = 0; j < TX_SIZES - 2; j++) { - output_counts->tx.p8x8[i][j] = input_counts->tx.p8x8[i][j]; - } - } - for (int i = 0; i < TX_SIZES; i++) { - output_counts->tx.tx_totals[i] = input_counts->tx.tx_totals[i]; - } - for (int i = 0; i < MV_JOINTS; i++) { - output_counts->mv.joints[i] = input_counts->mv.joints[i]; - } - for (int k = 0; k < 2; k++) { - const nmv_component_counts *const comps_t = &input_counts->mv.comps[k]; - for (int i = 0; i < 2; i++) { - output_counts->mv.comps[k].sign[i] = comps_t->sign[i]; - output_counts->mv.comps[k].class0_hp[i] = comps_t->class0_hp[i]; - output_counts->mv.comps[k].hp[i] = comps_t->hp[i]; - } - for (int i = 0; i < MV_CLASSES; i++) { - output_counts->mv.comps[k].classes[i] = comps_t->classes[i]; - } - for (int i = 0; i < CLASS0_SIZE; i++) { - output_counts->mv.comps[k].class0[i] = comps_t->class0[i]; - for (int j = 0; j < MV_FP_SIZE; j++) { - output_counts->mv.comps[k].class0_fp[i][j] = comps_t->class0_fp[i][j]; - } - } - for (int i = 0; i < MV_OFFSET_BITS; i++) { - for (int j = 0; j < 2; j++) { - output_counts->mv.comps[k].bits[i][j] = comps_t->bits[i][j]; - } - } - for (int i = 0; i < MV_FP_SIZE; i++) { - output_counts->mv.comps[k].fp[i] = comps_t->fp[i]; - } - } -} - -void output_image_buffer(const ImageBuffer &image_buffer, std::FILE *out_file) { - for (int plane = 0; plane < 3; ++plane) { - const int w = image_buffer.plane_width[plane]; - const int h = image_buffer.plane_height[plane]; - const uint8_t *buf = image_buffer.plane_buffer[plane].get(); - fprintf(out_file, "%d %d\n", h, w); - for (int i = 0; i < w * h; ++i) { - fprintf(out_file, "%d ", (int)buf[i]); - } - fprintf(out_file, "\n"); - } -} - -static bool init_image_buffer(ImageBuffer *image_buffer, int frame_width, - int frame_height, vpx_img_fmt_t img_fmt) { - for (int plane = 0; plane < 3; ++plane) { - const int w = get_plane_width(img_fmt, frame_width, plane); - const int h = get_plane_height(img_fmt, frame_height, plane); - image_buffer->plane_width[plane] = w; - image_buffer->plane_height[plane] = h; - image_buffer->plane_buffer[plane].reset(new (std::nothrow) uint8_t[w * h]); - if (image_buffer->plane_buffer[plane].get() == nullptr) { - return false; - } - } - return true; -} - -static void ImageBuffer_to_IMAGE_BUFFER(const ImageBuffer &image_buffer, - IMAGE_BUFFER *image_buffer_c) { - image_buffer_c->allocated = 1; - for (int plane = 0; plane < 3; ++plane) { - image_buffer_c->plane_width[plane] = image_buffer.plane_width[plane]; - image_buffer_c->plane_height[plane] = image_buffer.plane_height[plane]; - image_buffer_c->plane_buffer[plane] = - image_buffer.plane_buffer[plane].get(); - } -} - -static size_t get_max_coding_data_byte_size(int frame_width, int frame_height) { - return frame_width * frame_height * 3; -} - -static bool init_encode_frame_result(EncodeFrameResult *encode_frame_result, - int frame_width, int frame_height, - vpx_img_fmt_t img_fmt) { - const size_t max_coding_data_byte_size = - get_max_coding_data_byte_size(frame_width, frame_height); - - encode_frame_result->coding_data.reset( - new (std::nothrow) uint8_t[max_coding_data_byte_size]); - encode_frame_result->max_coding_data_byte_size = max_coding_data_byte_size; - - encode_frame_result->num_rows_4x4 = get_num_unit_4x4(frame_height); - encode_frame_result->num_cols_4x4 = get_num_unit_4x4(frame_width); - encode_frame_result->partition_info.resize(encode_frame_result->num_rows_4x4 * - encode_frame_result->num_cols_4x4); - encode_frame_result->motion_vector_info.resize( - encode_frame_result->num_rows_4x4 * encode_frame_result->num_cols_4x4); - encode_frame_result->tpl_stats_info.resize(MAX_LAG_BUFFERS); - - if (encode_frame_result->coding_data.get() == nullptr) { - encode_frame_result->max_coding_data_byte_size = 0; - return false; - } - return init_image_buffer(&encode_frame_result->coded_frame, frame_width, - frame_height, img_fmt); -} - -static void encode_frame_result_update_rq_history( - const RATE_QINDEX_HISTORY *rq_history, - EncodeFrameResult *encode_frame_result) { - encode_frame_result->recode_count = rq_history->recode_count; - for (int i = 0; i < encode_frame_result->recode_count; ++i) { - const int q_index = rq_history->q_index_history[i]; - const int rate = rq_history->rate_history[i]; - encode_frame_result->q_index_history.push_back(q_index); - encode_frame_result->rate_history.push_back(rate); - } -} - -static void update_encode_frame_result( - EncodeFrameResult *encode_frame_result, const int show_frame_count, - const ENCODE_FRAME_RESULT *encode_frame_info) { - encode_frame_result->coding_data_bit_size = - encode_frame_result->coding_data_byte_size * 8; - encode_frame_result->show_idx = encode_frame_info->show_idx; - encode_frame_result->coding_idx = encode_frame_info->frame_coding_index; - assert(kRefFrameTypeMax == MAX_INTER_REF_FRAMES); - for (int i = 0; i < kRefFrameTypeMax; ++i) { - encode_frame_result->ref_frame_info.coding_indexes[i] = - encode_frame_info->ref_frame_coding_indexes[i]; - encode_frame_result->ref_frame_info.valid_list[i] = - encode_frame_info->ref_frame_valid_list[i]; - } - encode_frame_result->frame_type = - get_frame_type_from_update_type(encode_frame_info->update_type); - encode_frame_result->psnr = encode_frame_info->psnr; - encode_frame_result->sse = encode_frame_info->sse; - encode_frame_result->quantize_index = encode_frame_info->quantize_index; - update_partition_info(encode_frame_info->partition_info, - encode_frame_result->num_rows_4x4, - encode_frame_result->num_cols_4x4, - &encode_frame_result->partition_info[0]); - update_motion_vector_info(encode_frame_info->motion_vector_info, - encode_frame_result->num_rows_4x4, - encode_frame_result->num_cols_4x4, - &encode_frame_result->motion_vector_info[0], - kMotionVectorSubPixelPrecision); - update_frame_counts(&encode_frame_info->frame_counts, - &encode_frame_result->frame_counts); - if (encode_frame_result->frame_type == kFrameTypeAltRef) { - update_tpl_stats_info(encode_frame_info->tpl_stats_info, show_frame_count, - &encode_frame_result->tpl_stats_info[0]); - } - encode_frame_result_update_rq_history(&encode_frame_info->rq_history, - encode_frame_result); -} - -static void IncreaseGroupOfPictureIndex(GroupOfPicture *group_of_picture) { - ++group_of_picture->next_encode_frame_index; -} - -static int IsGroupOfPictureFinished(const GroupOfPicture &group_of_picture) { - return static_cast(group_of_picture.next_encode_frame_index) == - group_of_picture.encode_frame_list.size(); -} - -bool operator==(const RefFrameInfo &a, const RefFrameInfo &b) { - bool match = true; - for (int i = 0; i < kRefFrameTypeMax; ++i) { - match &= a.coding_indexes[i] == b.coding_indexes[i]; - match &= a.valid_list[i] == b.valid_list[i]; - } - return match; -} - -static void InitRefFrameInfo(RefFrameInfo *ref_frame_info) { - for (int i = 0; i < kRefFrameTypeMax; ++i) { - ref_frame_info->coding_indexes[i] = -1; - ref_frame_info->valid_list[i] = 0; - } -} - -// After finishing coding a frame, this function will update the coded frame -// into the ref_frame_info based on the frame_type and the coding_index. -static void PostUpdateRefFrameInfo(FrameType frame_type, int frame_coding_index, - RefFrameInfo *ref_frame_info) { - // This part is written based on the logics in vp9_configure_buffer_updates() - // and update_ref_frames() - int *ref_frame_coding_indexes = ref_frame_info->coding_indexes; - switch (frame_type) { - case kFrameTypeKey: - ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index; - ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index; - ref_frame_coding_indexes[kRefFrameTypeFuture] = frame_coding_index; - break; - case kFrameTypeInter: - ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index; - break; - case kFrameTypeAltRef: - ref_frame_coding_indexes[kRefFrameTypeFuture] = frame_coding_index; - break; - case kFrameTypeOverlay: - // Reserve the past coding_index in the future slot. This logic is from - // update_ref_frames() with condition vp9_preserve_existing_gf() == 1 - // TODO(angiebird): Invetegate why we need this. - ref_frame_coding_indexes[kRefFrameTypeFuture] = - ref_frame_coding_indexes[kRefFrameTypePast]; - ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index; - break; - case kFrameTypeGolden: - ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index; - ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index; - break; - } - - // This part is written based on the logics in get_ref_frame_flags() but we - // rename the flags alt, golden to future, past respectively. Mark - // non-duplicated reference frames as valid. The priorities are - // kRefFrameTypeLast > kRefFrameTypePast > kRefFrameTypeFuture. - const int last_index = ref_frame_coding_indexes[kRefFrameTypeLast]; - const int past_index = ref_frame_coding_indexes[kRefFrameTypePast]; - const int future_index = ref_frame_coding_indexes[kRefFrameTypeFuture]; - - int *ref_frame_valid_list = ref_frame_info->valid_list; - for (int ref_frame_idx = 0; ref_frame_idx < kRefFrameTypeMax; - ++ref_frame_idx) { - ref_frame_valid_list[ref_frame_idx] = 1; - } - - if (past_index == last_index) { - ref_frame_valid_list[kRefFrameTypePast] = 0; - } - - if (future_index == last_index) { - ref_frame_valid_list[kRefFrameTypeFuture] = 0; - } - - if (future_index == past_index) { - ref_frame_valid_list[kRefFrameTypeFuture] = 0; - } -} - -static void SetGroupOfPicture(int first_is_key_frame, int use_alt_ref, - int coding_frame_count, int first_show_idx, - int last_gop_use_alt_ref, int start_coding_index, - const RefFrameInfo &start_ref_frame_info, - GroupOfPicture *group_of_picture) { - // Clean up the state of previous group of picture. - group_of_picture->encode_frame_list.clear(); - group_of_picture->next_encode_frame_index = 0; - group_of_picture->show_frame_count = coding_frame_count - use_alt_ref; - group_of_picture->start_show_index = first_show_idx; - group_of_picture->start_coding_index = start_coding_index; - group_of_picture->first_is_key_frame = first_is_key_frame; - group_of_picture->use_alt_ref = use_alt_ref; - group_of_picture->last_gop_use_alt_ref = last_gop_use_alt_ref; - - // We need to make a copy of start reference frame info because we - // use it to simulate the ref frame update. - RefFrameInfo ref_frame_info = start_ref_frame_info; - - { - // First frame in the group of pictures. It's either key frame or show inter - // frame. - EncodeFrameInfo encode_frame_info; - // Set frame_type - if (first_is_key_frame) { - encode_frame_info.frame_type = kFrameTypeKey; - } else { - if (last_gop_use_alt_ref) { - encode_frame_info.frame_type = kFrameTypeOverlay; - } else { - encode_frame_info.frame_type = kFrameTypeGolden; - } - } - - encode_frame_info.show_idx = first_show_idx; - encode_frame_info.coding_index = start_coding_index; - - encode_frame_info.ref_frame_info = ref_frame_info; - PostUpdateRefFrameInfo(encode_frame_info.frame_type, - encode_frame_info.coding_index, &ref_frame_info); - - group_of_picture->encode_frame_list.push_back(encode_frame_info); - } - - const int show_frame_count = coding_frame_count - use_alt_ref; - if (use_alt_ref) { - // If there is alternate reference, it is always coded at the second place. - // Its show index (or timestamp) is at the last of this group - EncodeFrameInfo encode_frame_info; - encode_frame_info.frame_type = kFrameTypeAltRef; - encode_frame_info.show_idx = first_show_idx + show_frame_count; - encode_frame_info.coding_index = start_coding_index + 1; - - encode_frame_info.ref_frame_info = ref_frame_info; - PostUpdateRefFrameInfo(encode_frame_info.frame_type, - encode_frame_info.coding_index, &ref_frame_info); - - group_of_picture->encode_frame_list.push_back(encode_frame_info); - } - - // Encode the rest show inter frames. - for (int i = 1; i < show_frame_count; ++i) { - EncodeFrameInfo encode_frame_info; - encode_frame_info.frame_type = kFrameTypeInter; - encode_frame_info.show_idx = first_show_idx + i; - encode_frame_info.coding_index = start_coding_index + use_alt_ref + i; - - encode_frame_info.ref_frame_info = ref_frame_info; - PostUpdateRefFrameInfo(encode_frame_info.frame_type, - encode_frame_info.coding_index, &ref_frame_info); - - group_of_picture->encode_frame_list.push_back(encode_frame_info); - } -} - -// Gets group of picture information from VP9's decision, and update -// |group_of_picture| accordingly. -// This is called at the starting of encoding of each group of picture. -static void UpdateGroupOfPicture(const VP9_COMP *cpi, int start_coding_index, - const RefFrameInfo &start_ref_frame_info, - GroupOfPicture *group_of_picture) { - int first_is_key_frame; - int use_alt_ref; - int coding_frame_count; - int first_show_idx; - int last_gop_use_alt_ref; - vp9_get_next_group_of_picture(cpi, &first_is_key_frame, &use_alt_ref, - &coding_frame_count, &first_show_idx, - &last_gop_use_alt_ref); - SetGroupOfPicture(first_is_key_frame, use_alt_ref, coding_frame_count, - first_show_idx, last_gop_use_alt_ref, start_coding_index, - start_ref_frame_info, group_of_picture); -} - -#define SET_STRUCT_VALUE(config, structure, ret, field) \ - do { \ - if (strcmp(config.name, #field) == 0) { \ - structure->field = atoi(config.value); \ - ret = 1; \ - } \ - } while (false) - -static void UpdateEncodeConfig(const EncodeConfig &config, - VP9EncoderConfig *oxcf) { - int ret = 0; - SET_STRUCT_VALUE(config, oxcf, ret, key_freq); - SET_STRUCT_VALUE(config, oxcf, ret, two_pass_vbrmin_section); - SET_STRUCT_VALUE(config, oxcf, ret, two_pass_vbrmax_section); - SET_STRUCT_VALUE(config, oxcf, ret, under_shoot_pct); - SET_STRUCT_VALUE(config, oxcf, ret, over_shoot_pct); - SET_STRUCT_VALUE(config, oxcf, ret, max_threads); - SET_STRUCT_VALUE(config, oxcf, ret, frame_parallel_decoding_mode); - SET_STRUCT_VALUE(config, oxcf, ret, tile_columns); - SET_STRUCT_VALUE(config, oxcf, ret, arnr_max_frames); - SET_STRUCT_VALUE(config, oxcf, ret, arnr_strength); - SET_STRUCT_VALUE(config, oxcf, ret, lag_in_frames); - SET_STRUCT_VALUE(config, oxcf, ret, encode_breakout); - SET_STRUCT_VALUE(config, oxcf, ret, enable_tpl_model); - SET_STRUCT_VALUE(config, oxcf, ret, enable_auto_arf); - if (strcmp(config.name, "rc_mode") == 0) { - int rc_mode = atoi(config.value); - if (rc_mode >= VPX_VBR && rc_mode <= VPX_Q) { - oxcf->rc_mode = (enum vpx_rc_mode)rc_mode; - ret = 1; - } else { - fprintf(stderr, "Invalid rc_mode value: %d\n", rc_mode); - } - } - SET_STRUCT_VALUE(config, oxcf, ret, cq_level); - if (ret == 0) { - fprintf(stderr, "Ignored unsupported encode_config %s\n", config.name); - } -} - -static VP9EncoderConfig GetEncodeConfig( - int frame_width, int frame_height, vpx_rational_t frame_rate, - int target_bitrate, int encode_speed, int target_level, - vpx_enc_pass enc_pass, - const std::vector &encode_config_list) { - VP9EncoderConfig oxcf = vp9_get_encoder_config( - frame_width, frame_height, frame_rate, target_bitrate, encode_speed, - target_level, enc_pass); - for (const auto &config : encode_config_list) { - UpdateEncodeConfig(config, &oxcf); - } - if (enc_pass == VPX_RC_FIRST_PASS) { - oxcf.lag_in_frames = 0; - } - oxcf.use_simple_encode_api = 1; - return oxcf; -} - -SimpleEncode::SimpleEncode(int frame_width, int frame_height, - int frame_rate_num, int frame_rate_den, - int target_bitrate, int num_frames, int target_level, - const char *infile_path, const char *outfile_path) { - impl_ptr_ = std::unique_ptr(new EncodeImpl()); - frame_width_ = frame_width; - frame_height_ = frame_height; - frame_rate_num_ = frame_rate_num; - frame_rate_den_ = frame_rate_den; - target_bitrate_ = target_bitrate; - num_frames_ = num_frames; - encode_speed_ = 0; - target_level_ = target_level; - - frame_coding_index_ = 0; - show_frame_count_ = 0; - - key_frame_group_index_ = 0; - key_frame_group_size_ = 0; - - // TODO(angirbid): Should we keep a file pointer here or keep the file_path? - assert(infile_path != nullptr); - in_file_ = fopen(infile_path, "r"); - if (outfile_path != nullptr) { - out_file_ = fopen(outfile_path, "w"); - } else { - out_file_ = nullptr; - } - impl_ptr_->cpi = nullptr; - impl_ptr_->img_fmt = VPX_IMG_FMT_I420; - - InitRefFrameInfo(&ref_frame_info_); -} - -void SimpleEncode::SetEncodeSpeed(int encode_speed) { - encode_speed_ = encode_speed; -} - -StatusCode SimpleEncode::SetEncodeConfig(const char *name, const char *value) { - if (name == nullptr || value == nullptr) { - fprintf(stderr, "SetEncodeConfig: null pointer, name %p value %p\n", name, - value); - return StatusError; - } - EncodeConfig config; - snprintf(config.name, ENCODE_CONFIG_BUF_SIZE, "%s", name); - snprintf(config.value, ENCODE_CONFIG_BUF_SIZE, "%s", value); - impl_ptr_->encode_config_list.push_back(config); - return StatusOk; -} - -StatusCode SimpleEncode::DumpEncodeConfigs(int pass, FILE *fp) { - if (fp == nullptr) { - fprintf(stderr, "DumpEncodeConfigs: null pointer, fp %p\n", fp); - return StatusError; - } - vpx_enc_pass enc_pass; - if (pass == 1) { - enc_pass = VPX_RC_FIRST_PASS; - } else { - enc_pass = VPX_RC_LAST_PASS; - } - const vpx_rational_t frame_rate = - make_vpx_rational(frame_rate_num_, frame_rate_den_); - const VP9EncoderConfig oxcf = GetEncodeConfig( - frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_, - target_level_, enc_pass, impl_ptr_->encode_config_list); - vp9_dump_encoder_config(&oxcf, fp); - return StatusOk; -} - -void SimpleEncode::ComputeFirstPassStats() { - vpx_rational_t frame_rate = - make_vpx_rational(frame_rate_num_, frame_rate_den_); - const VP9EncoderConfig oxcf = GetEncodeConfig( - frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_, - target_level_, VPX_RC_FIRST_PASS, impl_ptr_->encode_config_list); - impl_ptr_->cpi = init_encoder(&oxcf, impl_ptr_->img_fmt); - struct lookahead_ctx *lookahead = impl_ptr_->cpi->lookahead; - int i; - int use_highbitdepth = 0; - const int num_rows_16x16 = get_num_unit_16x16(frame_height_); - const int num_cols_16x16 = get_num_unit_16x16(frame_width_); -#if CONFIG_VP9_HIGHBITDEPTH - use_highbitdepth = impl_ptr_->cpi->common.use_highbitdepth; -#endif - vpx_image_t img; - if (impl_ptr_->img_fmt == VPX_IMG_FMT_NV12) { - fprintf(stderr, "VPX_IMG_FMT_NV12 is not supported\n"); - abort(); - } - vpx_img_alloc(&img, impl_ptr_->img_fmt, frame_width_, frame_height_, 1); - rewind(in_file_); - impl_ptr_->first_pass_stats.clear(); - for (i = 0; i < num_frames_; ++i) { - assert(!vp9_lookahead_full(lookahead)); - if (img_read(&img, in_file_)) { - int next_show_idx = vp9_lookahead_next_show_idx(lookahead); - int64_t ts_start = - timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx); - int64_t ts_end = - timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx + 1); - YV12_BUFFER_CONFIG sd; - image2yuvconfig(&img, &sd); - vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0); - { - int64_t time_stamp; - int64_t time_end; - int flush = 1; // Makes vp9_get_compressed_data process a frame - size_t size; - unsigned int frame_flags = 0; - ENCODE_FRAME_RESULT encode_frame_info; - vp9_init_encode_frame_result(&encode_frame_info); - // TODO(angiebird): Call vp9_first_pass directly - vp9_get_compressed_data(impl_ptr_->cpi, &frame_flags, &size, nullptr, 0, - &time_stamp, &time_end, flush, - &encode_frame_info); - // vp9_get_compressed_data only generates first pass stats not - // compresses data - assert(size == 0); - // Get vp9 first pass motion vector info. - std::vector mv_info(num_rows_16x16 * num_cols_16x16); - update_motion_vector_info( - impl_ptr_->cpi->fp_motion_vector_info, num_rows_16x16, - num_cols_16x16, mv_info.data(), kMotionVectorFullPixelPrecision); - fp_motion_vector_info_.push_back(mv_info); - } - impl_ptr_->first_pass_stats.push_back( - vp9_get_frame_stats(&impl_ptr_->cpi->twopass)); - } - } - // TODO(angiebird): Store the total_stats apart form first_pass_stats - impl_ptr_->first_pass_stats.push_back( - vp9_get_total_stats(&impl_ptr_->cpi->twopass)); - vp9_end_first_pass(impl_ptr_->cpi); - - // Generate key_frame_map based on impl_ptr_->first_pass_stats. - key_frame_map_ = ComputeKeyFrameMap(); - - free_encoder(impl_ptr_->cpi); - impl_ptr_->cpi = nullptr; - rewind(in_file_); - vpx_img_free(&img); -} - -std::vector> SimpleEncode::ObserveFirstPassStats() { - std::vector> output_stats; - // TODO(angiebird): This function make several assumptions of - // FIRSTPASS_STATS. 1) All elements in FIRSTPASS_STATS are double except the - // last one. 2) The last entry of first_pass_stats is the total_stats. - // Change the code structure, so that we don't have to make these assumptions - - // Note the last entry of first_pass_stats is the total_stats, we don't need - // it. - for (size_t i = 0; i < impl_ptr_->first_pass_stats.size() - 1; ++i) { - double *buf_start = - reinterpret_cast(&impl_ptr_->first_pass_stats[i]); - // We use - 2 here because: - // (1). The last member in FIRSTPASS_STATS is not double. - // (2). We do not need the last - 1 member. - double *buf_end = - buf_start + sizeof(impl_ptr_->first_pass_stats[i]) / sizeof(*buf_end) - - 2; - std::vector this_stats(buf_start, buf_end); - output_stats.push_back(this_stats); - } - return output_stats; -} - -std::vector> -SimpleEncode::ObserveFirstPassMotionVectors() { - return fp_motion_vector_info_; -} - -void SimpleEncode::SetExternalGroupOfPicturesMap(int *gop_map, - int gop_map_size) { - for (int i = 0; i < gop_map_size; ++i) { - gop_map_.push_back(gop_map[i]); - } - // The following will check and modify gop_map_ to make sure the - // gop_map_ satisfies the constraints. - // 1) Each key frame position should be at the start of a gop. - // 2) The last gop should not use an alt ref. - assert(gop_map_.size() == key_frame_map_.size()); - int last_gop_start = 0; - for (int i = 0; static_cast(i) < gop_map_.size(); ++i) { - if (key_frame_map_[i] == 1 && gop_map_[i] == 0) { - fprintf(stderr, "Add an extra gop start at show_idx %d\n", i); - // Insert a gop start at key frame location. - gop_map_[i] |= kGopMapFlagStart; - gop_map_[i] |= kGopMapFlagUseAltRef; - } - if (gop_map_[i] & kGopMapFlagStart) { - last_gop_start = i; - } - } - if (gop_map_[last_gop_start] & kGopMapFlagUseAltRef) { - fprintf(stderr, - "Last group of pictures starting at show_idx %d shouldn't use alt " - "ref\n", - last_gop_start); - gop_map_[last_gop_start] &= ~kGopMapFlagUseAltRef; - } -} - -std::vector SimpleEncode::ObserveExternalGroupOfPicturesMap() { - return gop_map_; -} - -template -T *GetVectorData(const std::vector &v) { - if (v.empty()) { - return nullptr; - } - return const_cast(v.data()); -} - -static GOP_COMMAND GetGopCommand(const std::vector &gop_map, - int start_show_index) { - GOP_COMMAND gop_command; - if (static_cast(start_show_index) < gop_map.size()) { - assert((gop_map[start_show_index] & kGopMapFlagStart) != 0); - int end_show_index = start_show_index + 1; - // gop_map[end_show_index] & kGopMapFlagStart == 0 means this is - // the start of a gop. - while (static_cast(end_show_index) < gop_map.size() && - (gop_map[end_show_index] & kGopMapFlagStart) == 0) { - ++end_show_index; - } - const int show_frame_count = end_show_index - start_show_index; - int use_alt_ref = (gop_map[start_show_index] & kGopMapFlagUseAltRef) != 0; - if (static_cast(end_show_index) == gop_map.size()) { - // This is the last gop group, there must be no altref. - use_alt_ref = 0; - } - gop_command_on(&gop_command, show_frame_count, use_alt_ref); - } else { - gop_command_off(&gop_command); - } - return gop_command; -} - -void SimpleEncode::StartEncode() { - assert(impl_ptr_->first_pass_stats.size() > 0); - vpx_rational_t frame_rate = - make_vpx_rational(frame_rate_num_, frame_rate_den_); - VP9EncoderConfig oxcf = GetEncodeConfig( - frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_, - target_level_, VPX_RC_LAST_PASS, impl_ptr_->encode_config_list); - - vpx_fixed_buf_t stats; - stats.buf = GetVectorData(impl_ptr_->first_pass_stats); - stats.sz = sizeof(impl_ptr_->first_pass_stats[0]) * - impl_ptr_->first_pass_stats.size(); - - vp9_set_first_pass_stats(&oxcf, &stats); - assert(impl_ptr_->cpi == nullptr); - impl_ptr_->cpi = init_encoder(&oxcf, impl_ptr_->img_fmt); - if (impl_ptr_->img_fmt == VPX_IMG_FMT_NV12) { - fprintf(stderr, "VPX_IMG_FMT_NV12 is not supported\n"); - abort(); - } - vpx_img_alloc(&impl_ptr_->tmp_img, impl_ptr_->img_fmt, frame_width_, - frame_height_, 1); - - frame_coding_index_ = 0; - show_frame_count_ = 0; - - assert(impl_ptr_->cpi != nullptr); - FRAME_INFO frame_info = vp9_get_frame_info(&oxcf); - unsigned int screen_area = frame_info.frame_width * frame_info.frame_height; - vp9_init_vizier_params(&impl_ptr_->cpi->twopass, screen_area); - - UpdateKeyFrameGroup(show_frame_count_); - - const GOP_COMMAND gop_command = GetGopCommand(gop_map_, show_frame_count_); - encode_command_set_gop_command(&impl_ptr_->cpi->encode_command, gop_command); - UpdateGroupOfPicture(impl_ptr_->cpi, frame_coding_index_, ref_frame_info_, - &group_of_picture_); - rewind(in_file_); - - if (out_file_ != nullptr) { - const char *fourcc = "VP90"; - // In SimpleEncode, we use time_base = 1 / TICKS_PER_SEC. - // Based on that, the ivf_timestamp for each image is set to - // show_idx * TICKS_PER_SEC / frame_rate - // such that each image's actual timestamp in seconds can be computed as - // ivf_timestamp * time_base == show_idx / frame_rate - // TODO(angiebird): 1) Add unit test for ivf timestamp. - // 2) Simplify the frame_rate setting process. - vpx_rational_t time_base = make_vpx_rational(1, TICKS_PER_SEC); - ivf_write_file_header_with_video_info(out_file_, *(const uint32_t *)fourcc, - num_frames_, frame_width_, - frame_height_, time_base); - } -} - -void SimpleEncode::EndEncode() { - free_encoder(impl_ptr_->cpi); - impl_ptr_->cpi = nullptr; - vpx_img_free(&impl_ptr_->tmp_img); - rewind(in_file_); -} - -void SimpleEncode::UpdateKeyFrameGroup(int key_frame_show_index) { - const VP9_COMP *cpi = impl_ptr_->cpi; - key_frame_group_index_ = 0; - key_frame_group_size_ = vp9_get_frames_to_next_key( - &cpi->oxcf, &cpi->twopass, key_frame_show_index, cpi->rc.min_gf_interval); - assert(key_frame_group_size_ > 0); - // Init the reference frame info when a new key frame group appears. - InitRefFrameInfo(&ref_frame_info_); -} - -void SimpleEncode::PostUpdateKeyFrameGroupIndex(FrameType frame_type) { - if (frame_type != kFrameTypeAltRef) { - // key_frame_group_index_ only counts show frames - ++key_frame_group_index_; - } -} - -int SimpleEncode::GetKeyFrameGroupSize() const { return key_frame_group_size_; } - -GroupOfPicture SimpleEncode::ObserveGroupOfPicture() const { - return group_of_picture_; -} - -EncodeFrameInfo SimpleEncode::GetNextEncodeFrameInfo() const { - return group_of_picture_ - .encode_frame_list[group_of_picture_.next_encode_frame_index]; -} - -void SimpleEncode::PostUpdateState( - const EncodeFrameResult &encode_frame_result) { - // This function needs to be called before the increament of - // frame_coding_index_ - PostUpdateRefFrameInfo(encode_frame_result.frame_type, frame_coding_index_, - &ref_frame_info_); - ++frame_coding_index_; - if (encode_frame_result.frame_type != kFrameTypeAltRef) { - // Only kFrameTypeAltRef is not a show frame - ++show_frame_count_; - } - - PostUpdateKeyFrameGroupIndex(encode_frame_result.frame_type); - if (key_frame_group_index_ == key_frame_group_size_) { - UpdateKeyFrameGroup(show_frame_count_); - } - - IncreaseGroupOfPictureIndex(&group_of_picture_); - if (IsGroupOfPictureFinished(group_of_picture_)) { - const GOP_COMMAND gop_command = GetGopCommand(gop_map_, show_frame_count_); - encode_command_set_gop_command(&impl_ptr_->cpi->encode_command, - gop_command); - // This function needs to be called after ref_frame_info_ is updated - // properly in PostUpdateRefFrameInfo() and UpdateKeyFrameGroup(). - UpdateGroupOfPicture(impl_ptr_->cpi, frame_coding_index_, ref_frame_info_, - &group_of_picture_); - } -} - -void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) { - VP9_COMP *cpi = impl_ptr_->cpi; - struct lookahead_ctx *lookahead = cpi->lookahead; - int use_highbitdepth = 0; -#if CONFIG_VP9_HIGHBITDEPTH - use_highbitdepth = cpi->common.use_highbitdepth; -#endif - // The lookahead's size is set to oxcf->lag_in_frames. - // We want to fill lookahead to it's max capacity if possible so that the - // encoder can construct alt ref frame in time. - // In the other words, we hope vp9_get_compressed_data to encode a frame - // every time in the function - while (!vp9_lookahead_full(lookahead)) { - // TODO(angiebird): Check whether we can move this file read logics to - // lookahead - if (img_read(&impl_ptr_->tmp_img, in_file_)) { - int next_show_idx = vp9_lookahead_next_show_idx(lookahead); - int64_t ts_start = - timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, next_show_idx); - int64_t ts_end = timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, - next_show_idx + 1); - YV12_BUFFER_CONFIG sd; - image2yuvconfig(&impl_ptr_->tmp_img, &sd); - vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0); - } else { - break; - } - } - - if (init_encode_frame_result(encode_frame_result, frame_width_, frame_height_, - impl_ptr_->img_fmt)) { - int64_t time_stamp; - int64_t time_end; - int flush = 1; // Make vp9_get_compressed_data encode a frame - unsigned int frame_flags = 0; - ENCODE_FRAME_RESULT encode_frame_info; - vp9_init_encode_frame_result(&encode_frame_info); - ImageBuffer_to_IMAGE_BUFFER(encode_frame_result->coded_frame, - &encode_frame_info.coded_frame); - vp9_get_compressed_data(cpi, &frame_flags, - &encode_frame_result->coding_data_byte_size, - encode_frame_result->coding_data.get(), - encode_frame_result->max_coding_data_byte_size, - &time_stamp, &time_end, flush, &encode_frame_info); - if (out_file_ != nullptr) { - ivf_write_frame_header(out_file_, time_stamp, - encode_frame_result->coding_data_byte_size); - fwrite(encode_frame_result->coding_data.get(), 1, - encode_frame_result->coding_data_byte_size, out_file_); - } - - // vp9_get_compressed_data is expected to encode a frame every time, so the - // data size should be greater than zero. - if (encode_frame_result->coding_data_byte_size <= 0) { - fprintf(stderr, "Coding data size <= 0\n"); - abort(); - } - if (encode_frame_result->coding_data_byte_size > - encode_frame_result->max_coding_data_byte_size) { - fprintf(stderr, "Coding data size exceeds the maximum.\n"); - abort(); - } - - const GroupOfPicture group_of_picture = this->ObserveGroupOfPicture(); - const int show_frame_count = group_of_picture.show_frame_count; - update_encode_frame_result(encode_frame_result, show_frame_count, - &encode_frame_info); - PostUpdateState(*encode_frame_result); - } else { - // TODO(angiebird): Clean up encode_frame_result. - fprintf(stderr, "init_encode_frame_result() failed.\n"); - this->EndEncode(); - } -} - -void SimpleEncode::EncodeFrameWithQuantizeIndex( - EncodeFrameResult *encode_frame_result, int quantize_index) { - encode_command_set_external_quantize_index(&impl_ptr_->cpi->encode_command, - quantize_index); - EncodeFrame(encode_frame_result); - encode_command_reset_external_quantize_index(&impl_ptr_->cpi->encode_command); -} - -void SimpleEncode::EncodeFrameWithTargetFrameBits( - EncodeFrameResult *encode_frame_result, int target_frame_bits, - double percent_diff) { - encode_command_set_target_frame_bits(&impl_ptr_->cpi->encode_command, - target_frame_bits, percent_diff); - EncodeFrame(encode_frame_result); - encode_command_reset_target_frame_bits(&impl_ptr_->cpi->encode_command); -} - -static int GetCodingFrameNumFromGopMap(const std::vector &gop_map) { - int start_show_index = 0; - int coding_frame_count = 0; - while (static_cast(start_show_index) < gop_map.size()) { - const GOP_COMMAND gop_command = GetGopCommand(gop_map, start_show_index); - start_show_index += gop_command.show_frame_count; - coding_frame_count += gop_command_coding_frame_count(&gop_command); - } - assert(static_cast(start_show_index) == gop_map.size()); - return coding_frame_count; -} - -int SimpleEncode::GetCodingFrameNum() const { - assert(impl_ptr_->first_pass_stats.size() > 0); - if (gop_map_.size() > 0) { - return GetCodingFrameNumFromGopMap(gop_map_); - } - - // These are the default settings for now. - TWO_PASS twopass; - const int multi_layer_arf = 0; - const int allow_alt_ref = 1; - vpx_rational_t frame_rate = - make_vpx_rational(frame_rate_num_, frame_rate_den_); - const VP9EncoderConfig oxcf = GetEncodeConfig( - frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_, - target_level_, VPX_RC_LAST_PASS, impl_ptr_->encode_config_list); - FRAME_INFO frame_info = vp9_get_frame_info(&oxcf); - fps_init_first_pass_info(&twopass.first_pass_info, - GetVectorData(impl_ptr_->first_pass_stats), - num_frames_); - unsigned int screen_area = frame_info.frame_width * frame_info.frame_height; - vp9_init_vizier_params(&twopass, screen_area); - return vp9_get_coding_frame_num(&oxcf, &twopass, &frame_info, multi_layer_arf, - allow_alt_ref); -} - -std::vector SimpleEncode::ComputeKeyFrameMap() const { - // The last entry of first_pass_stats is the overall stats. - assert(impl_ptr_->first_pass_stats.size() == - static_cast(num_frames_) + 1); - vpx_rational_t frame_rate = - make_vpx_rational(frame_rate_num_, frame_rate_den_); - const VP9EncoderConfig oxcf = GetEncodeConfig( - frame_width_, frame_height_, frame_rate, target_bitrate_, encode_speed_, - target_level_, VPX_RC_LAST_PASS, impl_ptr_->encode_config_list); - TWO_PASS twopass; - fps_init_first_pass_info(&twopass.first_pass_info, - GetVectorData(impl_ptr_->first_pass_stats), - num_frames_); - std::vector key_frame_map(num_frames_, 0); - vp9_get_key_frame_map(&oxcf, &twopass, GetVectorData(key_frame_map)); - return key_frame_map; -} - -std::vector SimpleEncode::ObserveKeyFrameMap() const { - return key_frame_map_; -} - -uint64_t SimpleEncode::GetFramePixelCount() const { - assert(frame_width_ % 2 == 0); - assert(frame_height_ % 2 == 0); - switch (impl_ptr_->img_fmt) { - case VPX_IMG_FMT_I420: return frame_width_ * frame_height_ * 3 / 2; - case VPX_IMG_FMT_I422: return frame_width_ * frame_height_ * 2; - case VPX_IMG_FMT_I444: return frame_width_ * frame_height_ * 3; - case VPX_IMG_FMT_I440: return frame_width_ * frame_height_ * 2; - case VPX_IMG_FMT_I42016: return frame_width_ * frame_height_ * 3 / 2; - case VPX_IMG_FMT_I42216: return frame_width_ * frame_height_ * 2; - case VPX_IMG_FMT_I44416: return frame_width_ * frame_height_ * 3; - case VPX_IMG_FMT_I44016: return frame_width_ * frame_height_ * 2; - default: return 0; - } -} - -SimpleEncode::~SimpleEncode() { - if (in_file_ != nullptr) { - fclose(in_file_); - } - if (out_file_ != nullptr) { - fclose(out_file_); - } -} - -} // namespace vp9 diff --git a/media/libvpx/libvpx/vp9/vp9_cx_iface.c b/media/libvpx/libvpx/vp9/vp9_cx_iface.c --- a/media/libvpx/libvpx/vp9/vp9_cx_iface.c +++ b/media/libvpx/libvpx/vp9/vp9_cx_iface.c @@ -15,10 +15,11 @@ #include "./vpx_config.h" #include "vpx/vpx_encoder.h" #include "vpx/vpx_ext_ratectrl.h" #include "vpx_dsp/psnr.h" +#include "vpx_dsp/vpx_dsp_common.h" #include "vpx_ports/static_assert.h" #include "vpx_ports/system_state.h" #include "vpx_util/vpx_timestamp.h" #include "vpx/internal/vpx_codec_internal.h" #include "./vpx_version.h" @@ -668,11 +669,10 @@ } else if (oxcf->ts_number_layers == 1) { oxcf->ts_rate_decimator[0] = 1; } if (get_level_index(oxcf->target_level) >= 0) config_target_level(oxcf); - oxcf->use_simple_encode_api = 0; // vp9_dump_encoder_config(oxcf, stderr); return VPX_CODEC_OK; } static vpx_codec_err_t set_twopass_params_from_config( @@ -911,12 +911,11 @@ static vpx_codec_err_t ctrl_set_cpuused(vpx_codec_alg_priv_t *ctx, va_list args) { struct vp9_extracfg extra_cfg = ctx->extra_cfg; // Use fastest speed setting (speed 9 or -9) if it's set beyond the range. extra_cfg.cpu_used = CAST(VP8E_SET_CPUUSED, args); - extra_cfg.cpu_used = VPXMIN(9, extra_cfg.cpu_used); - extra_cfg.cpu_used = VPXMAX(-9, extra_cfg.cpu_used); + extra_cfg.cpu_used = clamp(extra_cfg.cpu_used, -9, 9); #if CONFIG_REALTIME_ONLY if (extra_cfg.cpu_used > -5 && extra_cfg.cpu_used < 5) extra_cfg.cpu_used = (extra_cfg.cpu_used > 0) ? 5 : -5; #endif return update_extra_cfg(ctx, &extra_cfg); @@ -1420,12 +1419,23 @@ if (res == VPX_CODEC_OK) { unsigned int lib_flags = 0; size_t size, cx_data_sz; unsigned char *cx_data; + // Per-frame PSNR is not supported when g_lag_in_frames is greater than 0. + if ((flags & VPX_EFLAG_CALCULATE_PSNR) && ctx->cfg.g_lag_in_frames != 0) { + vpx_internal_error( + &ctx->cpi->common.error, VPX_CODEC_INCAPABLE, + "Cannot calculate per-frame PSNR when g_lag_in_frames is nonzero"); + } // Set up internal flags - if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) cpi->b_calculate_psnr = 1; +#if CONFIG_INTERNAL_STATS + assert(cpi->b_calculate_psnr == 1); +#else + cpi->b_calculate_psnr = (ctx->base.init_flags & VPX_CODEC_USE_PSNR) || + (flags & VPX_EFLAG_CALCULATE_PSNR); +#endif if (img != NULL) { YV12_BUFFER_CONFIG sd; if (!ctx->pts_offset_initialized) { @@ -1466,26 +1476,17 @@ } const int64_t dst_end_time_stamp = timebase_units_to_ticks(timebase_in_ts, pts_end); res = image2yuvconfig(img, &sd); - if (sd.y_width != ctx->cfg.g_w || sd.y_height != ctx->cfg.g_h) { - /* from vpx_encoder.h for g_w/g_h: - "Note that the frames passed as input to the encoder must have this - resolution" - */ - ctx->base.err_detail = "Invalid input frame resolution"; - res = VPX_CODEC_INVALID_PARAM; - } else { - // Store the original flags in to the frame buffer. Will extract the - // key frame flag when we actually encode this frame. - if (vp9_receive_raw_frame(cpi, flags | ctx->next_frame_flags, &sd, + // Store the original flags in to the frame buffer. Will extract the + // key frame flag when we actually encode this frame. + if (vp9_receive_raw_frame(cpi, flags | ctx->next_frame_flags, &sd, dst_time_stamp, dst_end_time_stamp)) { - res = update_error_state(ctx, &cpi->common.error); - } - ctx->next_frame_flags = 0; + res = update_error_state(ctx, &cpi->common.error); } + ctx->next_frame_flags = 0; } cx_data = ctx->cx_data; cx_data_sz = ctx->cx_data_sz; @@ -1544,14 +1545,12 @@ while (cx_data_sz >= ctx->cx_data_sz / 2 && -1 != vp9_get_compressed_data(cpi, &lib_flags, &size, cx_data, cx_data_sz, &dst_time_stamp, &dst_end_time_stamp, !img, &encode_frame_result)) { - // Pack psnr pkt - if (size > 0 && !cpi->use_svc) { - // TODO(angiebird): Figure out while we don't need psnr pkt when - // use_svc is on + // Pack psnr pkt. + if (size > 0) { PSNR_STATS psnr; if (vp9_get_psnr(cpi, &psnr)) { vpx_codec_cx_pkt_t psnr_pkt = get_psnr_pkt(&psnr); vpx_codec_pkt_list_add(&ctx->pkt_list.head, &psnr_pkt); } @@ -1988,11 +1987,11 @@ static vpx_codec_err_t ctrl_set_delta_q_uv(vpx_codec_alg_priv_t *ctx, va_list args) { struct vp9_extracfg extra_cfg = ctx->extra_cfg; int data = va_arg(args, int); - data = VPXMIN(VPXMAX(data, -15), 15); + data = clamp(data, -15, 15); extra_cfg.delta_q_uv = data; return update_extra_cfg(ctx, &extra_cfg); } static vpx_codec_err_t ctrl_register_cx_callback(vpx_codec_alg_priv_t *ctx, @@ -2300,11 +2299,12 @@ encoder_encode, // vpx_codec_encode_fn_t encoder_get_cxdata, // vpx_codec_get_cx_data_fn_t encoder_set_config, // vpx_codec_enc_config_set_fn_t encoder_get_global_headers, // vpx_codec_get_global_headers_fn_t encoder_get_preview, // vpx_codec_get_preview_frame_fn_t - NULL // vpx_codec_enc_mr_get_mem_loc_fn_t + NULL, // vpx_codec_enc_mr_get_mem_loc_fn_t + NULL // vpx_codec_enc_mr_free_mem_loc_fn_t } }; static vpx_codec_enc_cfg_t get_enc_cfg(int frame_width, int frame_height, vpx_rational_t frame_rate, @@ -2505,11 +2505,10 @@ DUMP_STRUCT_VALUE(fp, oxcf, temporal_layering_mode); DUMP_STRUCT_VALUE(fp, oxcf, row_mt); DUMP_STRUCT_VALUE(fp, oxcf, motion_vector_unit_test); DUMP_STRUCT_VALUE(fp, oxcf, delta_q_uv); - DUMP_STRUCT_VALUE(fp, oxcf, use_simple_encode_api); } FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf) { FRAME_INFO frame_info; int dummy; diff --git a/media/libvpx/libvpx/vp9/vp9_dx_iface.c b/media/libvpx/libvpx/vp9/vp9_dx_iface.c --- a/media/libvpx/libvpx/vp9/vp9_dx_iface.c +++ b/media/libvpx/libvpx/vp9/vp9_dx_iface.c @@ -735,8 +735,9 @@ NULL, // vpx_codec_encode_fn_t NULL, // vpx_codec_get_cx_data_fn_t NULL, // vpx_codec_enc_config_set_fn_t NULL, // vpx_codec_get_global_headers_fn_t NULL, // vpx_codec_get_preview_frame_fn_t - NULL // vpx_codec_enc_mr_get_mem_loc_fn_t + NULL, // vpx_codec_enc_mr_get_mem_loc_fn_t + NULL // vpx_codec_enc_mr_free_mem_loc_fn_t } }; diff --git a/media/libvpx/libvpx/vp9/vp9cx.mk b/media/libvpx/libvpx/vp9/vp9cx.mk --- a/media/libvpx/libvpx/vp9/vp9cx.mk +++ b/media/libvpx/libvpx/vp9/vp9cx.mk @@ -127,10 +127,11 @@ VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_highbd_block_error_intrin_sse2.c VP9_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/highbd_temporal_filter_ssse3.c VP9_CX_SRCS-$(HAVE_SSE4_1) += encoder/x86/highbd_temporal_filter_sse4.c VP9_CX_SRCS-$(HAVE_AVX2) += encoder/x86/highbd_temporal_filter_avx2.c VP9_CX_SRCS-$(HAVE_NEON) += encoder/arm/neon/vp9_highbd_temporal_filter_neon.c +VP9_CX_SRCS-$(HAVE_SVE2) += encoder/arm/neon/vp9_highbd_temporal_filter_sve2.c endif VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_dct_sse2.asm VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_error_sse2.asm @@ -177,10 +178,11 @@ VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/x86/highbd_temporal_filter_avx2.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/arm/neon/vp9_temporal_filter_neon.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/arm/neon/vp9_temporal_filter_neon_dotprod.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/arm/neon/vp9_temporal_filter_neon_i8mm.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/arm/neon/vp9_highbd_temporal_filter_neon.c +VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/arm/neon/vp9_highbd_temporal_filter_sve2.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/vp9_alt_ref_aq.h VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/vp9_alt_ref_aq.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/vp9_aq_variance.c VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/vp9_aq_variance.h VP9_CX_SRCS_REMOVE-$(CONFIG_REALTIME_ONLY) += encoder/vp9_aq_360.c diff --git a/media/libvpx/libvpx/vpx/internal/vpx_codec_internal.h b/media/libvpx/libvpx/vpx/internal/vpx_codec_internal.h --- a/media/libvpx/libvpx/vpx/internal/vpx_codec_internal.h +++ b/media/libvpx/libvpx/vpx/internal/vpx_codec_internal.h @@ -267,10 +267,12 @@ vpx_codec_alg_priv_t *ctx); typedef vpx_codec_err_t (*vpx_codec_enc_mr_get_mem_loc_fn_t)( const vpx_codec_enc_cfg_t *cfg, void **mem_loc); +typedef void (*vpx_codec_enc_mr_free_mem_loc_fn_t)(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 vpx_codec_enc_config_default() @@ -316,10 +318,12 @@ get_glob_hdrs; /**< \copydoc ::vpx_codec_get_global_headers_fn_t */ vpx_codec_get_preview_frame_fn_t get_preview; /**< \copydoc ::vpx_codec_get_preview_frame_fn_t */ vpx_codec_enc_mr_get_mem_loc_fn_t mr_get_mem_loc; /**< \copydoc ::vpx_codec_enc_mr_get_mem_loc_fn_t */ + vpx_codec_enc_mr_free_mem_loc_fn_t + mr_free_mem_loc; /**< \copydoc ::vpx_codec_enc_mr_free_mem_loc_fn_t */ } enc; }; /*!\brief Callback function pointer / user data pair storage */ typedef struct vpx_codec_priv_cb_pair { diff --git a/media/libvpx/libvpx/vpx/src/vpx_encoder.c b/media/libvpx/libvpx/vpx/src/vpx_encoder.c --- a/media/libvpx/libvpx/vpx/src/vpx_encoder.c +++ b/media/libvpx/libvpx/vpx/src/vpx_encoder.c @@ -13,14 +13,13 @@ * */ #include #include #include -#include #include -#include "vp8/common/blockd.h" #include "vpx_config.h" +#include "vpx/vpx_encoder.h" #include "vpx/internal/vpx_codec_internal.h" #define SAVE_STATUS(ctx, var) ((ctx) ? ((ctx)->err = (var)) : (var)) static vpx_codec_alg_priv_t *get_alg_priv(vpx_codec_ctx_t *ctx) { @@ -66,17 +65,18 @@ return SAVE_STATUS(ctx, res); } vpx_codec_err_t vpx_codec_enc_init_multi_ver( - vpx_codec_ctx_t *ctx, vpx_codec_iface_t *iface, vpx_codec_enc_cfg_t *cfg, - int num_enc, vpx_codec_flags_t flags, vpx_rational_t *dsf, int ver) { + vpx_codec_ctx_t *ctx, vpx_codec_iface_t *iface, + const vpx_codec_enc_cfg_t *cfg, int num_enc, vpx_codec_flags_t flags, + const vpx_rational_t *dsf, int ver) { vpx_codec_err_t res = VPX_CODEC_OK; if (ver != VPX_ENCODER_ABI_VERSION) res = VPX_CODEC_ABI_MISMATCH; - else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1)) + else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1) || !dsf) res = VPX_CODEC_INVALID_PARAM; else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) res = VPX_CODEC_ABI_MISMATCH; else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) res = VPX_CODEC_INCAPABLE; @@ -88,11 +88,11 @@ else { int i; #if CONFIG_MULTI_RES_ENCODING int mem_loc_owned = 0; #endif - void *mem_loc = NULL; + void *mem_loc; if (iface->enc.mr_get_mem_loc == NULL) return VPX_CODEC_INCAPABLE; if (!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) { for (i = 0; i < num_enc; i++) { @@ -104,18 +104,20 @@ res = VPX_CODEC_INVALID_PARAM; } else { 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; + mr_cfg.mr_down_sampling_factor = *dsf; ctx->iface = iface; ctx->name = iface->name; ctx->priv = NULL; ctx->init_flags = flags; ctx->config.enc = cfg; + // ctx takes ownership of mr_cfg.mr_low_res_mode_info if and only if + // this call succeeds. The first ctx entry in the array is + // responsible for freeing the memory. res = ctx->iface->init(ctx, &mr_cfg); } if (res) { const char *error_detail = ctx->priv ? ctx->priv->err_detail : NULL; @@ -131,12 +133,11 @@ i--; } #if CONFIG_MULTI_RES_ENCODING if (!mem_loc_owned) { assert(mem_loc); - free(((LOWER_RES_FRAME_INFO *)mem_loc)->mb_info); - free(mem_loc); + iface->enc.mr_free_mem_loc(mem_loc); } #endif return SAVE_STATUS(ctx, res); } #if CONFIG_MULTI_RES_ENCODING diff --git a/media/libvpx/libvpx/vpx/vp8cx.h b/media/libvpx/libvpx/vpx/vp8cx.h --- a/media/libvpx/libvpx/vpx/vp8cx.h +++ b/media/libvpx/libvpx/vpx/vp8cx.h @@ -671,11 +671,11 @@ * improve the compression performance. To enable, set this parameter to be * 1. The default value is set to be 1. */ VP9E_SET_TPL, - /*!\brief Codec control function to enable postencode frame drop. + /*!\brief Codec control function to enable post encode frame drop. * * This will allow encoder to drop frame after it's encoded. * * 0: Off (default), 1: Enabled * @@ -875,11 +875,11 @@ VP8_TWO_TOKENPARTITION = 1, VP8_FOUR_TOKENPARTITION = 2, VP8_EIGHT_TOKENPARTITION = 3 } vp8e_token_partitions; -/*!brief VP9 encoder content type */ +/*!\brief VP9 encoder content type */ typedef enum { VP9E_CONTENT_DEFAULT, VP9E_CONTENT_SCREEN, VP9E_CONTENT_FILM, VP9E_CONTENT_INVALID diff --git a/media/libvpx/libvpx/vpx/vpx_decoder.h b/media/libvpx/libvpx/vpx/vpx_decoder.h --- a/media/libvpx/libvpx/vpx/vpx_decoder.h +++ b/media/libvpx/libvpx/vpx/vpx_decoder.h @@ -58,11 +58,11 @@ #define VPX_CODEC_CAP_ERROR_CONCEALMENT 0x80000 /*!\brief Can receive encoded frames one fragment at a time */ #define VPX_CODEC_CAP_INPUT_FRAGMENTS 0x100000 /*!\brief Can support frame-based multi-threading */ #define VPX_CODEC_CAP_FRAME_THREADING 0x200000 -/*!brief Can support external frame buffers */ +/*!\brief Can support external frame buffers */ #define VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER 0x400000 /*! \brief Initialization-time Feature Enabling * * Certain codec features must be known at initialization time, to allow for diff --git a/media/libvpx/libvpx/vpx/vpx_encoder.h b/media/libvpx/libvpx/vpx/vpx_encoder.h --- a/media/libvpx/libvpx/vpx/vpx_encoder.h +++ b/media/libvpx/libvpx/vpx/vpx_encoder.h @@ -191,10 +191,11 @@ vpx_fixed_buf_t firstpass_mb_stats; /**< first pass mb packet */ struct vpx_psnr_pkt { unsigned int samples[4]; /**< Number of samples, total/y/u/v */ uint64_t sse[4]; /**< sum squared error, total/y/u/v */ double psnr[4]; /**< PSNR, total/y/u/v */ + int spatial_layer_id; /**< Spatial layer id */ } psnr; /**< data for PSNR packet */ vpx_fixed_buf_t raw; /**< data for arbitrary packets */ /* This packet size is fixed to allow codecs to extend this * interface without having to manage storage for raw packets, @@ -264,10 +265,12 @@ * named VPX_EFLAG_*, and bits specific to an algorithm will be named * /algo/_eflag_*. The lower order 16 bits are reserved for common use. */ typedef long vpx_enc_frame_flags_t; #define VPX_EFLAG_FORCE_KF (1 << 0) /**< Force this frame to be a keyframe */ +/** Calculate PSNR on this frame, requires g_lag_in_frames to be 0 */ +#define VPX_EFLAG_CALCULATE_PSNR (1 << 1) /*!\brief Encoder configuration structure * * This structure contains the encoder settings that have common representations * across all codecs. This doesn't imply that all codecs support all features, @@ -877,11 +880,11 @@ * If vpx_codec_enc_init_ver() fails, it is not necessary to call * vpx_codec_destroy() on the encoder context. * * \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. May be NULL. + * \param[in] cfg Configuration to use. * \param[in] flags Bitfield of VPX_CODEC_USE_* flags * \param[in] ver ABI version number. Must be set to * VPX_ENCODER_ABI_VERSION * \retval #VPX_CODEC_OK * The decoder algorithm initialized. @@ -900,31 +903,36 @@ #define vpx_codec_enc_init(ctx, iface, cfg, flags) \ vpx_codec_enc_init_ver(ctx, iface, cfg, flags, VPX_ENCODER_ABI_VERSION) /*!\brief Initialize multi-encoder instance * - * Initializes multi-encoder context using the given interface. + * Initializes multiple encoder contexts using the given interface. * Applications should call the vpx_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] ctx Pointer to an array of num_enc instances' contexts. * \param[in] iface Pointer to the algorithm interface to use. - * \param[in] cfg Configuration to use, if known. May be NULL. + * \param[in] cfg An array of num_enc configurations to use. * \param[in] num_enc Total number of encoders. * \param[in] flags Bitfield of VPX_CODEC_USE_* flags - * \param[in] dsf Pointer to down-sampling factors. + * \param[in] dsf Pointer to an array of num_enc down-sampling factors. * \param[in] ver ABI version number. Must be set to * VPX_ENCODER_ABI_VERSION * \retval #VPX_CODEC_OK * The encoder algorithm has been initialized. * \retval #VPX_CODEC_MEM_ERROR * Memory allocation failed. + * + * \note + * This is only supported by VP8. iface must point to the interface to the VP8 + * encoder. */ vpx_codec_err_t vpx_codec_enc_init_multi_ver( - vpx_codec_ctx_t *ctx, vpx_codec_iface_t *iface, vpx_codec_enc_cfg_t *cfg, - int num_enc, vpx_codec_flags_t flags, vpx_rational_t *dsf, int ver); + vpx_codec_ctx_t *ctx, vpx_codec_iface_t *iface, + const vpx_codec_enc_cfg_t *cfg, int num_enc, vpx_codec_flags_t flags, + const vpx_rational_t *dsf, int ver); /*!\brief Convenience macro for vpx_codec_enc_init_multi_ver() * * Ensures the ABI version parameter is properly set. */ diff --git a/media/libvpx/libvpx/vpx/vpx_ext_ratectrl.h b/media/libvpx/libvpx/vpx/vpx_ext_ratectrl.h --- a/media/libvpx/libvpx/vpx/vpx_ext_ratectrl.h +++ b/media/libvpx/libvpx/vpx/vpx_ext_ratectrl.h @@ -131,11 +131,11 @@ * system. */ #define VPX_DEFAULT_RDMULT -1 /*!\brief Superblock quantization parameters - * Store the superblock quantiztaion parameters + * Store the superblock quantization parameters */ typedef struct sb_parameters { int q_index; /**< Quantizer step index [0..255]*/ int rdmult; /**< Superblock level Lagrangian multiplier*/ } sb_params; diff --git a/media/libvpx/libvpx/vpx/vpx_image.h b/media/libvpx/libvpx/vpx/vpx_image.h --- a/media/libvpx/libvpx/vpx/vpx_image.h +++ b/media/libvpx/libvpx/vpx/vpx_image.h @@ -128,11 +128,11 @@ } vpx_image_rect_t; /**< alias for struct vpx_image_rect */ /*!\brief Open a descriptor, allocating storage for the underlying image * * Returns a descriptor for storing an image of the given format. The - * storage for the descriptor is allocated on the heap. + * storage for the image is allocated on the heap. * * \param[in] img Pointer to storage for descriptor. If this parameter * is NULL, the storage for the descriptor will be * allocated on the heap. * \param[in] fmt Format for the image @@ -153,11 +153,11 @@ unsigned int align); /*!\brief Open a descriptor, using existing storage for the underlying image * * Returns a descriptor for storing an image of the given format. The - * storage for descriptor has been allocated elsewhere, and a descriptor is + * storage for the image has been allocated elsewhere, and a descriptor is * desired to "wrap" that storage. * * \param[in] img Pointer to storage for descriptor. If this * parameter is NULL, the storage for the descriptor * will be allocated on the heap. @@ -173,10 +173,39 @@ * disposed of after calling vpx_img_free(). * * \return Returns a pointer to the initialized image descriptor. If the img * parameter is non-null, the value of the img parameter will be * returned. + * + * \note \a img_data is required to have a minimum allocation size that + * satisfies the requirements of the \a fmt, \a d_w, \a d_h and \a + * stride_align parameters. This size can be calculated as follows (see + * \c img_alloc_helper in the vpx_image.c file in the libvpx source tree + * for more detail): + * \code + * align = (1 << x_chroma_shift) - 1; + * w = (d_w + align) & ~align; + * align = (1 << y_chroma_shift) - 1; + * h = (d_h + align) & ~align; + * + * s = (fmt & VPX_IMG_FMT_PLANAR) ? w : (uint64_t)bps * w / 8; + * s = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s; + * s = (s + stride_align - 1) & ~((uint64_t)stride_align - 1); + * s = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s / 2 : s; + * alloc_size = (fmt & VPX_IMG_FMT_PLANAR) ? (uint64_t)h * s * bps / 8 + * : (uint64_t)h * s; + * \endcode + * \a x_chroma_shift, \a y_chroma_shift and \a bps can be obtained by calling + * \ref vpx_img_wrap with a non-\c NULL \a img_data parameter. The \c + * vpx_image_t pointer should \em not be used in other API calls until \em after + * a successful call to \ref vpx_img_wrap with a valid image buffer. For + * example: + * \code + * vpx_img_wrap(img, fmt, d_w, d_h, stride_align, (unsigned char *)1); + * ... calculate buffer size and allocate buffer as described earlier + * vpx_img_wrap(img, fmt, d_w, d_h, stride_align, img_data); + * \endcode */ vpx_image_t *vpx_img_wrap(vpx_image_t *img, vpx_img_fmt_t fmt, unsigned int d_w, unsigned int d_h, unsigned int stride_align, unsigned char *img_data); diff --git a/media/libvpx/libvpx/vpx_dsp/arm/highbd_sad_neon.c b/media/libvpx/libvpx/vpx_dsp/arm/highbd_sad_neon.c --- a/media/libvpx/libvpx/vpx_dsp/arm/highbd_sad_neon.c +++ b/media/libvpx/libvpx/vpx_dsp/arm/highbd_sad_neon.c @@ -7,10 +7,11 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include +#include #include "./vpx_config.h" #include "./vpx_dsp_rtcd.h" #include "vpx/vpx_integer.h" @@ -23,19 +24,18 @@ int ref_stride, int h) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); uint32x4_t sum = vdupq_n_u32(0); - int i = h; do { uint16x4_t s = vld1_u16(src16_ptr); uint16x4_t r = vld1_u16(ref16_ptr); sum = vabal_u16(sum, s, r); src16_ptr += src_stride; ref16_ptr += ref_stride; - } while (--i != 0); + } while (--h != 0); return horizontal_add_uint32x4(sum); } static INLINE uint32_t highbd_sad8xh_neon(const uint8_t *src_ptr, @@ -43,117 +43,138 @@ const uint8_t *ref_ptr, int ref_stride, int h) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); uint16x8_t sum = vdupq_n_u16(0); + assert(h <= 16); - int i = h; do { uint16x8_t s = vld1q_u16(src16_ptr); uint16x8_t r = vld1q_u16(ref16_ptr); sum = vabaq_u16(sum, s, r); src16_ptr += src_stride; ref16_ptr += ref_stride; - } while (--i != 0); + } while (--h != 0); return horizontal_add_uint16x8(sum); } static INLINE uint32_t highbd_sad16xh_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, int h) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); - uint32x4_t sum[2] = { vdupq_n_u32(0), vdupq_n_u32(0) }; + uint32x4_t sum_u32 = vdupq_n_u32(0); - int i = h; + // 'h_overflow' is the number of 16-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 16 16-wide rows using two accumulators. + const int h_overflow = 16; + // If block height 'h' is smaller than this limit, use 'h' instead. + const int h_limit = h < h_overflow ? h : h_overflow; + assert(h % h_limit == 0); + do { - uint16x8_t s0, s1, r0, r1; - uint16x8_t diff0, diff1; - - s0 = vld1q_u16(src16_ptr); - r0 = vld1q_u16(ref16_ptr); - diff0 = vabdq_u16(s0, r0); - sum[0] = vpadalq_u16(sum[0], diff0); + uint16x8_t sum_u16[2] = { vdupq_n_u16(0), vdupq_n_u16(0) }; + int i = h_limit; + do { + uint16x8_t s0, s1, r0, r1; - s1 = vld1q_u16(src16_ptr + 8); - r1 = vld1q_u16(ref16_ptr + 8); - diff1 = vabdq_u16(s1, r1); - sum[1] = vpadalq_u16(sum[1], diff1); + s0 = vld1q_u16(src16_ptr); + r0 = vld1q_u16(ref16_ptr); + sum_u16[0] = vabaq_u16(sum_u16[0], s0, r0); + + s1 = vld1q_u16(src16_ptr + 8); + r1 = vld1q_u16(ref16_ptr + 8); + sum_u16[1] = vabaq_u16(sum_u16[1], s1, r1); - src16_ptr += src_stride; - ref16_ptr += ref_stride; - } while (--i != 0); + src16_ptr += src_stride; + ref16_ptr += ref_stride; + } while (--i != 0); - sum[0] = vaddq_u32(sum[0], sum[1]); - return horizontal_add_uint32x4(sum[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[1]); + h -= h_limit; + } while (h != 0); + return horizontal_add_uint32x4(sum_u32); } static INLINE uint32_t highbd_sadwxh_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, - int ref_stride, int w, int h) { + int ref_stride, int w, int h, + const int h_overflow) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); - uint32x4_t sum[4] = { vdupq_n_u32(0), vdupq_n_u32(0), vdupq_n_u32(0), - vdupq_n_u32(0) }; - - int i = h; - do { - int j = 0; - do { - uint16x8_t s0, s1, s2, s3, r0, r1, r2, r3; - uint16x8_t diff0, diff1, diff2, diff3; + uint32x4_t sum_u32 = vdupq_n_u32(0); + const int h_limit = h < h_overflow ? h : h_overflow; + assert(h % h_limit == 0); - s0 = vld1q_u16(src16_ptr + j); - r0 = vld1q_u16(ref16_ptr + j); - diff0 = vabdq_u16(s0, r0); - sum[0] = vpadalq_u16(sum[0], diff0); + do { + uint16x8_t sum_u16[4] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0), + vdupq_n_u16(0) }; + int i = 0; + do { + int j = 0; + do { + uint16x8_t s0, s1, s2, s3, r0, r1, r2, r3; - s1 = vld1q_u16(src16_ptr + j + 8); - r1 = vld1q_u16(ref16_ptr + j + 8); - diff1 = vabdq_u16(s1, r1); - sum[1] = vpadalq_u16(sum[1], diff1); + s0 = vld1q_u16(src16_ptr + j); + r0 = vld1q_u16(ref16_ptr + j); + sum_u16[0] = vabaq_u16(sum_u16[0], s0, r0); + + s1 = vld1q_u16(src16_ptr + j + 8); + r1 = vld1q_u16(ref16_ptr + j + 8); + sum_u16[1] = vabaq_u16(sum_u16[1], s1, r1); - s2 = vld1q_u16(src16_ptr + j + 16); - r2 = vld1q_u16(ref16_ptr + j + 16); - diff2 = vabdq_u16(s2, r2); - sum[2] = vpadalq_u16(sum[2], diff2); + s2 = vld1q_u16(src16_ptr + j + 16); + r2 = vld1q_u16(ref16_ptr + j + 16); + sum_u16[2] = vabaq_u16(sum_u16[2], s2, r2); - s3 = vld1q_u16(src16_ptr + j + 24); - r3 = vld1q_u16(ref16_ptr + j + 24); - diff3 = vabdq_u16(s3, r3); - sum[3] = vpadalq_u16(sum[3], diff3); + s3 = vld1q_u16(src16_ptr + j + 24); + r3 = vld1q_u16(ref16_ptr + j + 24); + sum_u16[3] = vabaq_u16(sum_u16[3], s3, r3); - j += 32; - } while (j < w); + j += 32; + } while (j < w); + src16_ptr += src_stride; + ref16_ptr += ref_stride; + } while (++i != h_limit); - src16_ptr += src_stride; - ref16_ptr += ref_stride; - } while (--i != 0); - - sum[0] = vaddq_u32(sum[0], sum[1]); - sum[2] = vaddq_u32(sum[2], sum[3]); - sum[0] = vaddq_u32(sum[0], sum[2]); - - return horizontal_add_uint32x4(sum[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[1]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[2]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[3]); + h -= h_limit; + } while (h != 0); + return horizontal_add_uint32x4(sum_u32); } -static INLINE unsigned int highbd_sad64xh_neon(const uint8_t *src_ptr, - int src_stride, - const uint8_t *ref_ptr, - int ref_stride, int h) { - return highbd_sadwxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 64, h); +static INLINE uint32_t highbd_sad32xh_neon(const uint8_t *src_ptr, + int src_stride, + const uint8_t *ref_ptr, + int ref_stride, int h) { + // 'h_overflow' is the number of 32-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 16 32-wide rows using four accumulators. + const int h_overflow = 16; + return highbd_sadwxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 32, h, + h_overflow); } -static INLINE unsigned int highbd_sad32xh_neon(const uint8_t *src_ptr, - int src_stride, - const uint8_t *ref_ptr, - int ref_stride, int h) { - return highbd_sadwxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 32, h); +static INLINE uint32_t highbd_sad64xh_neon(const uint8_t *src_ptr, + int src_stride, + const uint8_t *ref_ptr, + int ref_stride, int h) { + // 'h_overflow' is the number of 64-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 8 64-wide rows using four accumulators. + const int h_overflow = 8; + return highbd_sadwxh_neon(src_ptr, src_stride, ref_ptr, ref_stride, 64, h, + h_overflow); } #define HBD_SAD_WXH_NEON(w, h) \ unsigned int vpx_highbd_sad##w##x##h##_neon( \ const uint8_t *src, int src_stride, const uint8_t *ref, \ @@ -217,11 +238,10 @@ const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); const uint16_t *pred16_ptr = CONVERT_TO_SHORTPTR(second_pred); uint32x4_t sum = vdupq_n_u32(0); - int i = h; do { uint16x4_t s = vld1_u16(src16_ptr); uint16x4_t r = vld1_u16(ref16_ptr); uint16x4_t p = vld1_u16(pred16_ptr); @@ -229,11 +249,11 @@ sum = vabal_u16(sum, s, avg); src16_ptr += src_stride; ref16_ptr += ref_stride; pred16_ptr += 4; - } while (--i != 0); + } while (--h != 0); return horizontal_add_uint32x4(sum); } static INLINE uint32_t highbd_sad8xh_avg_neon(const uint8_t *src_ptr, @@ -242,149 +262,171 @@ int ref_stride, int h, const uint8_t *second_pred) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); const uint16_t *pred16_ptr = CONVERT_TO_SHORTPTR(second_pred); - uint32x4_t sum = vdupq_n_u32(0); + uint16x8_t sum = vdupq_n_u16(0); + assert(h <= 16); - int i = h; do { uint16x8_t s = vld1q_u16(src16_ptr); uint16x8_t r = vld1q_u16(ref16_ptr); uint16x8_t p = vld1q_u16(pred16_ptr); uint16x8_t avg = vrhaddq_u16(r, p); - uint16x8_t diff = vabdq_u16(s, avg); - sum = vpadalq_u16(sum, diff); + sum = vabaq_u16(sum, s, avg); src16_ptr += src_stride; ref16_ptr += ref_stride; pred16_ptr += 8; - } while (--i != 0); + } while (--h != 0); - return horizontal_add_uint32x4(sum); + return horizontal_add_uint16x8(sum); } static INLINE uint32_t highbd_sad16xh_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, int h, const uint8_t *second_pred) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); const uint16_t *pred16_ptr = CONVERT_TO_SHORTPTR(second_pred); - uint32x4_t sum[2] = { vdupq_n_u32(0), vdupq_n_u32(0) }; - - int i = h; - do { - uint16x8_t s0, s1, r0, r1, p0, p1; - uint16x8_t avg0, avg1, diff0, diff1; + uint32x4_t sum_u32 = vdupq_n_u32(0); - s0 = vld1q_u16(src16_ptr); - r0 = vld1q_u16(ref16_ptr); - p0 = vld1q_u16(pred16_ptr); - avg0 = vrhaddq_u16(r0, p0); - diff0 = vabdq_u16(s0, avg0); - sum[0] = vpadalq_u16(sum[0], diff0); + // 'h_overflow' is the number of 16-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 16 16-wide rows using two accumulators. + const int h_overflow = 16; + // If block height 'h' is smaller than this limit, use 'h' instead. + const int h_limit = h < h_overflow ? h : h_overflow; + assert(h % h_limit == 0); + + do { + uint16x8_t sum_u16[2] = { vdupq_n_u16(0), vdupq_n_u16(0) }; + int i = h_limit; + do { + uint16x8_t s0, s1, r0, r1, p0, p1; + uint16x8_t avg0, avg1; - s1 = vld1q_u16(src16_ptr + 8); - r1 = vld1q_u16(ref16_ptr + 8); - p1 = vld1q_u16(pred16_ptr + 8); - avg1 = vrhaddq_u16(r1, p1); - diff1 = vabdq_u16(s1, avg1); - sum[1] = vpadalq_u16(sum[1], diff1); + s0 = vld1q_u16(src16_ptr); + r0 = vld1q_u16(ref16_ptr); + p0 = vld1q_u16(pred16_ptr); + avg0 = vrhaddq_u16(r0, p0); + sum_u16[0] = vabaq_u16(sum_u16[0], s0, avg0); - src16_ptr += src_stride; - ref16_ptr += ref_stride; - pred16_ptr += 16; - } while (--i != 0); + s1 = vld1q_u16(src16_ptr + 8); + r1 = vld1q_u16(ref16_ptr + 8); + p1 = vld1q_u16(pred16_ptr + 8); + avg1 = vrhaddq_u16(r1, p1); + sum_u16[1] = vabaq_u16(sum_u16[1], s1, avg1); - sum[0] = vaddq_u32(sum[0], sum[1]); - return horizontal_add_uint32x4(sum[0]); + src16_ptr += src_stride; + ref16_ptr += ref_stride; + pred16_ptr += 16; + } while (--i != 0); + + sum_u32 = vpadalq_u16(sum_u32, sum_u16[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[1]); + h -= h_limit; + } while (h != 0); + return horizontal_add_uint32x4(sum_u32); } static INLINE uint32_t highbd_sadwxh_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, int w, int h, - const uint8_t *second_pred) { + const uint8_t *second_pred, + const int h_overflow) { const uint16_t *src16_ptr = CONVERT_TO_SHORTPTR(src_ptr); const uint16_t *ref16_ptr = CONVERT_TO_SHORTPTR(ref_ptr); const uint16_t *pred16_ptr = CONVERT_TO_SHORTPTR(second_pred); - uint32x4_t sum[4] = { vdupq_n_u32(0), vdupq_n_u32(0), vdupq_n_u32(0), - vdupq_n_u32(0) }; + uint32x4_t sum_u32 = vdupq_n_u32(0); + const int h_limit = h < h_overflow ? h : h_overflow; + assert(h % h_limit == 0); - int i = h; do { - int j = 0; - do { - uint16x8_t s0, s1, s2, s3, r0, r1, r2, r3, p0, p1, p2, p3; - uint16x8_t avg0, avg1, avg2, avg3, diff0, diff1, diff2, diff3; + uint16x8_t sum_u16[4] = { vdupq_n_u16(0), vdupq_n_u16(0), vdupq_n_u16(0), + vdupq_n_u16(0) }; - s0 = vld1q_u16(src16_ptr + j); - r0 = vld1q_u16(ref16_ptr + j); - p0 = vld1q_u16(pred16_ptr + j); - avg0 = vrhaddq_u16(r0, p0); - diff0 = vabdq_u16(s0, avg0); - sum[0] = vpadalq_u16(sum[0], diff0); + int i = h_limit; + do { + int j = 0; + do { + uint16x8_t s0, s1, s2, s3, r0, r1, r2, r3, p0, p1, p2, p3; + uint16x8_t avg0, avg1, avg2, avg3; - s1 = vld1q_u16(src16_ptr + j + 8); - r1 = vld1q_u16(ref16_ptr + j + 8); - p1 = vld1q_u16(pred16_ptr + j + 8); - avg1 = vrhaddq_u16(r1, p1); - diff1 = vabdq_u16(s1, avg1); - sum[1] = vpadalq_u16(sum[1], diff1); + s0 = vld1q_u16(src16_ptr + j); + r0 = vld1q_u16(ref16_ptr + j); + p0 = vld1q_u16(pred16_ptr + j); + avg0 = vrhaddq_u16(r0, p0); + sum_u16[0] = vabaq_u16(sum_u16[0], s0, avg0); + + s1 = vld1q_u16(src16_ptr + j + 8); + r1 = vld1q_u16(ref16_ptr + j + 8); + p1 = vld1q_u16(pred16_ptr + j + 8); + avg1 = vrhaddq_u16(r1, p1); + sum_u16[1] = vabaq_u16(sum_u16[1], s1, avg1); - s2 = vld1q_u16(src16_ptr + j + 16); - r2 = vld1q_u16(ref16_ptr + j + 16); - p2 = vld1q_u16(pred16_ptr + j + 16); - avg2 = vrhaddq_u16(r2, p2); - diff2 = vabdq_u16(s2, avg2); - sum[2] = vpadalq_u16(sum[2], diff2); + s2 = vld1q_u16(src16_ptr + j + 16); + r2 = vld1q_u16(ref16_ptr + j + 16); + p2 = vld1q_u16(pred16_ptr + j + 16); + avg2 = vrhaddq_u16(r2, p2); + sum_u16[2] = vabaq_u16(sum_u16[2], s2, avg2); - s3 = vld1q_u16(src16_ptr + j + 24); - r3 = vld1q_u16(ref16_ptr + j + 24); - p3 = vld1q_u16(pred16_ptr + j + 24); - avg3 = vrhaddq_u16(r3, p3); - diff3 = vabdq_u16(s3, avg3); - sum[3] = vpadalq_u16(sum[3], diff3); + s3 = vld1q_u16(src16_ptr + j + 24); + r3 = vld1q_u16(ref16_ptr + j + 24); + p3 = vld1q_u16(pred16_ptr + j + 24); + avg3 = vrhaddq_u16(r3, p3); + sum_u16[3] = vabaq_u16(sum_u16[3], s3, avg3); - j += 32; - } while (j < w); + j += 32; + } while (j < w); + + src16_ptr += src_stride; + ref16_ptr += ref_stride; + pred16_ptr += w; + } while (--i != 0); - src16_ptr += src_stride; - ref16_ptr += ref_stride; - pred16_ptr += w; - } while (--i != 0); - - sum[0] = vaddq_u32(sum[0], sum[1]); - sum[2] = vaddq_u32(sum[2], sum[3]); - sum[0] = vaddq_u32(sum[0], sum[2]); - - return horizontal_add_uint32x4(sum[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[0]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[1]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[2]); + sum_u32 = vpadalq_u16(sum_u32, sum_u16[3]); + h -= h_limit; + } while (h != 0); + return horizontal_add_uint32x4(sum_u32); } -static INLINE unsigned int highbd_sad64xh_avg_neon(const uint8_t *src_ptr, - int src_stride, - const uint8_t *ref_ptr, - int ref_stride, int h, - const uint8_t *second_pred) { - return highbd_sadwxh_avg_neon(src_ptr, src_stride, ref_ptr, ref_stride, 64, h, - second_pred); +static INLINE uint32_t highbd_sad32xh_avg_neon(const uint8_t *src_ptr, + int src_stride, + const uint8_t *ref_ptr, + int ref_stride, int h, + const uint8_t *second_pred) { + // 'h_overflow' is the number of 32-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 16 32-wide rows using four accumulators. + const int h_overflow = 16; + return highbd_sadwxh_avg_neon(src_ptr, src_stride, ref_ptr, ref_stride, 32, h, + second_pred, h_overflow); } -static INLINE unsigned int highbd_sad32xh_avg_neon(const uint8_t *src_ptr, - int src_stride, - const uint8_t *ref_ptr, - int ref_stride, int h, - const uint8_t *second_pred) { - return highbd_sadwxh_avg_neon(src_ptr, src_stride, ref_ptr, ref_stride, 32, h, - second_pred); +static INLINE uint32_t highbd_sad64xh_avg_neon(const uint8_t *src_ptr, + int src_stride, + const uint8_t *ref_ptr, + int ref_stride, int h, + const uint8_t *second_pred) { + // 'h_overflow' is the number of 64-wide rows we can process before 16-bit + // accumulators overflow. After hitting this limit accumulate into 32-bit + // elements. 65535 / 4095 ~= 16, so 8 64-wide rows using four accumulators. + const int h_overflow = 8; + return highbd_sadwxh_avg_neon(src_ptr, src_stride, ref_ptr, ref_stride, 64, h, + second_pred, h_overflow); } #define HBD_SAD_WXH_AVG_NEON(w, h) \ - uint32_t vpx_highbd_sad##w##x##h##_avg_neon( \ + unsigned int vpx_highbd_sad##w##x##h##_avg_neon( \ const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \ const uint8_t *second_pred) { \ return highbd_sad##w##xh_avg_neon(src, src_stride, ref, ref_stride, (h), \ second_pred); \ } @@ -404,5 +446,7 @@ HBD_SAD_WXH_AVG_NEON(32, 32) HBD_SAD_WXH_AVG_NEON(32, 64) HBD_SAD_WXH_AVG_NEON(64, 32) HBD_SAD_WXH_AVG_NEON(64, 64) + +#undef HBD_SAD_WXH_AVG_NEON diff --git a/media/libvpx/libvpx/vpx_dsp/arm/highbd_vpx_convolve8_sve2.c b/media/libvpx/libvpx/vpx_dsp/arm/highbd_vpx_convolve8_sve2.c --- a/media/libvpx/libvpx/vpx_dsp/arm/highbd_vpx_convolve8_sve2.c +++ b/media/libvpx/libvpx/vpx_dsp/arm/highbd_vpx_convolve8_sve2.c @@ -34,76 +34,10 @@ // clang-format on DECLARE_ALIGNED(16, static const uint16_t, kTblConv4_8[8]) = { 0, 2, 4, 6, 1, 3, 5, 7 }; -static INLINE void transpose_concat_4x4(const int16x4_t s0, const int16x4_t s1, - const int16x4_t s2, const int16x4_t s3, - int16x8_t res[2]) { - // Transpose 16-bit elements: - // s0: 00, 01, 02, 03 - // s1: 10, 11, 12, 13 - // s2: 20, 21, 22, 23 - // s3: 30, 31, 32, 33 - // - // res[0]: 00 10 20 30 01 11 21 31 - // res[1]: 02 12 22 32 03 13 23 33 - - int16x8_t s0q = vcombine_s16(s0, vdup_n_s16(0)); - int16x8_t s1q = vcombine_s16(s1, vdup_n_s16(0)); - int16x8_t s2q = vcombine_s16(s2, vdup_n_s16(0)); - int16x8_t s3q = vcombine_s16(s3, vdup_n_s16(0)); - - int16x8_t s02 = vzip1q_s16(s0q, s2q); - int16x8_t s13 = vzip1q_s16(s1q, s3q); - - int16x8x2_t s0123 = vzipq_s16(s02, s13); - - res[0] = s0123.val[0]; - res[1] = s0123.val[1]; -} - -static INLINE void transpose_concat_8x4(const int16x8_t s0, const int16x8_t s1, - const int16x8_t s2, const int16x8_t s3, - int16x8_t res[4]) { - // Transpose 16-bit elements: - // s0: 00, 01, 02, 03, 04, 05, 06, 07 - // s1: 10, 11, 12, 13, 14, 15, 16, 17 - // s2: 20, 21, 22, 23, 24, 25, 26, 27 - // s3: 30, 31, 32, 33, 34, 35, 36, 37 - // - // res[0]: 00 10 20 30 01 11 21 31 - // res[1]: 02 12 22 32 03 13 23 33 - // res[2]: 04 14 24 34 05 15 25 35 - // res[3]: 06 16 26 36 07 17 27 37 - - int16x8x2_t s02 = vzipq_s16(s0, s2); - int16x8x2_t s13 = vzipq_s16(s1, s3); - - int16x8x2_t s0123_lo = vzipq_s16(s02.val[0], s13.val[0]); - int16x8x2_t s0123_hi = vzipq_s16(s02.val[1], s13.val[1]); - - res[0] = s0123_lo.val[0]; - res[1] = s0123_lo.val[1]; - res[2] = s0123_hi.val[0]; - res[3] = s0123_hi.val[1]; -} - -static INLINE void vpx_tbl2x4_s16(int16x8_t s0[4], int16x8_t s1[4], - int16x8_t res[4], uint16x8_t idx) { - res[0] = vpx_tbl2_s16(s0[0], s1[0], idx); - res[1] = vpx_tbl2_s16(s0[1], s1[1], idx); - res[2] = vpx_tbl2_s16(s0[2], s1[2], idx); - res[3] = vpx_tbl2_s16(s0[3], s1[3], idx); -} - -static INLINE void vpx_tbl2x2_s16(int16x8_t s0[2], int16x8_t s1[2], - int16x8_t res[2], uint16x8_t idx) { - res[0] = vpx_tbl2_s16(s0[0], s1[0], idx); - res[1] = vpx_tbl2_s16(s0[1], s1[1], idx); -} - static INLINE uint16x4_t highbd_convolve8_4_v(int16x8_t s_lo[2], int16x8_t s_hi[2], int16x8_t filter, uint16x4_t max) { int64x2_t sum01 = vpx_dotq_lane_s16(vdupq_n_s64(0), s_lo[0], filter, 0); @@ -144,49 +78,37 @@ static INLINE void highbd_convolve8_8tap_vert_sve2( const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, ptrdiff_t dst_stride, int w, int h, const int16x8_t filter, int bd) { assert(w >= 4 && h >= 4); - uint16x8x3_t merge_tbl_idx = vld1q_u16_x3(kDotProdMergeBlockTbl); - // Correct indices by the size of vector length. - merge_tbl_idx.val[0] = vaddq_u16( - merge_tbl_idx.val[0], - vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000000000000ULL))); - merge_tbl_idx.val[1] = vaddq_u16( - merge_tbl_idx.val[1], - vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100000000ULL))); - merge_tbl_idx.val[2] = vaddq_u16( - merge_tbl_idx.val[2], - vreinterpretq_u16_u64(vdupq_n_u64(svcnth() * 0x0001000100010000ULL))); - - if (w == 4) { + do { const uint16x4_t max = vdup_n_u16((1 << bd) - 1); const int16_t *s = (const int16_t *)src; uint16_t *d = dst; + int height = h; int16x4_t s0, s1, s2, s3, s4, s5, s6; load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); s += 7 * src_stride; int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; - transpose_concat_4x4(s0, s1, s2, s3, s0123); - transpose_concat_4x4(s1, s2, s3, s4, s1234); - transpose_concat_4x4(s2, s3, s4, s5, s2345); - transpose_concat_4x4(s3, s4, s5, s6, s3456); + transpose_concat_s16_4x4(s0, s1, s2, s3, &s0123[0], &s0123[1]); + transpose_concat_s16_4x4(s1, s2, s3, s4, &s1234[0], &s1234[1]); + transpose_concat_s16_4x4(s2, s3, s4, s5, &s2345[0], &s2345[1]); + transpose_concat_s16_4x4(s3, s4, s5, s6, &s3456[0], &s3456[1]); do { int16x4_t s7, s8, s9, sA; load_s16_4x4(s, src_stride, &s7, &s8, &s9, &sA); int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; - transpose_concat_4x4(s7, s8, s9, sA, s789A); - - vpx_tbl2x2_s16(s3456, s789A, s4567, merge_tbl_idx.val[0]); - vpx_tbl2x2_s16(s3456, s789A, s5678, merge_tbl_idx.val[1]); - vpx_tbl2x2_s16(s3456, s789A, s6789, merge_tbl_idx.val[2]); + transpose_concat_s16_4x4(s4, s5, s6, s7, &s4567[0], &s4567[1]); + transpose_concat_s16_4x4(s5, s6, s7, s8, &s5678[0], &s5678[1]); + transpose_concat_s16_4x4(s6, s7, s8, s9, &s6789[0], &s6789[1]); + transpose_concat_s16_4x4(s7, s8, s9, sA, &s789A[0], &s789A[1]); uint16x4_t d0 = highbd_convolve8_4_v(s0123, s4567, filter, max); uint16x4_t d1 = highbd_convolve8_4_v(s1234, s5678, filter, max); uint16x4_t d2 = highbd_convolve8_4_v(s2345, s6789, filter, max); uint16x4_t d3 = highbd_convolve8_4_v(s3456, s789A, filter, max); @@ -200,76 +122,23 @@ s2345[0] = s6789[0]; s2345[1] = s6789[1]; s3456[0] = s789A[0]; s3456[1] = s789A[1]; + s4 = s8; + s5 = s9; + s6 = sA; + s += 4 * src_stride; d += 4 * dst_stride; - h -= 4; - } while (h != 0); - } else { - const uint16x8_t max = vdupq_n_u16((1 << bd) - 1); - - do { - const int16_t *s = (const int16_t *)src; - uint16_t *d = dst; - int height = h; - - int16x8_t s0, s1, s2, s3, s4, s5, s6; - load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); - s += 7 * src_stride; - - int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; - transpose_concat_8x4(s0, s1, s2, s3, s0123); - transpose_concat_8x4(s1, s2, s3, s4, s1234); - transpose_concat_8x4(s2, s3, s4, s5, s2345); - transpose_concat_8x4(s3, s4, s5, s6, s3456); - - do { - int16x8_t s7, s8, s9, sA; - load_s16_8x4(s, src_stride, &s7, &s8, &s9, &sA); - - int16x8_t s4567[4], s5678[5], s6789[4], s789A[4]; - transpose_concat_8x4(s7, s8, s9, sA, s789A); - - vpx_tbl2x4_s16(s3456, s789A, s4567, merge_tbl_idx.val[0]); - vpx_tbl2x4_s16(s3456, s789A, s5678, merge_tbl_idx.val[1]); - vpx_tbl2x4_s16(s3456, s789A, s6789, merge_tbl_idx.val[2]); + height -= 4; + } while (height != 0); - uint16x8_t d0 = highbd_convolve8_8_v(s0123, s4567, filter, max); - uint16x8_t d1 = highbd_convolve8_8_v(s1234, s5678, filter, max); - uint16x8_t d2 = highbd_convolve8_8_v(s2345, s6789, filter, max); - uint16x8_t d3 = highbd_convolve8_8_v(s3456, s789A, filter, max); - - store_u16_8x4(d, dst_stride, d0, d1, d2, d3); - - s0123[0] = s4567[0]; - s0123[1] = s4567[1]; - s0123[2] = s4567[2]; - s0123[3] = s4567[3]; - s1234[0] = s5678[0]; - s1234[1] = s5678[1]; - s1234[2] = s5678[2]; - s1234[3] = s5678[3]; - s2345[0] = s6789[0]; - s2345[1] = s6789[1]; - s2345[2] = s6789[2]; - s2345[3] = s6789[3]; - s3456[0] = s789A[0]; - s3456[1] = s789A[1]; - s3456[2] = s789A[2]; - s3456[3] = s789A[3]; - - s += 4 * src_stride; - d += 4 * dst_stride; - height -= 4; - } while (height != 0); - src += 8; - dst += 8; - w -= 8; - } while (w != 0); - } + src += 4; + dst += 4; + w -= 4; + } while (w != 0); } void vpx_highbd_convolve8_vert_sve2(const uint16_t *src, ptrdiff_t src_stride, uint16_t *dst, ptrdiff_t dst_stride, const InterpKernel *filter, int x0_q4, @@ -341,22 +210,22 @@ int16x4_t s0, s1, s2, s3, s4, s5, s6; load_s16_4x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); s += 7 * src_stride; int16x8_t s0123[2], s1234[2], s2345[2], s3456[2]; - transpose_concat_4x4(s0, s1, s2, s3, s0123); - transpose_concat_4x4(s1, s2, s3, s4, s1234); - transpose_concat_4x4(s2, s3, s4, s5, s2345); - transpose_concat_4x4(s3, s4, s5, s6, s3456); + transpose_concat_s16_4x4(s0, s1, s2, s3, &s0123[0], &s0123[1]); + transpose_concat_s16_4x4(s1, s2, s3, s4, &s1234[0], &s1234[1]); + transpose_concat_s16_4x4(s2, s3, s4, s5, &s2345[0], &s2345[1]); + transpose_concat_s16_4x4(s3, s4, s5, s6, &s3456[0], &s3456[1]); do { int16x4_t s7, s8, s9, sA; load_s16_4x4(s, src_stride, &s7, &s8, &s9, &sA); int16x8_t s4567[2], s5678[2], s6789[2], s789A[2]; - transpose_concat_4x4(s7, s8, s9, sA, s789A); + transpose_concat_s16_4x4(s7, s8, s9, sA, &s789A[0], &s789A[1]); vpx_tbl2x2_s16(s3456, s789A, s4567, merge_tbl_idx.val[0]); vpx_tbl2x2_s16(s3456, s789A, s5678, merge_tbl_idx.val[1]); vpx_tbl2x2_s16(s3456, s789A, s6789, merge_tbl_idx.val[2]); @@ -396,21 +265,26 @@ int16x8_t s0, s1, s2, s3, s4, s5, s6; load_s16_8x7(s, src_stride, &s0, &s1, &s2, &s3, &s4, &s5, &s6); s += 7 * src_stride; int16x8_t s0123[4], s1234[4], s2345[4], s3456[4]; - transpose_concat_8x4(s0, s1, s2, s3, s0123); - transpose_concat_8x4(s1, s2, s3, s4, s1234); - transpose_concat_8x4(s2, s3, s4, s5, s2345); - transpose_concat_8x4(s3, s4, s5, s6, s3456); + transpose_concat_s16_8x4(s0, s1, s2, s3, &s0123[0], &s0123[1], &s0123[2], + &s0123[3]); + transpose_concat_s16_8x4(s1, s2, s3, s4, &s1234[0], &s1234[1], &s1234[2], + &s1234[3]); + transpose_concat_s16_8x4(s2, s3, s4, s5, &s2345[0], &s2345[1], &s2345[2], + &s2345[3]); + transpose_concat_s16_8x4(s3, s4, s5, s6, &s3456[0], &s3456[1], &s3456[2], + &s3456[3]); do { int16x8_t s7, s8, s9, sA; load_s16_8x4(s, src_stride, &s7, &s8, &s9, &sA); int16x8_t s4567[4], s5678[5], s6789[4], s789A[4]; - transpose_concat_8x4(s7, s8, s9, sA, s789A); + transpose_concat_s16_8x4(s7, s8, s9, sA, &s789A[0], &s789A[1], + &s789A[2], &s789A[3]); vpx_tbl2x4_s16(s3456, s789A, s4567, merge_tbl_idx.val[0]); vpx_tbl2x4_s16(s3456, s789A, s5678, merge_tbl_idx.val[1]); vpx_tbl2x4_s16(s3456, s789A, s6789, merge_tbl_idx.val[2]); diff --git a/media/libvpx/libvpx/vpx_dsp/arm/mem_neon.h b/media/libvpx/libvpx/vpx_dsp/arm/mem_neon.h --- a/media/libvpx/libvpx/vpx_dsp/arm/mem_neon.h +++ b/media/libvpx/libvpx/vpx_dsp/arm/mem_neon.h @@ -38,15 +38,15 @@ #endif static INLINE int16x4_t create_s16x4_neon(const int16_t c0, const int16_t c1, const int16_t c2, const int16_t c3) { return vcreate_s16((uint16_t)c0 | ((uint32_t)c1 << 16) | - ((int64_t)(uint16_t)c2 << 32) | ((int64_t)c3 << 48)); + ((uint64_t)(uint16_t)c2 << 32) | ((uint64_t)c3 << 48)); } static INLINE int32x2_t create_s32x2_neon(const int32_t c0, const int32_t c1) { - return vcreate_s32((uint32_t)c0 | ((int64_t)(uint32_t)c1 << 32)); + return vcreate_s32((uint32_t)c0 | ((uint64_t)(uint32_t)c1 << 32)); } static INLINE int32x4_t create_s32x4_neon(const int32_t c0, const int32_t c1, const int32_t c2, const int32_t c3) { return vcombine_s32(create_s32x2_neon(c0, c1), create_s32x2_neon(c2, c3)); @@ -497,10 +497,38 @@ *s2 = vld1_s16(s); s += p; *s3 = vld1_s16(s); } +static INLINE void load_s16_4x11(const int16_t *s, const ptrdiff_t p, + int16x4_t *s0, int16x4_t *s1, int16x4_t *s2, + int16x4_t *s3, int16x4_t *s4, int16x4_t *s5, + int16x4_t *s6, int16x4_t *s7, int16x4_t *s8, + int16x4_t *s9, int16x4_t *s10) { + *s0 = vld1_s16(s); + s += p; + *s1 = vld1_s16(s); + s += p; + *s2 = vld1_s16(s); + s += p; + *s3 = vld1_s16(s); + s += p; + *s4 = vld1_s16(s); + s += p; + *s5 = vld1_s16(s); + s += p; + *s6 = vld1_s16(s); + s += p; + *s7 = vld1_s16(s); + s += p; + *s8 = vld1_s16(s); + s += p; + *s9 = vld1_s16(s); + s += p; + *s10 = vld1_s16(s); +} + static INLINE void store_u16_4x4(uint16_t *s, const ptrdiff_t p, const uint16x4_t s0, const uint16x4_t s1, const uint16x4_t s2, const uint16x4_t s3) { vst1_u16(s, s0); s += p; @@ -644,10 +672,69 @@ *s6 = vld1_s16(s); s += p; *s7 = vld1_s16(s); } +static INLINE void load_s16_8x11(const int16_t *s, const ptrdiff_t p, + int16x8_t *s0, int16x8_t *s1, int16x8_t *s2, + int16x8_t *s3, int16x8_t *s4, int16x8_t *s5, + int16x8_t *s6, int16x8_t *s7, int16x8_t *s8, + int16x8_t *s9, int16x8_t *s10) { + *s0 = vld1q_s16(s); + s += p; + *s1 = vld1q_s16(s); + s += p; + *s2 = vld1q_s16(s); + s += p; + *s3 = vld1q_s16(s); + s += p; + *s4 = vld1q_s16(s); + s += p; + *s5 = vld1q_s16(s); + s += p; + *s6 = vld1q_s16(s); + s += p; + *s7 = vld1q_s16(s); + s += p; + *s8 = vld1q_s16(s); + s += p; + *s9 = vld1q_s16(s); + s += p; + *s10 = vld1q_s16(s); +} + +static INLINE void load_s16_8x12(const int16_t *s, const ptrdiff_t p, + int16x8_t *s0, int16x8_t *s1, int16x8_t *s2, + int16x8_t *s3, int16x8_t *s4, int16x8_t *s5, + int16x8_t *s6, int16x8_t *s7, int16x8_t *s8, + int16x8_t *s9, int16x8_t *s10, + int16x8_t *s11) { + *s0 = vld1q_s16(s); + s += p; + *s1 = vld1q_s16(s); + s += p; + *s2 = vld1q_s16(s); + s += p; + *s3 = vld1q_s16(s); + s += p; + *s4 = vld1q_s16(s); + s += p; + *s5 = vld1q_s16(s); + s += p; + *s6 = vld1q_s16(s); + s += p; + *s7 = vld1q_s16(s); + s += p; + *s8 = vld1q_s16(s); + s += p; + *s9 = vld1q_s16(s); + s += p; + *s10 = vld1q_s16(s); + s += p; + *s11 = vld1q_s16(s); +} + static INLINE void load_s16_8x8(const int16_t *s, const ptrdiff_t p, int16x8_t *s0, int16x8_t *s1, int16x8_t *s2, int16x8_t *s3, int16x8_t *s4, int16x8_t *s5, int16x8_t *s6, int16x8_t *s7) { *s0 = vld1q_s16(s); diff --git a/media/libvpx/libvpx/vpx_dsp/arm/transpose_neon.h b/media/libvpx/libvpx/vpx_dsp/arm/transpose_neon.h --- a/media/libvpx/libvpx/vpx_dsp/arm/transpose_neon.h +++ b/media/libvpx/libvpx/vpx_dsp/arm/transpose_neon.h @@ -1547,6 +1547,160 @@ a7->val[0] = vld1q_s32(a); a7->val[1] = vld1q_s32(a + 4); transpose_s32_8x8(a0, a1, a2, a3, a4, a5, a6, a7); } + +static INLINE void transpose_concat_s16_4x4(const int16x4_t a0, + const int16x4_t a1, + const int16x4_t a2, + const int16x4_t a3, int16x8_t *b0, + int16x8_t *b1) { + // Transpose 16-bit elements: + // a0: 00, 01, 02, 03 + // a1: 10, 11, 12, 13 + // a2: 20, 21, 22, 23 + // a3: 30, 31, 32, 33 + // + // b0: 00 10 20 30 01 11 21 31 + // b1: 02 12 22 32 03 13 23 33 + + int16x8_t a0q = vcombine_s16(a0, vdup_n_s16(0)); + int16x8_t a1q = vcombine_s16(a1, vdup_n_s16(0)); + int16x8_t a2q = vcombine_s16(a2, vdup_n_s16(0)); + int16x8_t a3q = vcombine_s16(a3, vdup_n_s16(0)); + + int16x8_t a02 = vzipq_s16(a0q, a2q).val[0]; + int16x8_t a13 = vzipq_s16(a1q, a3q).val[0]; + + int16x8x2_t a0123 = vzipq_s16(a02, a13); + + *b0 = a0123.val[0]; + *b1 = a0123.val[1]; +} + +static INLINE void transpose_concat_s16_8x4(const int16x8_t a0, + const int16x8_t a1, + const int16x8_t a2, + const int16x8_t a3, int16x8_t *b0, + int16x8_t *b1, int16x8_t *b2, + int16x8_t *b3) { + // Transpose 16-bit elements: + // a0: 00, 01, 02, 03, 04, 05, 06, 07 + // a1: 10, 11, 12, 13, 14, 15, 16, 17 + // a2: 20, 21, 22, 23, 24, 25, 26, 27 + // a3: 30, 31, 32, 33, 34, 35, 36, 37 + // + // b0: 00 10 20 30 01 11 21 31 + // b1: 02 12 22 32 03 13 23 33 + // b2: 04 14 24 34 05 15 25 35 + // b3: 06 16 26 36 07 17 27 37 + + int16x8x2_t a02 = vzipq_s16(a0, a2); + int16x8x2_t a13 = vzipq_s16(a1, a3); + + int16x8x2_t a0123_lo = vzipq_s16(a02.val[0], a13.val[0]); + int16x8x2_t a0123_hi = vzipq_s16(a02.val[1], a13.val[1]); + + *b0 = a0123_lo.val[0]; + *b1 = a0123_lo.val[1]; + *b2 = a0123_hi.val[0]; + *b3 = a0123_hi.val[1]; +} + +static INLINE void transpose_concat_s8_8x4(int8x8_t a0, int8x8_t a1, + int8x8_t a2, int8x8_t a3, + int8x16_t *b0, int8x16_t *b1) { + // Transpose 8-bit elements and concatenate result rows as follows: + // a0: 00, 01, 02, 03, 04, 05, 06, 07 + // a1: 10, 11, 12, 13, 14, 15, 16, 17 + // a2: 20, 21, 22, 23, 24, 25, 26, 27 + // a3: 30, 31, 32, 33, 34, 35, 36, 37 + // + // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 + // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 + + int8x16_t a0q = vcombine_s8(a0, vdup_n_s8(0)); + int8x16_t a1q = vcombine_s8(a1, vdup_n_s8(0)); + int8x16_t a2q = vcombine_s8(a2, vdup_n_s8(0)); + int8x16_t a3q = vcombine_s8(a3, vdup_n_s8(0)); + + int8x16_t a02 = vzipq_s8(a0q, a2q).val[0]; + int8x16_t a13 = vzipq_s8(a1q, a3q).val[0]; + + int8x16x2_t a0123 = vzipq_s8(a02, a13); + + *b0 = a0123.val[0]; + *b1 = a0123.val[1]; +} + +static INLINE void transpose_concat_u8_8x4(uint8x8_t a0, uint8x8_t a1, + uint8x8_t a2, uint8x8_t a3, + uint8x16_t *b0, uint8x16_t *b1) { + // Transpose 8-bit elements and concatenate result rows as follows: + // a0: 00, 01, 02, 03, 04, 05, 06, 07 + // a1: 10, 11, 12, 13, 14, 15, 16, 17 + // a2: 20, 21, 22, 23, 24, 25, 26, 27 + // a3: 30, 31, 32, 33, 34, 35, 36, 37 + // + // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 + // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 + + uint8x16_t a0q = vcombine_u8(a0, vdup_n_u8(0)); + uint8x16_t a1q = vcombine_u8(a1, vdup_n_u8(0)); + uint8x16_t a2q = vcombine_u8(a2, vdup_n_u8(0)); + uint8x16_t a3q = vcombine_u8(a3, vdup_n_u8(0)); + + uint8x16_t a02 = vzipq_u8(a0q, a2q).val[0]; + uint8x16_t a13 = vzipq_u8(a1q, a3q).val[0]; + + uint8x16x2_t a0123 = vzipq_u8(a02, a13); + + *b0 = a0123.val[0]; + *b1 = a0123.val[1]; +} + +static INLINE void transpose_concat_s8_4x4(int8x8_t a0, int8x8_t a1, + int8x8_t a2, int8x8_t a3, + int8x16_t *b) { + // Transpose 8-bit elements and concatenate result rows as follows: + // a0: 00, 01, 02, 03, XX, XX, XX, XX + // a1: 10, 11, 12, 13, XX, XX, XX, XX + // a2: 20, 21, 22, 23, XX, XX, XX, XX + // a3: 30, 31, 32, 33, XX, XX, XX, XX + // + // b: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 + + int8x16_t a0q = vcombine_s8(a0, vdup_n_s8(0)); + int8x16_t a1q = vcombine_s8(a1, vdup_n_s8(0)); + int8x16_t a2q = vcombine_s8(a2, vdup_n_s8(0)); + int8x16_t a3q = vcombine_s8(a3, vdup_n_s8(0)); + + int8x16_t a02 = vzipq_s8(a0q, a2q).val[0]; + int8x16_t a13 = vzipq_s8(a1q, a3q).val[0]; + + *b = vzipq_s8(a02, a13).val[0]; +} + +static INLINE void transpose_concat_u8_4x4(uint8x8_t a0, uint8x8_t a1, + uint8x8_t a2, uint8x8_t a3, + uint8x16_t *b) { + // Transpose 8-bit elements and concatenate result rows as follows: + // a0: 00, 01, 02, 03, XX, XX, XX, XX + // a1: 10, 11, 12, 13, XX, XX, XX, XX + // a2: 20, 21, 22, 23, XX, XX, XX, XX + // a3: 30, 31, 32, 33, XX, XX, XX, XX + // + // b: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 + + uint8x16_t a0q = vcombine_u8(a0, vdup_n_u8(0)); + uint8x16_t a1q = vcombine_u8(a1, vdup_n_u8(0)); + uint8x16_t a2q = vcombine_u8(a2, vdup_n_u8(0)); + uint8x16_t a3q = vcombine_u8(a3, vdup_n_u8(0)); + + uint8x16_t a02 = vzipq_u8(a0q, a2q).val[0]; + uint8x16_t a13 = vzipq_u8(a1q, a3q).val[0]; + + *b = vzipq_u8(a02, a13).val[0]; +} + #endif // VPX_VPX_DSP_ARM_TRANSPOSE_NEON_H_ diff --git a/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_dotprod.c b/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_dotprod.c --- a/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_dotprod.c +++ b/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_dotprod.c @@ -358,57 +358,10 @@ h -= 4; } while (h != 0); } } -static INLINE void transpose_concat_4x4(int8x8_t a0, int8x8_t a1, int8x8_t a2, - int8x8_t a3, int8x16_t *b) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, XX, XX, XX, XX - // a1: 10, 11, 12, 13, XX, XX, XX, XX - // a2: 20, 21, 22, 23, XX, XX, XX, XX - // a3: 30, 31, 32, 33, XX, XX, XX, XX - // - // b: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - - int8x16_t a0q = vcombine_s8(a0, vdup_n_s8(0)); - int8x16_t a1q = vcombine_s8(a1, vdup_n_s8(0)); - int8x16_t a2q = vcombine_s8(a2, vdup_n_s8(0)); - int8x16_t a3q = vcombine_s8(a3, vdup_n_s8(0)); - - int8x16_t a02 = vzipq_s8(a0q, a2q).val[0]; - int8x16_t a13 = vzipq_s8(a1q, a3q).val[0]; - - *b = vzipq_s8(a02, a13).val[0]; -} - -static INLINE void transpose_concat_8x4(int8x8_t a0, int8x8_t a1, int8x8_t a2, - int8x8_t a3, int8x16_t *b0, - int8x16_t *b1) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, 04, 05, 06, 07 - // a1: 10, 11, 12, 13, 14, 15, 16, 17 - // a2: 20, 21, 22, 23, 24, 25, 26, 27 - // a3: 30, 31, 32, 33, 34, 35, 36, 37 - // - // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 - - int8x16_t a0q = vcombine_s8(a0, vdup_n_s8(0)); - int8x16_t a1q = vcombine_s8(a1, vdup_n_s8(0)); - int8x16_t a2q = vcombine_s8(a2, vdup_n_s8(0)); - int8x16_t a3q = vcombine_s8(a3, vdup_n_s8(0)); - - int8x16_t a02 = vzipq_s8(a0q, a2q).val[0]; - int8x16_t a13 = vzipq_s8(a1q, a3q).val[0]; - - int8x16x2_t a0123 = vzipq_s8(a02, a13); - - *b0 = a0123.val[0]; - *b1 = a0123.val[1]; -} - static INLINE int16x4_t convolve8_4_v(const int8x16_t samples_lo, const int8x16_t samples_hi, const int8x8_t filters) { // The sample range transform and permutation are performed by the caller. @@ -462,14 +415,14 @@ int8x8_t s6 = vreinterpret_s8_u8(vsub_u8(t6, vdup_n_u8(128))); // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. int8x16_t s0123, s1234, s2345, s3456; - transpose_concat_4x4(s0, s1, s2, s3, &s0123); - transpose_concat_4x4(s1, s2, s3, s4, &s1234); - transpose_concat_4x4(s2, s3, s4, s5, &s2345); - transpose_concat_4x4(s3, s4, s5, s6, &s3456); + transpose_concat_s8_4x4(s0, s1, s2, s3, &s0123); + transpose_concat_s8_4x4(s1, s2, s3, s4, &s1234); + transpose_concat_s8_4x4(s2, s3, s4, s5, &s2345); + transpose_concat_s8_4x4(s3, s4, s5, s6, &s3456); do { uint8x8_t t7, t8, t9, t10; load_u8_8x4(src, src_stride, &t7, &t8, &t9, &t10); @@ -477,11 +430,11 @@ int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, vdup_n_u8(128))); int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, vdup_n_u8(128))); int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, vdup_n_u8(128))); int8x16_t s78910; - transpose_concat_4x4(s7, s8, s9, s10, &s78910); + transpose_concat_s8_4x4(s7, s8, s9, s10, &s78910); // Merge new data into block from previous iteration. int8x16x2_t samples_LUT = { { s3456, s78910 } }; int8x16_t s4567 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[0]); int8x16_t s5678 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); @@ -529,14 +482,14 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. int8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_s8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_s8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_s8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_s8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); do { uint8x8_t t7, t8, t9, t10; load_u8_8x4(s, src_stride, &t7, &t8, &t9, &t10); @@ -544,11 +497,11 @@ int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, vdup_n_u8(128))); int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, vdup_n_u8(128))); int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, vdup_n_u8(128))); int8x16_t s78910_lo, s78910_hi; - transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); + transpose_concat_s8_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); // Merge new data into block from previous iteration. int8x16x2_t samples_LUT = { { s3456_lo, s78910_lo } }; int8x16_t s4567_lo = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[0]); int8x16_t s5678_lo = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); @@ -653,14 +606,14 @@ int8x8_t s6 = vreinterpret_s8_u8(vsub_u8(t6, vdup_n_u8(128))); // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. int8x16_t s0123, s1234, s2345, s3456; - transpose_concat_4x4(s0, s1, s2, s3, &s0123); - transpose_concat_4x4(s1, s2, s3, s4, &s1234); - transpose_concat_4x4(s2, s3, s4, s5, &s2345); - transpose_concat_4x4(s3, s4, s5, s6, &s3456); + transpose_concat_s8_4x4(s0, s1, s2, s3, &s0123); + transpose_concat_s8_4x4(s1, s2, s3, s4, &s1234); + transpose_concat_s8_4x4(s2, s3, s4, s5, &s2345); + transpose_concat_s8_4x4(s3, s4, s5, s6, &s3456); do { uint8x8_t t7, t8, t9, t10; load_u8_8x4(src, src_stride, &t7, &t8, &t9, &t10); @@ -668,11 +621,11 @@ int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, vdup_n_u8(128))); int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, vdup_n_u8(128))); int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, vdup_n_u8(128))); int8x16_t s78910; - transpose_concat_4x4(s7, s8, s9, s10, &s78910); + transpose_concat_s8_4x4(s7, s8, s9, s10, &s78910); // Merge new data into block from previous iteration. int8x16x2_t samples_LUT = { { s3456, s78910 } }; int8x16_t s4567 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[0]); int8x16_t s5678 = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); @@ -726,14 +679,14 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. int8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_s8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_s8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_s8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_s8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); do { uint8x8_t t7, t8, t9, t10; load_u8_8x4(s, src_stride, &t7, &t8, &t9, &t10); @@ -741,11 +694,11 @@ int8x8_t s8 = vreinterpret_s8_u8(vsub_u8(t8, vdup_n_u8(128))); int8x8_t s9 = vreinterpret_s8_u8(vsub_u8(t9, vdup_n_u8(128))); int8x8_t s10 = vreinterpret_s8_u8(vsub_u8(t10, vdup_n_u8(128))); int8x16_t s78910_lo, s78910_hi; - transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); + transpose_concat_s8_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); // Merge new data into block from previous iteration. int8x16x2_t samples_LUT = { { s3456_lo, s78910_lo } }; int8x16_t s4567_lo = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[0]); int8x16_t s5678_lo = vqtbl2q_s8(samples_LUT, merge_block_tbl.val[1]); diff --git a/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_i8mm.c b/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_i8mm.c --- a/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_i8mm.c +++ b/media/libvpx/libvpx/vpx_dsp/arm/vpx_convolve8_neon_i8mm.c @@ -338,58 +338,10 @@ h -= 4; } while (h != 0); } } -static INLINE void transpose_concat_4x4(uint8x8_t a0, uint8x8_t a1, - uint8x8_t a2, uint8x8_t a3, - uint8x16_t *b) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, XX, XX, XX, XX - // a1: 10, 11, 12, 13, XX, XX, XX, XX - // a2: 20, 21, 22, 23, XX, XX, XX, XX - // a3: 30, 31, 32, 33, XX, XX, XX, XX - // - // b: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - - uint8x16_t a0q = vcombine_u8(a0, vdup_n_u8(0)); - uint8x16_t a1q = vcombine_u8(a1, vdup_n_u8(0)); - uint8x16_t a2q = vcombine_u8(a2, vdup_n_u8(0)); - uint8x16_t a3q = vcombine_u8(a3, vdup_n_u8(0)); - - uint8x16_t a02 = vzipq_u8(a0q, a2q).val[0]; - uint8x16_t a13 = vzipq_u8(a1q, a3q).val[0]; - - *b = vzipq_u8(a02, a13).val[0]; -} - -static INLINE void transpose_concat_8x4(uint8x8_t a0, uint8x8_t a1, - uint8x8_t a2, uint8x8_t a3, - uint8x16_t *b0, uint8x16_t *b1) { - // Transpose 8-bit elements and concatenate result rows as follows: - // a0: 00, 01, 02, 03, 04, 05, 06, 07 - // a1: 10, 11, 12, 13, 14, 15, 16, 17 - // a2: 20, 21, 22, 23, 24, 25, 26, 27 - // a3: 30, 31, 32, 33, 34, 35, 36, 37 - // - // b0: 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 - // b1: 04, 14, 24, 34, 05, 15, 25, 35, 06, 16, 26, 36, 07, 17, 27, 37 - - uint8x16_t a0q = vcombine_u8(a0, vdup_n_u8(0)); - uint8x16_t a1q = vcombine_u8(a1, vdup_n_u8(0)); - uint8x16_t a2q = vcombine_u8(a2, vdup_n_u8(0)); - uint8x16_t a3q = vcombine_u8(a3, vdup_n_u8(0)); - - uint8x16_t a02 = vzipq_u8(a0q, a2q).val[0]; - uint8x16_t a13 = vzipq_u8(a1q, a3q).val[0]; - - uint8x16x2_t a0123 = vzipq_u8(a02, a13); - - *b0 = a0123.val[0]; - *b1 = a0123.val[1]; -} - static INLINE int16x4_t convolve8_4_v(const uint8x16_t samples_lo, const uint8x16_t samples_hi, const int8x8_t filters) { // Sample permutation is performed by the caller. int32x4_t sum = vusdotq_lane_s32(vdupq_n_s32(0), samples_lo, filters, 0); @@ -430,21 +382,21 @@ src += 7 * src_stride; // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. uint8x16_t s0123, s1234, s2345, s3456; - transpose_concat_4x4(s0, s1, s2, s3, &s0123); - transpose_concat_4x4(s1, s2, s3, s4, &s1234); - transpose_concat_4x4(s2, s3, s4, s5, &s2345); - transpose_concat_4x4(s3, s4, s5, s6, &s3456); + transpose_concat_u8_4x4(s0, s1, s2, s3, &s0123); + transpose_concat_u8_4x4(s1, s2, s3, s4, &s1234); + transpose_concat_u8_4x4(s2, s3, s4, s5, &s2345); + transpose_concat_u8_4x4(s3, s4, s5, s6, &s3456); do { uint8x8_t s7, s8, s9, s10; load_u8_8x4(src, src_stride, &s7, &s8, &s9, &s10); uint8x16_t s78910; - transpose_concat_4x4(s7, s8, s9, s10, &s78910); + transpose_concat_u8_4x4(s7, s8, s9, s10, &s78910); // Merge new data into block from previous iteration. uint8x16x2_t samples_LUT = { { s3456, s78910 } }; uint8x16_t s4567 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[0]); uint8x16_t s5678 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); @@ -483,21 +435,21 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. uint8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_u8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_u8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_u8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_u8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); do { uint8x8_t s7, s8, s9, s10; load_u8_8x4(s, src_stride, &s7, &s8, &s9, &s10); uint8x16_t s78910_lo, s78910_hi; - transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); + transpose_concat_u8_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); // Merge new data into block from previous iteration. uint8x16x2_t samples_LUT = { { s3456_lo, s78910_lo } }; uint8x16_t s4567_lo = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[0]); uint8x16_t s5678_lo = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); @@ -592,21 +544,21 @@ src += 7 * src_stride; // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. uint8x16_t s0123, s1234, s2345, s3456; - transpose_concat_4x4(s0, s1, s2, s3, &s0123); - transpose_concat_4x4(s1, s2, s3, s4, &s1234); - transpose_concat_4x4(s2, s3, s4, s5, &s2345); - transpose_concat_4x4(s3, s4, s5, s6, &s3456); + transpose_concat_u8_4x4(s0, s1, s2, s3, &s0123); + transpose_concat_u8_4x4(s1, s2, s3, s4, &s1234); + transpose_concat_u8_4x4(s2, s3, s4, s5, &s2345); + transpose_concat_u8_4x4(s3, s4, s5, s6, &s3456); do { uint8x8_t s7, s8, s9, s10; load_u8_8x4(src, src_stride, &s7, &s8, &s9, &s10); uint8x16_t s78910; - transpose_concat_4x4(s7, s8, s9, s10, &s78910); + transpose_concat_u8_4x4(s7, s8, s9, s10, &s78910); // Merge new data into block from previous iteration. uint8x16x2_t samples_LUT = { { s3456, s78910 } }; uint8x16_t s4567 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[0]); uint8x16_t s5678 = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); @@ -651,21 +603,21 @@ // This operation combines a conventional transpose and the sample permute // (see horizontal case) required before computing the dot product. uint8x16_t s0123_lo, s0123_hi, s1234_lo, s1234_hi, s2345_lo, s2345_hi, s3456_lo, s3456_hi; - transpose_concat_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); - transpose_concat_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); - transpose_concat_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); - transpose_concat_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); + transpose_concat_u8_8x4(s0, s1, s2, s3, &s0123_lo, &s0123_hi); + transpose_concat_u8_8x4(s1, s2, s3, s4, &s1234_lo, &s1234_hi); + transpose_concat_u8_8x4(s2, s3, s4, s5, &s2345_lo, &s2345_hi); + transpose_concat_u8_8x4(s3, s4, s5, s6, &s3456_lo, &s3456_hi); do { uint8x8_t s7, s8, s9, s10; load_u8_8x4(s, src_stride, &s7, &s8, &s9, &s10); uint8x16_t s78910_lo, s78910_hi; - transpose_concat_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); + transpose_concat_u8_8x4(s7, s8, s9, s10, &s78910_lo, &s78910_hi); // Merge new data into block from previous iteration. uint8x16x2_t samples_LUT = { { s3456_lo, s78910_lo } }; uint8x16_t s4567_lo = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[0]); uint8x16_t s5678_lo = vqtbl2q_u8(samples_LUT, merge_block_tbl.val[1]); diff --git a/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve2_bridge.h b/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve2_bridge.h --- a/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve2_bridge.h +++ b/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve2_bridge.h @@ -27,6 +27,20 @@ svset_neonq_s16(svundef_s16(), s1)); return svget_neonq_s16( svtbl2_s16(samples, svset_neonq_u16(svundef_u16(), tbl))); } +static INLINE void vpx_tbl2x4_s16(int16x8_t s0[4], int16x8_t s1[4], + int16x8_t res[4], uint16x8_t idx) { + res[0] = vpx_tbl2_s16(s0[0], s1[0], idx); + res[1] = vpx_tbl2_s16(s0[1], s1[1], idx); + res[2] = vpx_tbl2_s16(s0[2], s1[2], idx); + res[3] = vpx_tbl2_s16(s0[3], s1[3], idx); +} + +static INLINE void vpx_tbl2x2_s16(int16x8_t s0[2], int16x8_t s1[2], + int16x8_t res[2], uint16x8_t idx) { + res[0] = vpx_tbl2_s16(s0[0], s1[0], idx); + res[1] = vpx_tbl2_s16(s0[1], s1[1], idx); +} + #endif // VPX_VPX_DSP_ARM_VPX_NEON_SVE2_BRIDGE_H_ diff --git a/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve_bridge.h b/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve_bridge.h --- a/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve_bridge.h +++ b/media/libvpx/libvpx/vpx_dsp/arm/vpx_neon_sve_bridge.h @@ -46,6 +46,11 @@ static INLINE uint16x8_t vpx_tbl_u16(uint16x8_t data, uint16x8_t indices) { return svget_neonq_u16(svtbl_u16(svset_neonq_u16(svundef_u16(), data), svset_neonq_u16(svundef_u16(), indices))); } +static INLINE int16x8_t vpx_tbl_s16(int16x8_t data, uint16x8_t indices) { + return svget_neonq_s16(svtbl_s16(svset_neonq_s16(svundef_s16(), data), + svset_neonq_u16(svundef_u16(), indices))); +} + #endif // VPX_VPX_DSP_ARM_VPX_NEON_SVE_BRIDGE_H_ diff --git a/media/libvpx/libvpx/vpx_dsp/intrapred.c b/media/libvpx/libvpx/vpx_dsp/intrapred.c --- a/media/libvpx/libvpx/vpx_dsp/intrapred.c +++ b/media/libvpx/libvpx/vpx_dsp/intrapred.c @@ -12,11 +12,11 @@ #include "./vpx_dsp_rtcd.h" #include "vpx_dsp/vpx_dsp_common.h" #include "vpx_mem/vpx_mem.h" -#define DST(x, y) dst[(x) + (y)*stride] +#define DST(x, y) dst[(x) + (y) * stride] #define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) #define AVG2(a, b) (((a) + (b) + 1) >> 1) static INLINE void d207_predictor(uint8_t *dst, ptrdiff_t stride, int bs, const uint8_t *above, const uint8_t *left) { diff --git a/media/libvpx/libvpx/vpx_dsp/mips/macros_msa.h b/media/libvpx/libvpx/vpx_dsp/mips/macros_msa.h --- a/media/libvpx/libvpx/vpx_dsp/mips/macros_msa.h +++ b/media/libvpx/libvpx/vpx_dsp/mips/macros_msa.h @@ -154,11 +154,11 @@ #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *)(pdst); \ uint32_t val0_sd_m, val1_sd_m; \ \ - val0_sd_m = (uint32_t)((val)&0x00000000FFFFFFFF); \ + val0_sd_m = (uint32_t)((val) & 0x00000000FFFFFFFF); \ val1_sd_m = (uint32_t)(((val) >> 32) & 0x00000000FFFFFFFF); \ \ SW(val0_sd_m, pdst_sd_m); \ SW(val1_sd_m, pdst_sd_m + 4); \ } @@ -479,21 +479,21 @@ Details : Each unsigned byte element from 'in0' vector is added with each unsigned byte element from 'in1' vector. Then the average with rounding is calculated and written to 'out0' */ #define AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1) \ - { \ + do { \ out0 = (RTYPE)__msa_aver_u_b((v16u8)in0, (v16u8)in1); \ out1 = (RTYPE)__msa_aver_u_b((v16u8)in2, (v16u8)in3); \ - } + } while (0) #define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__) #define AVER_UB4(RTYPE, in0, in1, in2, in3, in4, in5, in6, in7, out0, out1, \ out2, out3) \ { \ - AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1) \ - AVER_UB2(RTYPE, in4, in5, in6, in7, out2, out3) \ + AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1); \ + AVER_UB2(RTYPE, in4, in5, in6, in7, out2, out3); \ } #define AVER_UB4_UB(...) AVER_UB4(v16u8, __VA_ARGS__) /* Description : Immediate number of elements to slide with zero Arguments : Inputs - in0, in1, slide_val @@ -1461,19 +1461,19 @@ 'shift'. The last discarded bit is added to shifted value for rounding and the result is written in-place. 'shift' is a vector. */ #define SRAR_W2(RTYPE, in0, in1, shift) \ - { \ + do { \ in0 = (RTYPE)__msa_srar_w((v4i32)in0, (v4i32)shift); \ in1 = (RTYPE)__msa_srar_w((v4i32)in1, (v4i32)shift); \ - } + } while (0) #define SRAR_W4(RTYPE, in0, in1, in2, in3, shift) \ { \ - SRAR_W2(RTYPE, in0, in1, shift) \ - SRAR_W2(RTYPE, in2, in3, shift) \ + SRAR_W2(RTYPE, in0, in1, shift); \ + SRAR_W2(RTYPE, in2, in3, shift); \ } #define SRAR_W4_SW(...) SRAR_W4(v4i32, __VA_ARGS__) /* Description : Shift right arithmetic rounded (immediate) Arguments : Inputs - in0, in1, shift diff --git a/media/libvpx/libvpx/vpx_dsp/mips/variance_mmi.c b/media/libvpx/libvpx/vpx_dsp/mips/variance_mmi.c --- a/media/libvpx/libvpx/vpx_dsp/mips/variance_mmi.c +++ b/media/libvpx/libvpx/vpx_dsp/mips/variance_mmi.c @@ -1118,11 +1118,11 @@ uint32_t vpx_sub_pixel_variance16x##H##_mmi( \ const uint8_t *src_ptr, int src_stride, int x_offset, int y_offset, \ const uint8_t *ref_ptr, int ref_stride, uint32_t *sse) { \ uint8_t temp2[16 * (H)]; \ var_filter_block2d_bil_16x(src_ptr, src_stride, x_offset, y_offset, temp2, \ - ((H)-2) / 2); \ + ((H) - 2) / 2); \ \ return vpx_variance16x##H##_mmi(temp2, 16, ref_ptr, ref_stride, sse); \ } SUBPIX_VAR16XN(16) @@ -1217,11 +1217,11 @@ uint32_t vpx_sub_pixel_variance8x##H##_mmi( \ const uint8_t *src_ptr, int src_stride, int x_offset, int y_offset, \ const uint8_t *ref_ptr, int ref_stride, uint32_t *sse) { \ uint8_t temp2[8 * (H)]; \ var_filter_block2d_bil_8x(src_ptr, src_stride, x_offset, y_offset, temp2, \ - ((H)-2) / 2); \ + ((H) - 2) / 2); \ \ return vpx_variance8x##H##_mmi(temp2, 8, ref_ptr, ref_stride, sse); \ } SUBPIX_VAR8XN(16) @@ -1313,11 +1313,11 @@ uint32_t vpx_sub_pixel_variance4x##H##_mmi( \ const uint8_t *src_ptr, int src_stride, int x_offset, int y_offset, \ const uint8_t *ref_ptr, int ref_stride, uint32_t *sse) { \ uint8_t temp2[4 * (H)]; \ var_filter_block2d_bil_4x(src_ptr, src_stride, x_offset, y_offset, temp2, \ - ((H)-2) / 2); \ + ((H) - 2) / 2); \ \ return vpx_variance4x##H##_mmi(temp2, 4, ref_ptr, ref_stride, sse); \ } SUBPIX_VAR4XN(8) diff --git a/media/libvpx/libvpx/vpx_dsp/ppc/inv_txfm_vsx.c b/media/libvpx/libvpx/vpx_dsp/ppc/inv_txfm_vsx.c --- a/media/libvpx/libvpx/vpx_dsp/ppc/inv_txfm_vsx.c +++ b/media/libvpx/libvpx/vpx_dsp/ppc/inv_txfm_vsx.c @@ -1058,23 +1058,23 @@ out[2][4], out[2][5], out[2][6], out[2][7]); \ TRANSPOSE8x8(in[3][0], in[3][1], in[3][2], in[3][3], in[3][4], in[3][5], \ in[3][6], in[3][7], out[3][0], out[3][1], out[3][2], out[3][3], \ out[3][4], out[3][5], out[3][6], out[3][7]); -#define PIXEL_ADD_STORE32(in0, in1, in2, in3, step) \ - dst = vec_vsx_ld((step)*stride, dest); \ - d_uh = (int16x8_t)vec_mergeh(dst, zerov); \ - d_ul = (int16x8_t)vec_mergel(dst, zerov); \ - PIXEL_ADD(in0, d_uh, add, shift6); \ - PIXEL_ADD(in1, d_ul, add, shift6); \ - vec_vsx_st(vec_packsu(d_uh, d_ul), (step)*stride, dest); \ - dst = vec_vsx_ld((step)*stride + 16, dest); \ - d_uh = (int16x8_t)vec_mergeh(dst, zerov); \ - d_ul = (int16x8_t)vec_mergel(dst, zerov); \ - PIXEL_ADD(in2, d_uh, add, shift6); \ - PIXEL_ADD(in3, d_ul, add, shift6); \ - vec_vsx_st(vec_packsu(d_uh, d_ul), (step)*stride + 16, dest); +#define PIXEL_ADD_STORE32(in0, in1, in2, in3, step) \ + dst = vec_vsx_ld((step) * stride, dest); \ + d_uh = (int16x8_t)vec_mergeh(dst, zerov); \ + d_ul = (int16x8_t)vec_mergel(dst, zerov); \ + PIXEL_ADD(in0, d_uh, add, shift6); \ + PIXEL_ADD(in1, d_ul, add, shift6); \ + vec_vsx_st(vec_packsu(d_uh, d_ul), (step) * stride, dest); \ + dst = vec_vsx_ld((step) * stride + 16, dest); \ + d_uh = (int16x8_t)vec_mergeh(dst, zerov); \ + d_ul = (int16x8_t)vec_mergel(dst, zerov); \ + PIXEL_ADD(in2, d_uh, add, shift6); \ + PIXEL_ADD(in3, d_ul, add, shift6); \ + vec_vsx_st(vec_packsu(d_uh, d_ul), (step) * stride + 16, dest); #define ADD_STORE_BLOCK(in, offset) \ PIXEL_ADD_STORE32(in[0][0], in[1][0], in[2][0], in[3][0], (offset) + 0); \ PIXEL_ADD_STORE32(in[0][1], in[1][1], in[2][1], in[3][1], (offset) + 1); \ PIXEL_ADD_STORE32(in[0][2], in[1][2], in[2][2], in[3][2], (offset) + 2); \ diff --git a/media/libvpx/libvpx/vpx_dsp/ppc/types_vsx.h b/media/libvpx/libvpx/vpx_dsp/ppc/types_vsx.h --- a/media/libvpx/libvpx/vpx_dsp/ppc/types_vsx.h +++ b/media/libvpx/libvpx/vpx_dsp/ppc/types_vsx.h @@ -62,11 +62,11 @@ #define unpack_to_s16_h(v) \ (int16x8_t) vec_mergeh((uint8x16_t)v, vec_splat_u8(0)) #define unpack_to_s16_l(v) \ (int16x8_t) vec_mergel((uint8x16_t)v, vec_splat_u8(0)) #ifndef xxpermdi -#define xxpermdi(a, b, c) vec_xxpermdi(b, a, (((c) >> 1) | ((c)&1) << 1) ^ 3) +#define xxpermdi(a, b, c) vec_xxpermdi(b, a, (((c) >> 1) | ((c) & 1) << 1) ^ 3) #endif #endif static INLINE uint8x16_t read4x2(const uint8_t *a, int stride) { const uint32x4_t a0 = (uint32x4_t)vec_vsx_ld(0, a); diff --git a/media/libvpx/libvpx/vpx_dsp/prob.h b/media/libvpx/libvpx/vpx_dsp/prob.h --- a/media/libvpx/libvpx/vpx_dsp/prob.h +++ b/media/libvpx/libvpx/vpx_dsp/prob.h @@ -28,11 +28,11 @@ #define vpx_prob_half ((vpx_prob)128) typedef int8_t vpx_tree_index; -#define TREE_SIZE(leaf_count) (2 * (leaf_count)-2) +#define TREE_SIZE(leaf_count) (2 * (leaf_count) - 2) #define vpx_complement(x) (255 - (x)) #define MODE_MV_COUNT_SAT 20 diff --git a/media/libvpx/libvpx/vpx_dsp/psnr.h b/media/libvpx/libvpx/vpx_dsp/psnr.h --- a/media/libvpx/libvpx/vpx_dsp/psnr.h +++ b/media/libvpx/libvpx/vpx_dsp/psnr.h @@ -37,14 +37,15 @@ #if CONFIG_VP9_HIGHBITDEPTH int64_t vpx_highbd_get_y_sse(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b); void vpx_calc_highbd_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, PSNR_STATS *psnr, - unsigned int bit_depth, unsigned int in_bit_depth); + unsigned int bit_depth, unsigned int in_bit_depth, + int spatial_layer_id); #endif void vpx_calc_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, - PSNR_STATS *psnr); + PSNR_STATS *psnr, int spatial_layer_id); double vpx_psnrhvs(const YV12_BUFFER_CONFIG *source, const YV12_BUFFER_CONFIG *dest, double *phvs_y, double *phvs_u, double *phvs_v, uint32_t bd, uint32_t in_bd); diff --git a/media/libvpx/libvpx/vpx_dsp/psnr.c b/media/libvpx/libvpx/vpx_dsp/psnr.c --- a/media/libvpx/libvpx/vpx_dsp/psnr.c +++ b/media/libvpx/libvpx/vpx_dsp/psnr.c @@ -175,11 +175,12 @@ #endif // CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH void vpx_calc_highbd_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, PSNR_STATS *psnr, - uint32_t bit_depth, uint32_t in_bit_depth) { + uint32_t bit_depth, uint32_t in_bit_depth, + int spatial_layer_id) { const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width }; const int heights[3] = { a->y_crop_height, a->uv_crop_height, a->uv_crop_height }; const uint8_t *a_planes[3] = { a->y_buffer, a->u_buffer, a->v_buffer }; const int a_strides[3] = { a->y_stride, a->uv_stride, a->uv_stride }; @@ -217,16 +218,17 @@ psnr->sse[0] = total_sse; psnr->samples[0] = total_samples; psnr->psnr[0] = vpx_sse_to_psnr((double)total_samples, peak, (double)total_sse); + psnr->spatial_layer_id = spatial_layer_id; } #endif // !CONFIG_VP9_HIGHBITDEPTH void vpx_calc_psnr(const YV12_BUFFER_CONFIG *a, const YV12_BUFFER_CONFIG *b, - PSNR_STATS *psnr) { + PSNR_STATS *psnr, int spatial_layer_id) { static const double peak = 255.0; const int widths[3] = { a->y_crop_width, a->uv_crop_width, a->uv_crop_width }; const int heights[3] = { a->y_crop_height, a->uv_crop_height, a->uv_crop_height }; const uint8_t *a_planes[3] = { a->y_buffer, a->u_buffer, a->v_buffer }; @@ -253,6 +255,7 @@ psnr->sse[0] = total_sse; psnr->samples[0] = total_samples; psnr->psnr[0] = vpx_sse_to_psnr((double)total_samples, peak, (double)total_sse); + psnr->spatial_layer_id = spatial_layer_id; } diff --git a/media/libvpx/libvpx/vpx_mem/include/vpx_mem_intrnl.h b/media/libvpx/libvpx/vpx_mem/include/vpx_mem_intrnl.h --- a/media/libvpx/libvpx/vpx_mem/include/vpx_mem_intrnl.h +++ b/media/libvpx/libvpx/vpx_mem/include/vpx_mem_intrnl.h @@ -24,8 +24,8 @@ #endif #endif /*returns an addr aligned to the byte boundary specified by align*/ #define align_addr(addr, align) \ - (void *)(((size_t)(addr) + ((align)-1)) & ~(size_t)((align)-1)) + (void *)(((size_t)(addr) + ((align) - 1)) & ~(size_t)((align) - 1)) #endif // VPX_VPX_MEM_INCLUDE_VPX_MEM_INTRNL_H_ diff --git a/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c b/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c --- a/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c +++ b/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c @@ -14,11 +14,11 @@ #if defined(__APPLE__) #include #endif -#if !CONFIG_RUNTIME_CPU_DETECT || defined(__OpenBSD__) +#if !CONFIG_RUNTIME_CPU_DETECT static int arm_get_cpu_caps(void) { // This function should actually be a no-op. There is no way to adjust any of // these because the RTCD tables do not exist: the functions are called // statically. @@ -27,11 +27,11 @@ flags |= HAS_NEON; #endif // HAVE_NEON return flags; } -#elif defined(__APPLE__) // end !CONFIG_RUNTIME_CPU_DETECT || defined(__OpenBSD__) +#elif defined(__APPLE__) // end !CONFIG_RUNTIME_CPU_DETECT // sysctlbyname() parameter documentation for instruction set characteristics: // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics static INLINE int64_t have_feature(const char *feature) { int64_t feature_present = 0; diff --git a/media/libvpx/libvpx/vpx_ports/mem.h b/media/libvpx/libvpx/vpx_ports/mem.h --- a/media/libvpx/libvpx/vpx_ports/mem.h +++ b/media/libvpx/libvpx/vpx_ports/mem.h @@ -32,12 +32,12 @@ #if !VPX_HAS_BUILTIN(__builtin_prefetch) && !defined(__GNUC__) #define __builtin_prefetch(x) #endif /* Shift down with rounding */ -#define ROUND_POWER_OF_TWO(value, n) (((value) + (1 << ((n)-1))) >> (n)) -#define ROUND64_POWER_OF_TWO(value, n) (((value) + (1ULL << ((n)-1))) >> (n)) +#define ROUND_POWER_OF_TWO(value, n) (((value) + (1 << ((n) - 1))) >> (n)) +#define ROUND64_POWER_OF_TWO(value, n) (((value) + (1ULL << ((n) - 1))) >> (n)) #define ALIGN_POWER_OF_TWO(value, n) \ (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)) #define CONVERT_TO_SHORTPTR(x) ((uint16_t *)(((uintptr_t)(x)) << 1)) diff --git a/media/libvpx/libvpx/vpx_ports/vpx_timer.h b/media/libvpx/libvpx/vpx_ports/vpx_timer.h --- a/media/libvpx/libvpx/vpx_ports/vpx_timer.h +++ b/media/libvpx/libvpx/vpx_ports/vpx_timer.h @@ -29,47 +29,51 @@ #include #else /* * POSIX specific includes */ -#include +#include /* timersub is not provided by msys at this time. */ -#ifndef timersub -#define timersub(a, b, result) \ +#ifndef timersub_ns +#define timersub_ns(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ + (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ + if ((result)->tv_nsec < 0) { \ --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ + (result)->tv_nsec += 1000000000; \ } \ } while (0) #endif #endif struct vpx_usec_timer { #if defined(_WIN32) LARGE_INTEGER begin, end; #else - struct timeval begin, end; + struct timespec begin, end; #endif }; static INLINE void vpx_usec_timer_start(struct vpx_usec_timer *t) { #if defined(_WIN32) QueryPerformanceCounter(&t->begin); +#elif defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &t->begin); #else - gettimeofday(&t->begin, NULL); + clock_gettime(CLOCK_MONOTONIC, &t->begin); #endif } static INLINE void vpx_usec_timer_mark(struct vpx_usec_timer *t) { #if defined(_WIN32) QueryPerformanceCounter(&t->end); +#elif defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &t->end); #else - gettimeofday(&t->end, NULL); + clock_gettime(CLOCK_MONOTONIC, &t->end); #endif } static INLINE int64_t vpx_usec_timer_elapsed(struct vpx_usec_timer *t) { #if defined(_WIN32) @@ -78,22 +82,22 @@ diff.QuadPart = t->end.QuadPart - t->begin.QuadPart; QueryPerformanceFrequency(&freq); return diff.QuadPart * 1000000 / freq.QuadPart; #else - struct timeval diff; + struct timespec diff; - timersub(&t->end, &t->begin, &diff); - return (int64_t)diff.tv_sec * 1000000 + diff.tv_usec; + timersub_ns(&t->end, &t->begin, &diff); + return (int64_t)diff.tv_sec * 1000000 + diff.tv_nsec / 1000; #endif } #else /* CONFIG_OS_SUPPORT = 0*/ /* Empty timer functions if CONFIG_OS_SUPPORT = 0 */ -#ifndef timersub -#define timersub(a, b, result) +#ifndef timersub_ns +#define timersub_ns(a, b, result) #endif struct vpx_usec_timer { void *dummy; }; diff --git a/media/libvpx/libvpx/vpx_ports/x86.h b/media/libvpx/libvpx/vpx_ports/x86.h --- a/media/libvpx/libvpx/vpx_ports/x86.h +++ b/media/libvpx/libvpx/vpx_ports/x86.h @@ -162,71 +162,70 @@ #define HAS_AVX512 0x100 #ifndef BIT #define BIT(n) (1u << (n)) #endif +#define MMX_BITS BIT(23) +#define SSE_BITS BIT(25) +#define SSE2_BITS BIT(26) +#define SSE3_BITS BIT(0) +#define SSSE3_BITS BIT(9) +#define SSE4_1_BITS BIT(19) +// Bits 27 (OSXSAVE) & 28 (256-bit AVX) +#define AVX_BITS (BIT(27) | BIT(28)) +#define AVX2_BITS BIT(5) +// Bits 16 (AVX-512F) & 17 (AVX-512DQ) & 28 (AVX-512CD) & 30 (AVX-512BW) +// & 31 (AVX-512VL) +#define AVX512_BITS (BIT(16) | BIT(17) | BIT(28) | BIT(30) | BIT(31)) + +#define FEATURE_SET(reg, feature) \ + (((reg) & (feature##_BITS)) == (feature##_BITS)) + static INLINE int x86_simd_caps(void) { unsigned int flags = 0; unsigned int mask = ~0u; unsigned int max_cpuid_val, reg_eax, reg_ebx, reg_ecx, reg_edx; char *env; (void)reg_ebx; /* See if the CPU capabilities are being overridden by the environment */ env = getenv("VPX_SIMD_CAPS"); - if (env && *env) return (int)strtol(env, NULL, 0); env = getenv("VPX_SIMD_CAPS_MASK"); - if (env && *env) mask = (unsigned int)strtoul(env, NULL, 0); /* Ensure that the CPUID instruction supports extended features */ cpuid(0, 0, max_cpuid_val, reg_ebx, reg_ecx, reg_edx); - if (max_cpuid_val < 1) return 0; /* Get the standard feature flags */ cpuid(1, 0, reg_eax, reg_ebx, reg_ecx, reg_edx); - if (reg_edx & BIT(23)) flags |= HAS_MMX; - - if (reg_edx & BIT(25)) flags |= HAS_SSE; /* aka xmm */ - - if (reg_edx & BIT(26)) flags |= HAS_SSE2; /* aka wmt */ + flags |= FEATURE_SET(reg_edx, MMX) ? HAS_MMX : 0; + flags |= FEATURE_SET(reg_edx, SSE) ? HAS_SSE : 0; + flags |= FEATURE_SET(reg_edx, SSE2) ? HAS_SSE2 : 0; + flags |= FEATURE_SET(reg_ecx, SSE3) ? HAS_SSE3 : 0; + flags |= FEATURE_SET(reg_ecx, SSSE3) ? HAS_SSSE3 : 0; + flags |= FEATURE_SET(reg_ecx, SSE4_1) ? HAS_SSE4_1 : 0; - if (reg_ecx & BIT(0)) flags |= HAS_SSE3; - - if (reg_ecx & BIT(9)) flags |= HAS_SSSE3; - - if (reg_ecx & BIT(19)) flags |= HAS_SSE4_1; - - // bits 27 (OSXSAVE) & 28 (256-bit AVX) - if ((reg_ecx & (BIT(27) | BIT(28))) == (BIT(27) | BIT(28))) { + if (FEATURE_SET(reg_ecx, AVX)) { // Check for OS-support of YMM state. Necessary for AVX and AVX2. if ((xgetbv() & 0x6) == 0x6) { flags |= HAS_AVX; - if (max_cpuid_val >= 7) { /* Get the leaf 7 feature flags. Needed to check for AVX2 support */ cpuid(7, 0, reg_eax, reg_ebx, reg_ecx, reg_edx); - - if (reg_ebx & BIT(5)) flags |= HAS_AVX2; - - // bits 16 (AVX-512F) & 17 (AVX-512DQ) & 28 (AVX-512CD) & - // 30 (AVX-512BW) & 32 (AVX-512VL) - if ((reg_ebx & (BIT(16) | BIT(17) | BIT(28) | BIT(30) | BIT(31))) == - (BIT(16) | BIT(17) | BIT(28) | BIT(30) | BIT(31))) { + flags |= FEATURE_SET(reg_ebx, AVX2) ? HAS_AVX2 : 0; + if (FEATURE_SET(reg_ebx, AVX512)) { // Check for OS-support of ZMM and YMM state. Necessary for AVX-512. if ((xgetbv() & 0xe6) == 0xe6) flags |= HAS_AVX512; } } } } - (void)reg_eax; // Avoid compiler warning on unused-but-set variable. - return flags & mask; } // Fine-Grain Measurement Functions // diff --git a/media/libvpx/libvpx/vpx_scale/generic/yv12config.c b/media/libvpx/libvpx/vpx_scale/generic/yv12config.c --- a/media/libvpx/libvpx/vpx_scale/generic/yv12config.c +++ b/media/libvpx/libvpx/vpx_scale/generic/yv12config.c @@ -25,11 +25,11 @@ /**************************************************************************** * ****************************************************************************/ #define yv12_align_addr(addr, align) \ - (void *)(((size_t)(addr) + ((align)-1)) & (size_t) - (align)) + (void *)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align)) int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) { if (ybf) { // If libvpx is using frame buffer callbacks then buffer_alloc_sz must // not be set. diff --git a/media/libvpx/libvpx/vpx_util/vpx_atomics.h b/media/libvpx/libvpx/vpx_util/vpx_atomics.h --- a/media/libvpx/libvpx/vpx_util/vpx_atomics.h +++ b/media/libvpx/libvpx/vpx_util/vpx_atomics.h @@ -70,12 +70,11 @@ // (NOT memset) and accessed through vpx_atomic_ functions. typedef struct vpx_atomic_int { volatile int value; } vpx_atomic_int; -#define VPX_ATOMIC_INIT(num) \ - { num } +#define VPX_ATOMIC_INIT(num) { num } // Initialization of an atomic int, not thread safe. static INLINE void vpx_atomic_init(vpx_atomic_int *atomic, int value) { atomic->value = value; } diff --git a/media/libvpx/libvpx/vpx_util/vpx_pthread.h b/media/libvpx/libvpx/vpx_util/vpx_pthread.h --- a/media/libvpx/libvpx/vpx_util/vpx_pthread.h +++ b/media/libvpx/libvpx/vpx_util/vpx_pthread.h @@ -24,16 +24,15 @@ // Prevent leaking max/min macros. #undef NOMINMAX #define NOMINMAX #undef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN -#include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT typedef HANDLE pthread_t; -typedef CRITICAL_SECTION pthread_mutex_t; +typedef SRWLOCK pthread_mutex_t; #if _WIN32_WINNT < 0x0600 #error _WIN32_WINNT must target Windows Vista / Server 2008 or newer. #endif typedef CONDITION_VARIABLE pthread_cond_t; @@ -79,39 +78,34 @@ return 0; } static INLINE int pthread_join(pthread_t thread, void **value_ptr) { (void)value_ptr; - return (WaitForSingleObjectEx(thread, INFINITE, FALSE /*bAlertable*/) != - WAIT_OBJECT_0 || + return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || CloseHandle(thread) == 0); } // Mutex static INLINE int pthread_mutex_init(pthread_mutex_t *const mutex, void *mutexattr) { (void)mutexattr; - InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/); + InitializeSRWLock(mutex); return 0; } -static INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) { - return TryEnterCriticalSection(mutex) ? 0 : EBUSY; -} - static INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) { - EnterCriticalSection(mutex); + AcquireSRWLockExclusive(mutex); return 0; } static INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) { - LeaveCriticalSection(mutex); + ReleaseSRWLockExclusive(mutex); return 0; } static INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) { - DeleteCriticalSection(mutex); + (void)mutex; return 0; } // Condition static INLINE int pthread_cond_destroy(pthread_cond_t *const condition) { @@ -136,12 +130,11 @@ return 0; } static INLINE int pthread_cond_wait(pthread_cond_t *const condition, pthread_mutex_t *const mutex) { - int ok; - ok = SleepConditionVariableCS(condition, mutex, INFINITE); + const int ok = SleepConditionVariableSRW(condition, mutex, INFINITE, 0); return !ok; } #else // _WIN32 #include // NOLINT #define THREADFN void * diff --git a/media/libvpx/libvpx/vpxenc.c b/media/libvpx/libvpx/vpxenc.c --- a/media/libvpx/libvpx/vpxenc.c +++ b/media/libvpx/libvpx/vpxenc.c @@ -717,11 +717,11 @@ if (rat->den < 0) { rat->num *= -1; rat->den *= -1; } - if (rat->num < 0) die("Error: %s must be positive\n", msg); + if (rat->num <= 0) die("Error: %s must be positive\n", msg); if (!rat->den) die("Error: %s has zero denominator\n", msg); } static void parse_global_config(struct VpxEncoderConfig *global, char **argv) { @@ -850,11 +850,11 @@ if (stream == NULL) { fatal("Failed to allocate new stream."); } if (prev) { - memcpy(stream, prev, sizeof(*stream)); + *stream = *prev; stream->index++; prev->next = stream; } else { vpx_codec_err_t res; diff --git a/media/libvpx/libvpx/webmdec.cc b/media/libvpx/libvpx/webmdec.cc --- a/media/libvpx/libvpx/webmdec.cc +++ b/media/libvpx/libvpx/webmdec.cc @@ -177,11 +177,11 @@ const mkvparser::Block::Frame &frame = block->GetFrame(webm_ctx->block_frame_index); ++webm_ctx->block_frame_index; if (frame.len > static_cast(*buffer_size)) { - delete[] * buffer; + delete[] *buffer; *buffer = new uint8_t[frame.len]; if (*buffer == nullptr) { return -1; } webm_ctx->buffer = *buffer; diff --git a/media/libvpx/moz.yaml b/media/libvpx/moz.yaml --- a/media/libvpx/moz.yaml +++ b/media/libvpx/moz.yaml @@ -18,15 +18,15 @@ # Usually different from repository url url: https://chromium.googlesource.com/webm/libvpx # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: 95afae324986797afb19a606f3d95ecdf21e99a7 (Fri Feb 28 04:15:02 2025). + release: cdd9b1ea25aca22200996a726eafd25d4fcd56d1 (Tue Dec 16 01:02:52 2025). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: 95afae324986797afb19a606f3d95ecdf21e99a7 + revision: cdd9b1ea25aca22200996a726eafd25d4fcd56d1 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ # Multiple licenses can be specified (as a YAML list) # A "LICENSE" file must exist containing the full license text