aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--CHANGELOG27
-rw-r--r--METADATA6
-rw-r--r--README.android8
-rw-r--r--TEST_MAPPING12
-rw-r--r--build/make/configure.sh101
-rw-r--r--config/arm-neon/vpx_dsp_rtcd.h4
-rw-r--r--config/arm-neon/vpx_version.h8
-rw-r--r--config/arm64/vpx_dsp_rtcd.h4
-rw-r--r--config/arm64/vpx_version.h8
-rw-r--r--config/generic/vpx_dsp_rtcd.h2
-rw-r--r--config/generic/vpx_version.h8
-rw-r--r--config/x86/vpx_dsp_rtcd.h2
-rw-r--r--config/x86/vpx_version.h8
-rw-r--r--config/x86_64/vpx_dsp_rtcd.h2
-rw-r--r--config/x86_64/vpx_version.h8
-rw-r--r--libs.mk2
-rw-r--r--test/encode_api_test.cc650
-rw-r--r--test/sum_squares_test.cc1
-rw-r--r--test/test.mk1
-rw-r--r--test/video_source.h2
-rw-r--r--test/vp8_datarate_test.cc23
-rw-r--r--test/vp9_boolcoder_test.cc25
-rw-r--r--test/vp9_scale_test.cc9
-rw-r--r--test/vpx_image_test.cc127
-rw-r--r--vp8/decoder/threading.c17
-rw-r--r--vp8/encoder/encodeframe.c17
-rw-r--r--vp8/encoder/onyx_if.c57
-rw-r--r--vp8/encoder/ratectrl.c29
-rw-r--r--vp9/encoder/vp9_bitstream.c122
-rw-r--r--vp9/encoder/vp9_bitstream.h3
-rw-r--r--vp9/encoder/vp9_encodeframe.c12
-rw-r--r--vp9/encoder/vp9_encoder.c90
-rw-r--r--vp9/encoder/vp9_encoder.h8
-rw-r--r--vp9/encoder/vp9_multi_thread.c29
-rw-r--r--vp9/encoder/vp9_ratectrl.c9
-rw-r--r--vp9/encoder/x86/vp9_frame_scale_ssse3.c16
-rw-r--r--vp9/ratectrl_rtc.cc4
-rw-r--r--vp9/simple_encode.cc13
-rw-r--r--vp9/simple_encode.h1
-rw-r--r--vp9/vp9_cx_iface.c15
-rw-r--r--vpx/src/vpx_image.c64
-rw-r--r--vpx/vpx_image.h18
-rw-r--r--vpx_dsp/arm/highbd_sse_neon.c1
-rw-r--r--vpx_dsp/arm/sse_neon.c2
-rw-r--r--vpx_dsp/bitwriter.c21
-rw-r--r--vpx_dsp/bitwriter.h34
-rw-r--r--vpx_dsp/bitwriter_buffer.c21
-rw-r--r--vpx_dsp/bitwriter_buffer.h16
-rw-r--r--vpx_dsp/sse.c1
-rw-r--r--vpx_dsp/vpx_dsp_rtcd_defs.pl2
-rw-r--r--vpx_dsp/x86/sse_avx2.c3
52 files changed, 1384 insertions, 290 deletions
diff --git a/AUTHORS b/AUTHORS
index 5515e2658..a98d0d891 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -76,6 +76,7 @@ Hangyu Kuang <hkuang@google.com>
Hanno Böck <hanno@hboeck.de>
Han Shen <shenhan@google.com>
Hao Chen <chenhao@loongson.cn>
+Hari Limaye <hari.limaye@arm.com>
Harish Mahendrakar <harish.mahendrakar@ittiam.com>
Henrik Lundin <hlundin@google.com>
Hien Ho <hienho@google.com>
diff --git a/CHANGELOG b/CHANGELOG
index 6e39ca09e..9d3d0faa2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,30 @@
+2024-05-21 v1.14.1 "Venetian Duck"
+ This release includes enhancements and bug fixes.
+
+ - Upgrading:
+ This release is ABI compatible with the previous release.
+
+ - Enhancement:
+ Improved the detection of compiler support for AArch64 extensions,
+ particularly SVE.
+
+ Added vpx_codec_get_global_headers() support for VP9.
+
+ - Bug fixes:
+ Added buffer bounds checks to vpx_writer and vpx_write_bit_buffer.
+ Fix to GetSegmentationData() crash in aq_mode=0 for RTC rate control.
+ Fix to alloc for row_base_thresh_freq_fac.
+ Free row mt memory before freeing cpi->tile_data.
+ Fix to buffer alloc for vp9_bitstream_worker_data.
+ Fix to VP8 race issue for multi-thread with pnsr_calc.
+ Fix to uv width/height in vp9_scale_and_extend_frame_ssse3.
+ Fix to integer division by zero and overflow in calc_pframe_target_size().
+ Fix to integer overflow in vpx_img_alloc() & vpx_img_wrap()(CVE-2024-5197).
+ Fix to UBSan error in vp9_rc_update_framerate().
+ Fix to UBSan errors in vp8_new_framerate().
+ Fix to integer overflow in vp8 encodeframe.c.
+ Handle EINTR from sem_wait().
+
2024-01-02 v1.14.0 "Venetian Duck"
This release drops support for old C compilers, such as Visual Studio 2012
and older, that disallow mixing variable declarations and statements (a C99
diff --git a/METADATA b/METADATA
index 08199cc3a..2ad1ff1c8 100644
--- a/METADATA
+++ b/METADATA
@@ -11,12 +11,12 @@ third_party {
}
last_upgrade_date {
year: 2024
- month: 1
- day: 22
+ month: 6
+ day: 3
}
identifier {
type: "Git"
value: "https://chromium.googlesource.com/webm/libvpx"
- version: "v1.14.0"
+ version: "v1.14.1"
}
}
diff --git a/README.android b/README.android
index 5706119b4..7a01a008a 100644
--- a/README.android
+++ b/README.android
@@ -1,12 +1,12 @@
Name: libvpx
URL: http://www.webmproject.org
-Version: v1.14.0
+Version: v1.14.1
License: BSD
License File: libvpx/LICENSE
-Date: Monday January 22 2024
-Branch: v1.14.0
-Commit: 602e2e8979d111b02c959470da5322797dd96a19
+Date: Monday June 3 2024
+Branch: v1.14.1
+Commit: 12f3a2ac603e8f10742105519e0cd03c3b8f71dd
Description:
Contains the sources used to compile libvpx.
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 000000000..eaaa4619e
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "postsubmit": [
+ {
+ "name": "MctsMediaV2TestCases",
+ "options": [
+ {
+ "instrumentation-arg": "codec-filter:=c2\\.android\\.vp[89]"
+ }
+ ]
+ }
+ ]
+}
diff --git a/build/make/configure.sh b/build/make/configure.sh
index b645a666f..93643f3de 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -429,6 +429,40 @@ check_gcc_machine_options() {
fi
}
+check_neon_sve_bridge_compiles() {
+ if enabled sve; then
+ check_cc -march=armv8.2-a+dotprod+i8mm+sve <<EOF
+#ifndef __ARM_NEON_SVE_BRIDGE
+#error 1
+#endif
+#include <arm_sve.h>
+#include <arm_neon_sve_bridge.h>
+EOF
+ compile_result=$?
+ if [ ${compile_result} -eq 0 ]; then
+ # Check whether the compiler can compile SVE functions that require
+ # backup/restore of SVE registers according to AAPCS. Clang for Windows
+ # used to fail this, see
+ # https://github.com/llvm/llvm-project/issues/80009.
+ check_cc -march=armv8.2-a+dotprod+i8mm+sve <<EOF
+#include <arm_sve.h>
+void other(void);
+svfloat32_t func(svfloat32_t a) {
+ other();
+ return a;
+}
+EOF
+ compile_result=$?
+ fi
+
+ if [ ${compile_result} -ne 0 ]; then
+ log_echo " disabling sve: arm_neon_sve_bridge.h not supported by compiler"
+ disable_feature sve
+ RTCD_OPTIONS="${RTCD_OPTIONS}--disable-sve "
+ fi
+ fi
+}
+
check_gcc_avx512_compiles() {
if disabled gcc; then
return
@@ -980,36 +1014,18 @@ EOF
case ${toolchain} in
arm*)
soft_enable runtime_cpu_detect
- # Arm ISA extensions are treated as supersets.
- case ${tgt_isa} in
- arm64|armv8)
- for ext in ${ARCH_EXT_LIST_AARCH64}; do
- # Disable higher order extensions to simplify dependencies.
- if [ "$disable_exts" = "yes" ]; then
- if ! disabled $ext; then
- RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${ext} "
- disable_feature $ext
- fi
- elif disabled $ext; then
- disable_exts="yes"
- else
- soft_enable $ext
- fi
- done
- ;;
- armv7|armv7s)
- soft_enable neon
- # Only enable neon_asm when neon is also enabled.
- enabled neon && soft_enable neon_asm
- # If someone tries to force it through, die.
- if disabled neon && enabled neon_asm; then
- die "Disabling neon while keeping neon-asm is not supported"
- fi
- ;;
- esac
- asm_conversion_cmd="cat"
+ if [ ${tgt_isa} = "armv7" ] || [ ${tgt_isa} = "armv7s" ]; then
+ soft_enable neon
+ # Only enable neon_asm when neon is also enabled.
+ enabled neon && soft_enable neon_asm
+ # If someone tries to force it through, die.
+ if disabled neon && enabled neon_asm; then
+ die "Disabling neon while keeping neon-asm is not supported"
+ fi
+ fi
+ asm_conversion_cmd="cat"
case ${tgt_cc} in
gcc)
link_with_cc=gcc
@@ -1228,6 +1244,35 @@ EOF
fi
;;
esac
+
+ # AArch64 ISA extensions are treated as supersets.
+ if [ ${tgt_isa} = "arm64" ] || [ ${tgt_isa} = "armv8" ]; then
+ aarch64_arch_flag_neon="arch=armv8-a"
+ aarch64_arch_flag_neon_dotprod="arch=armv8.2-a+dotprod"
+ aarch64_arch_flag_neon_i8mm="arch=armv8.2-a+dotprod+i8mm"
+ aarch64_arch_flag_sve="arch=armv8.2-a+dotprod+i8mm+sve"
+ for ext in ${ARCH_EXT_LIST_AARCH64}; do
+ if [ "$disable_exts" = "yes" ]; then
+ RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${ext} "
+ soft_disable $ext
+ else
+ # Check the compiler supports the -march flag for the extension.
+ # This needs to happen after toolchain/OS inspection so we handle
+ # $CROSS etc correctly when checking for flags, else these will
+ # always fail.
+ flag="$(eval echo \$"aarch64_arch_flag_${ext}")"
+ check_gcc_machine_option "${flag}" "${ext}"
+ if ! enabled $ext; then
+ # Disable higher order extensions to simplify dependencies.
+ disable_exts="yes"
+ RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${ext} "
+ soft_disable $ext
+ fi
+ fi
+ done
+ check_neon_sve_bridge_compiles
+ fi
+
;;
mips*)
link_with_cc=gcc
diff --git a/config/arm-neon/vpx_dsp_rtcd.h b/config/arm-neon/vpx_dsp_rtcd.h
index 578f1c5dc..f0800ab88 100644
--- a/config/arm-neon/vpx_dsp_rtcd.h
+++ b/config/arm-neon/vpx_dsp_rtcd.h
@@ -1968,8 +1968,8 @@ void vpx_scaled_horiz_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
void vpx_scaled_vert_c(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);
#define vpx_scaled_vert vpx_scaled_vert_c
-int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
-int64_t vpx_sse_neon(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
+int64_t vpx_sse_c(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
+int64_t vpx_sse_neon(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
#define vpx_sse vpx_sse_neon
uint32_t vpx_sub_pixel_avg_variance16x16_c(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, const uint8_t *second_pred);
diff --git a/config/arm-neon/vpx_version.h b/config/arm-neon/vpx_version.h
index 00ab40fe2..a06c0a0f1 100644
--- a/config/arm-neon/vpx_version.h
+++ b/config/arm-neon/vpx_version.h
@@ -1,8 +1,8 @@
// This file is generated. Do not edit.
#define VERSION_MAJOR 1
#define VERSION_MINOR 14
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "1616-g26104bbc9d"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "1650-g0e5dcd1f52"
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.14.0-1616-g26104bbc9d"
-#define VERSION_STRING " v1.14.0-1616-g26104bbc9d"
+#define VERSION_STRING_NOSP "v1.14.1-1650-g0e5dcd1f52"
+#define VERSION_STRING " v1.14.1-1650-g0e5dcd1f52"
diff --git a/config/arm64/vpx_dsp_rtcd.h b/config/arm64/vpx_dsp_rtcd.h
index 578f1c5dc..f0800ab88 100644
--- a/config/arm64/vpx_dsp_rtcd.h
+++ b/config/arm64/vpx_dsp_rtcd.h
@@ -1968,8 +1968,8 @@ void vpx_scaled_horiz_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
void vpx_scaled_vert_c(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);
#define vpx_scaled_vert vpx_scaled_vert_c
-int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
-int64_t vpx_sse_neon(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
+int64_t vpx_sse_c(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
+int64_t vpx_sse_neon(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
#define vpx_sse vpx_sse_neon
uint32_t vpx_sub_pixel_avg_variance16x16_c(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, const uint8_t *second_pred);
diff --git a/config/arm64/vpx_version.h b/config/arm64/vpx_version.h
index 00ab40fe2..a06c0a0f1 100644
--- a/config/arm64/vpx_version.h
+++ b/config/arm64/vpx_version.h
@@ -1,8 +1,8 @@
// This file is generated. Do not edit.
#define VERSION_MAJOR 1
#define VERSION_MINOR 14
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "1616-g26104bbc9d"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "1650-g0e5dcd1f52"
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.14.0-1616-g26104bbc9d"
-#define VERSION_STRING " v1.14.0-1616-g26104bbc9d"
+#define VERSION_STRING_NOSP "v1.14.1-1650-g0e5dcd1f52"
+#define VERSION_STRING " v1.14.1-1650-g0e5dcd1f52"
diff --git a/config/generic/vpx_dsp_rtcd.h b/config/generic/vpx_dsp_rtcd.h
index 256cbdfa5..7f8cc7b7a 100644
--- a/config/generic/vpx_dsp_rtcd.h
+++ b/config/generic/vpx_dsp_rtcd.h
@@ -1492,7 +1492,7 @@ void vpx_scaled_horiz_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
void vpx_scaled_vert_c(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);
#define vpx_scaled_vert vpx_scaled_vert_c
-int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
+int64_t vpx_sse_c(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
#define vpx_sse vpx_sse_c
uint32_t vpx_sub_pixel_avg_variance16x16_c(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, const uint8_t *second_pred);
diff --git a/config/generic/vpx_version.h b/config/generic/vpx_version.h
index 00ab40fe2..a06c0a0f1 100644
--- a/config/generic/vpx_version.h
+++ b/config/generic/vpx_version.h
@@ -1,8 +1,8 @@
// This file is generated. Do not edit.
#define VERSION_MAJOR 1
#define VERSION_MINOR 14
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "1616-g26104bbc9d"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "1650-g0e5dcd1f52"
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.14.0-1616-g26104bbc9d"
-#define VERSION_STRING " v1.14.0-1616-g26104bbc9d"
+#define VERSION_STRING_NOSP "v1.14.1-1650-g0e5dcd1f52"
+#define VERSION_STRING " v1.14.1-1650-g0e5dcd1f52"
diff --git a/config/x86/vpx_dsp_rtcd.h b/config/x86/vpx_dsp_rtcd.h
index 67c150490..5c6993a70 100644
--- a/config/x86/vpx_dsp_rtcd.h
+++ b/config/x86/vpx_dsp_rtcd.h
@@ -1931,7 +1931,7 @@ void vpx_scaled_horiz_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
void vpx_scaled_vert_c(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);
#define vpx_scaled_vert vpx_scaled_vert_c
-int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
+int64_t vpx_sse_c(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
#define vpx_sse vpx_sse_c
uint32_t vpx_sub_pixel_avg_variance16x16_c(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, const uint8_t *second_pred);
diff --git a/config/x86/vpx_version.h b/config/x86/vpx_version.h
index 00ab40fe2..a06c0a0f1 100644
--- a/config/x86/vpx_version.h
+++ b/config/x86/vpx_version.h
@@ -1,8 +1,8 @@
// This file is generated. Do not edit.
#define VERSION_MAJOR 1
#define VERSION_MINOR 14
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "1616-g26104bbc9d"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "1650-g0e5dcd1f52"
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.14.0-1616-g26104bbc9d"
-#define VERSION_STRING " v1.14.0-1616-g26104bbc9d"
+#define VERSION_STRING_NOSP "v1.14.1-1650-g0e5dcd1f52"
+#define VERSION_STRING " v1.14.1-1650-g0e5dcd1f52"
diff --git a/config/x86_64/vpx_dsp_rtcd.h b/config/x86_64/vpx_dsp_rtcd.h
index 5eb512172..134856f05 100644
--- a/config/x86_64/vpx_dsp_rtcd.h
+++ b/config/x86_64/vpx_dsp_rtcd.h
@@ -1938,7 +1938,7 @@ void vpx_scaled_horiz_c(const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
void vpx_scaled_vert_c(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);
#define vpx_scaled_vert vpx_scaled_vert_c
-int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height);
+int64_t vpx_sse_c(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height);
#define vpx_sse vpx_sse_c
uint32_t vpx_sub_pixel_avg_variance16x16_c(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, const uint8_t *second_pred);
diff --git a/config/x86_64/vpx_version.h b/config/x86_64/vpx_version.h
index 00ab40fe2..a06c0a0f1 100644
--- a/config/x86_64/vpx_version.h
+++ b/config/x86_64/vpx_version.h
@@ -1,8 +1,8 @@
// This file is generated. Do not edit.
#define VERSION_MAJOR 1
#define VERSION_MINOR 14
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "1616-g26104bbc9d"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "1650-g0e5dcd1f52"
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.14.0-1616-g26104bbc9d"
-#define VERSION_STRING " v1.14.0-1616-g26104bbc9d"
+#define VERSION_STRING_NOSP "v1.14.1-1650-g0e5dcd1f52"
+#define VERSION_STRING " v1.14.1-1650-g0e5dcd1f52"
diff --git a/libs.mk b/libs.mk
index 596438671..70207a4a8 100644
--- a/libs.mk
+++ b/libs.mk
@@ -315,7 +315,7 @@ $(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS)
# (c1, a1, r1) and set MAJOR to [c1-a1], MINOR to a1 and PATCH to r1
SO_VERSION_MAJOR := 9
SO_VERSION_MINOR := 0
-SO_VERSION_PATCH := 0
+SO_VERSION_PATCH := 1
ifeq ($(filter darwin%,$(TGT_OS)),$(TGT_OS))
LIBVPX_SO := libvpx.$(SO_VERSION_MAJOR).dylib
SHARED_LIB_SUF := .dylib
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index a25dbc625..3bc38c537 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -8,13 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <cassert>
#include <climits>
+#include <cstdint>
#include <cstring>
#include <initializer_list>
#include <new>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "test/acm_random.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
@@ -45,6 +48,49 @@ bool IsVP9(vpx_codec_iface_t *iface) {
0;
}
+void *Memset16(void *dest, int val, size_t length) {
+ uint16_t *dest16 = reinterpret_cast<uint16_t *>(dest);
+ for (size_t i = 0; i < length; i++) {
+ *dest16++ = val;
+ }
+ return dest;
+}
+
+vpx_image_t *CreateImage(vpx_bit_depth_t bit_depth, vpx_img_fmt_t fmt,
+ unsigned int width, unsigned int height) {
+ assert(fmt != VPX_IMG_FMT_NV12);
+ if (bit_depth > VPX_BITS_8) {
+ fmt = static_cast<vpx_img_fmt_t>(fmt | VPX_IMG_FMT_HIGHBITDEPTH);
+ }
+ vpx_image_t *image = vpx_img_alloc(nullptr, fmt, width, height, 1);
+ if (!image) return image;
+
+ const int val = 1 << (bit_depth - 1);
+ const unsigned int uv_h =
+ (image->d_h + image->y_chroma_shift) >> image->y_chroma_shift;
+ const unsigned int uv_w =
+ (image->d_w + image->x_chroma_shift) >> image->x_chroma_shift;
+ if (bit_depth > VPX_BITS_8) {
+ for (unsigned int i = 0; i < image->d_h; ++i) {
+ Memset16(image->planes[0] + i * image->stride[0], val, image->d_w);
+ }
+ for (unsigned int i = 0; i < uv_h; ++i) {
+ Memset16(image->planes[1] + i * image->stride[1], val, uv_w);
+ Memset16(image->planes[2] + i * image->stride[2], val, uv_w);
+ }
+ } else {
+ for (unsigned int i = 0; i < image->d_h; ++i) {
+ memset(image->planes[0] + i * image->stride[0], val, image->d_w);
+ }
+ for (unsigned int i = 0; i < uv_h; ++i) {
+ memset(image->planes[1] + i * image->stride[1], val, uv_w);
+ memset(image->planes[2] + i * image->stride[2], val, uv_w);
+ }
+ }
+
+ return image;
+}
+
void InitCodec(vpx_codec_iface_t &iface, int width, int height,
vpx_codec_ctx_t *enc, vpx_codec_enc_cfg_t *cfg) {
cfg->g_w = width;
@@ -210,6 +256,211 @@ TEST(EncodeAPI, HugeFramerateVp8) {
ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
}
+// A test that reproduces https://crbug.com/webm/1831.
+TEST(EncodeAPI, RandomPixelsVp8) {
+ // Initialize libvpx encoder
+ vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
+ vpx_codec_enc_cfg_t cfg;
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
+
+ cfg.rc_target_bitrate = 2000;
+ cfg.g_w = 1280;
+ cfg.g_h = 720;
+
+ vpx_codec_ctx_t enc;
+ ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
+
+ // Generate random frame data and encode
+ libvpx_test::RandomVideoSource video;
+ video.SetSize(cfg.g_w, cfg.g_h);
+ video.SetImageFormat(VPX_IMG_FMT_I420);
+ video.Begin();
+ ASSERT_EQ(vpx_codec_encode(&enc, video.img(), video.pts(), video.duration(),
+ /*flags=*/0, VPX_DL_BEST_QUALITY),
+ VPX_CODEC_OK);
+
+ // Destroy libvpx encoder
+ vpx_codec_destroy(&enc);
+}
+
+TEST(EncodeAPI, ChangeToL1T3AndSetBitrateVp8) {
+ // Initialize libvpx encoder
+ vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
+ vpx_codec_enc_cfg_t cfg;
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
+
+ cfg.g_threads = 1;
+ cfg.g_profile = 0;
+ cfg.g_w = 1;
+ cfg.g_h = 64;
+ cfg.g_bit_depth = VPX_BITS_8;
+ cfg.g_input_bit_depth = 8;
+ cfg.g_timebase.num = 1;
+ cfg.g_timebase.den = 1000000;
+ cfg.g_pass = VPX_RC_ONE_PASS;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_dropframe_thresh = 0; // Don't drop frames
+ cfg.rc_resize_allowed = 0;
+ cfg.rc_end_usage = VPX_VBR;
+ cfg.rc_target_bitrate = 10;
+ cfg.rc_min_quantizer = 2;
+ cfg.rc_max_quantizer = 58;
+ cfg.kf_mode = VPX_KF_AUTO;
+ cfg.kf_min_dist = 0;
+ cfg.kf_max_dist = 10000;
+
+ vpx_codec_ctx_t enc;
+ ASSERT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), VPX_CODEC_OK);
+
+ ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK);
+
+ // Generate random frame data and encode
+ uint8_t img[1 * 64 * 3 / 2];
+ libvpx_test::ACMRandom rng;
+ for (size_t i = 0; i < sizeof(img); ++i) {
+ img[i] = rng.Rand8();
+ }
+ vpx_image_t img_wrapper;
+ ASSERT_EQ(
+ vpx_img_wrap(&img_wrapper, VPX_IMG_FMT_I420, cfg.g_w, cfg.g_h, 1, img),
+ &img_wrapper);
+ vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, &img_wrapper, 0, 500000, flags, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+ ASSERT_EQ(vpx_codec_encode(&enc, nullptr, -1, 0, 0, 0), VPX_CODEC_OK);
+
+ cfg.rc_target_bitrate = 4294967;
+ // Set the scalability mode to L1T3.
+ cfg.ts_number_layers = 3;
+ cfg.ts_periodicity = 4;
+ cfg.ts_layer_id[0] = 0;
+ cfg.ts_layer_id[1] = 2;
+ cfg.ts_layer_id[2] = 1;
+ cfg.ts_layer_id[3] = 2;
+ cfg.ts_rate_decimator[0] = 4;
+ cfg.ts_rate_decimator[1] = 2;
+ cfg.ts_rate_decimator[2] = 1;
+ // Bitrate allocation L0: 50% L1: 20% L2: 30%
+ cfg.layer_target_bitrate[0] = cfg.ts_target_bitrate[0] =
+ 50 * cfg.rc_target_bitrate / 100;
+ cfg.layer_target_bitrate[1] = cfg.ts_target_bitrate[1] =
+ 70 * cfg.rc_target_bitrate / 100;
+ cfg.layer_target_bitrate[2] = cfg.ts_target_bitrate[2] =
+ cfg.rc_target_bitrate;
+ cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212;
+ cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
+ ASSERT_EQ(vpx_codec_enc_config_set(&enc, &cfg), VPX_CODEC_OK);
+
+ ASSERT_EQ(vpx_codec_control(&enc, VP8E_SET_TEMPORAL_LAYER_ID, 2),
+ VPX_CODEC_OK);
+
+ constexpr vpx_enc_frame_flags_t VP8_UPDATE_NOTHING =
+ VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
+ // Layer 2: only reference last frame, no updates
+ // It only depends on layer 0
+ flags = VP8_UPDATE_NOTHING | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF;
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, &img_wrapper, 0, 500000, flags, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+
+ // Destroy libvpx encoder
+ vpx_codec_destroy(&enc);
+}
+
+// Emulates the WebCodecs VideoEncoder interface.
+class VP8Encoder {
+ public:
+ explicit VP8Encoder(int speed) : speed_(speed) {}
+ ~VP8Encoder();
+
+ void Configure(unsigned int threads, unsigned int width, unsigned int height,
+ vpx_rc_mode end_usage, unsigned long deadline);
+ void Encode(bool key_frame);
+
+ private:
+ const int speed_;
+ bool initialized_ = false;
+ vpx_codec_enc_cfg_t cfg_;
+ vpx_codec_ctx_t enc_;
+ int frame_index_ = 0;
+ unsigned long deadline_ = 0;
+};
+
+VP8Encoder::~VP8Encoder() {
+ if (initialized_) {
+ EXPECT_EQ(vpx_codec_destroy(&enc_), VPX_CODEC_OK);
+ }
+}
+
+void VP8Encoder::Configure(unsigned int threads, unsigned int width,
+ unsigned int height, vpx_rc_mode end_usage,
+ unsigned long deadline) {
+ deadline_ = deadline;
+
+ if (!initialized_) {
+ vpx_codec_iface_t *const iface = vpx_codec_vp8_cx();
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg_, /*usage=*/0),
+ VPX_CODEC_OK);
+ cfg_.g_threads = threads;
+ cfg_.g_w = width;
+ cfg_.g_h = height;
+ cfg_.g_timebase.num = 1;
+ cfg_.g_timebase.den = 1000 * 1000; // microseconds
+ cfg_.g_pass = VPX_RC_ONE_PASS;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.rc_end_usage = end_usage;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 58;
+ ASSERT_EQ(vpx_codec_enc_init(&enc_, iface, &cfg_, 0), VPX_CODEC_OK);
+ ASSERT_EQ(vpx_codec_control(&enc_, VP8E_SET_CPUUSED, speed_), VPX_CODEC_OK);
+ initialized_ = true;
+ return;
+ }
+
+ cfg_.g_threads = threads;
+ cfg_.g_w = width;
+ cfg_.g_h = height;
+ cfg_.rc_end_usage = end_usage;
+ ASSERT_EQ(vpx_codec_enc_config_set(&enc_, &cfg_), VPX_CODEC_OK)
+ << vpx_codec_error_detail(&enc_);
+}
+
+void VP8Encoder::Encode(bool key_frame) {
+ assert(initialized_);
+ const vpx_codec_cx_pkt_t *pkt;
+ vpx_image_t *image =
+ CreateImage(VPX_BITS_8, VPX_IMG_FMT_I420, cfg_.g_w, cfg_.g_h);
+ ASSERT_NE(image, nullptr);
+ const vpx_enc_frame_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
+ ASSERT_EQ(vpx_codec_encode(&enc_, image, frame_index_, 1, flags, deadline_),
+ VPX_CODEC_OK);
+ ++frame_index_;
+ vpx_codec_iter_t iter = nullptr;
+ while ((pkt = vpx_codec_get_cx_data(&enc_, &iter)) != nullptr) {
+ ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
+ if (key_frame) {
+ ASSERT_EQ(pkt->data.frame.flags & VPX_FRAME_IS_KEY, VPX_FRAME_IS_KEY);
+ }
+ }
+ vpx_img_free(image);
+}
+
+// This is the reproducer testcase for crbug.com/324459561. However,
+// just running this test is not enough to reproduce the bug. We also
+// need to send signals to the test.
+TEST(EncodeAPI, Chromium324459561) {
+ VP8Encoder encoder(-12);
+
+ encoder.Configure(11, 1685, 652, VPX_CBR, VPX_DL_REALTIME);
+
+ encoder.Encode(true);
+ encoder.Encode(true);
+ encoder.Encode(true);
+
+ encoder.Configure(0, 1685, 1, VPX_VBR, VPX_DL_REALTIME);
+}
+
TEST(EncodeAPI, VP8GlobalHeaders) {
constexpr int kWidth = 320;
constexpr int kHeight = 240;
@@ -228,6 +479,79 @@ TEST(EncodeAPI, VP8GlobalHeaders) {
EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc.ctx));
EXPECT_EQ(vpx_codec_get_global_headers(&enc.ctx), nullptr);
}
+
+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;
+
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
+
+ cfg.g_w = 1920;
+ cfg.g_h = 1080;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_target_bitrate = 1000000;
+ // Set this to more than 1 percent to cause a signed integer overflow in the
+ // multiplication cpi->av_per_frame_bandwidth *
+ // cpi->oxcf.two_pass_vbrmin_section in vp8_new_framerate() if the
+ // multiplication is done in the `int` type.
+ cfg.rc_2pass_vbr_minsection_pct = 2;
+
+ 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 frame.
+ // `duration` can go as high as 300, but the UBSan error is gone if
+ // `duration` is 301 or higher.
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+
+ // Free resources.
+ vpx_img_free(image);
+ ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
+
+TEST(EncodeAPI, AomediaIssue3509VbrMinSection101PercentVP8) {
+ // 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 = 1920;
+ cfg.g_h = 1080;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_target_bitrate = 1000000;
+ // Set this to more than 100 percent to cause an error when vbr_min_bits is
+ // cast to `int` in vp8_new_framerate() if vbr_min_bits is not clamped to
+ // INT_MAX.
+ cfg.rc_2pass_vbr_minsection_pct = 101;
+
+ 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 frame.
+ // `duration` can go as high as 300, but the UBSan error is gone if
+ // `duration` is 301 or higher.
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+
+ // Free resources.
+ vpx_img_free(image);
+ ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
#endif // CONFIG_VP8_ENCODER
// Set up 2 spatial streams with 2 temporal layers per stream, and generate
@@ -488,6 +812,48 @@ TEST(EncodeAPI, ConfigResizeChangeThreadCount) {
}
}
+TEST(EncodeAPI, ConfigResizeBiggerAfterInit) {
+ for (const auto *iface : kCodecIfaces) {
+ SCOPED_TRACE(vpx_codec_iface_name(iface));
+ vpx_codec_enc_cfg_t cfg;
+ vpx_codec_ctx_t enc;
+
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
+ EXPECT_NO_FATAL_FAILURE(InitCodec(*iface, 1, 1, &enc, &cfg));
+
+ cfg.g_w = 1920;
+ cfg.g_h = 1;
+ EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
+ IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
+
+ EXPECT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+ }
+}
+
+TEST(EncodeAPI, ConfigResizeBiggerAfterEncode) {
+ for (const auto *iface : kCodecIfaces) {
+ SCOPED_TRACE(vpx_codec_iface_name(iface));
+ vpx_codec_enc_cfg_t cfg;
+ vpx_codec_ctx_t enc;
+
+ ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg, 0), VPX_CODEC_OK);
+ EXPECT_NO_FATAL_FAILURE(InitCodec(*iface, 1, 1, &enc, &cfg));
+ EXPECT_NO_FATAL_FAILURE(EncodeWithConfig(cfg, &enc));
+
+ cfg.g_w = 1920;
+ cfg.g_h = 1;
+ EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
+ IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
+
+ cfg.g_w = 1920;
+ cfg.g_h = 1080;
+ EXPECT_EQ(vpx_codec_enc_config_set(&enc, &cfg),
+ IsVP9(iface) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM);
+
+ EXPECT_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
@@ -517,28 +883,18 @@ TEST(EncodeAPI, ConfigLargeTargetBitrateVp9) {
}
#endif // VPX_ARCH_X86_64 || VPX_ARCH_AARCH64
-vpx_image_t *CreateImage(const unsigned int width, const unsigned int height) {
- vpx_image_t *image =
- vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, width, height, 1);
- if (!image) return image;
-
- for (unsigned int i = 0; i < image->d_h; ++i) {
- memset(image->planes[0] + i * image->stride[0], 128, image->d_w);
- }
- const unsigned int uv_h = (image->d_h + 1) / 2;
- const unsigned int uv_w = (image->d_w + 1) / 2;
- for (unsigned int i = 0; i < uv_h; ++i) {
- memset(image->planes[1] + i * image->stride[1], 128, uv_w);
- memset(image->planes[2] + i * image->stride[2], 128, uv_w);
- }
-
- return image;
-}
-
// Emulates the WebCodecs VideoEncoder interface.
class VP9Encoder {
public:
- VP9Encoder(int speed) : speed_(speed) {}
+ explicit VP9Encoder(int speed)
+ : speed_(speed), row_mt_(0), bit_depth_(VPX_BITS_8),
+ fmt_(VPX_IMG_FMT_I420) {}
+ // The image format `fmt` must not have the VPX_IMG_FMT_HIGHBITDEPTH bit set.
+ // If bit_depth > 8, we will set the VPX_IMG_FMT_HIGHBITDEPTH bit before
+ // passing the image format to vpx_img_alloc().
+ VP9Encoder(int speed, unsigned int row_mt, vpx_bit_depth_t bit_depth,
+ vpx_img_fmt_t fmt)
+ : speed_(speed), row_mt_(row_mt), bit_depth_(bit_depth), fmt_(fmt) {}
~VP9Encoder();
void Configure(unsigned int threads, unsigned int width, unsigned int height,
@@ -547,6 +903,9 @@ class VP9Encoder {
private:
const int speed_;
+ const unsigned int row_mt_;
+ const vpx_bit_depth_t bit_depth_;
+ const vpx_img_fmt_t fmt_;
bool initialized_ = false;
vpx_codec_enc_cfg_t cfg_;
vpx_codec_ctx_t enc_;
@@ -566,12 +925,22 @@ void VP9Encoder::Configure(unsigned int threads, unsigned int width,
deadline_ = deadline;
if (!initialized_) {
+ ASSERT_EQ(fmt_ & VPX_IMG_FMT_HIGHBITDEPTH, 0);
+ const bool high_bit_depth = bit_depth_ > VPX_BITS_8;
+ const bool is_420 = fmt_ == VPX_IMG_FMT_I420;
vpx_codec_iface_t *const iface = vpx_codec_vp9_cx();
ASSERT_EQ(vpx_codec_enc_config_default(iface, &cfg_, /*usage=*/0),
VPX_CODEC_OK);
cfg_.g_threads = threads;
+ // In profiles 0 and 2, only 4:2:0 format is allowed. In profiles 1 and 3,
+ // all other subsampling formats are allowed. In profiles 0 and 1, only bit
+ // depth 8 is allowed. In profiles 2 and 3, only bit depths 10 and 12 are
+ // allowed.
+ cfg_.g_profile = 2 * high_bit_depth + !is_420;
cfg_.g_w = width;
cfg_.g_h = height;
+ cfg_.g_bit_depth = bit_depth_;
+ cfg_.g_input_bit_depth = bit_depth_;
cfg_.g_timebase.num = 1;
cfg_.g_timebase.den = 1000 * 1000; // microseconds
cfg_.g_pass = VPX_RC_ONE_PASS;
@@ -579,8 +948,12 @@ void VP9Encoder::Configure(unsigned int threads, unsigned int width,
cfg_.rc_end_usage = end_usage;
cfg_.rc_min_quantizer = 2;
cfg_.rc_max_quantizer = 58;
- ASSERT_EQ(vpx_codec_enc_init(&enc_, iface, &cfg_, 0), VPX_CODEC_OK);
+ ASSERT_EQ(
+ vpx_codec_enc_init(&enc_, iface, &cfg_,
+ high_bit_depth ? VPX_CODEC_USE_HIGHBITDEPTH : 0),
+ VPX_CODEC_OK);
ASSERT_EQ(vpx_codec_control(&enc_, VP8E_SET_CPUUSED, speed_), VPX_CODEC_OK);
+ ASSERT_EQ(vpx_codec_control(&enc_, VP9E_SET_ROW_MT, row_mt_), VPX_CODEC_OK);
initialized_ = true;
return;
}
@@ -594,14 +967,15 @@ void VP9Encoder::Configure(unsigned int threads, unsigned int width,
}
void VP9Encoder::Encode(bool key_frame) {
+ assert(initialized_);
const vpx_codec_cx_pkt_t *pkt;
- vpx_image_t *image = CreateImage(cfg_.g_w, cfg_.g_h);
+ vpx_image_t *image = CreateImage(bit_depth_, fmt_, cfg_.g_w, cfg_.g_h);
ASSERT_NE(image, nullptr);
const vpx_enc_frame_flags_t frame_flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
ASSERT_EQ(
vpx_codec_encode(&enc_, image, frame_index_, 1, frame_flags, deadline_),
VPX_CODEC_OK);
- frame_index_++;
+ ++frame_index_;
vpx_codec_iter_t iter = nullptr;
while ((pkt = vpx_codec_get_cx_data(&enc_, &iter)) != nullptr) {
ASSERT_EQ(pkt->kind, VPX_CODEC_CX_FRAME_PKT);
@@ -934,6 +1308,166 @@ TEST(EncodeAPI, Buganizer311294795) {
encoder.Encode(false);
}
+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);
+}
+
+TEST(EncodeAPI, Buganizer319964497) {
+ VP9Encoder encoder(7);
+ encoder.Configure(/*threads=*/1, /*width=*/320, /*height=*/240, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/1, /*width=*/2, /*height=*/2, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+}
+
+TEST(EncodeAPI, Buganizer329088759RowMT0) {
+ VP9Encoder encoder(8, 0, VPX_BITS_8, VPX_IMG_FMT_I444);
+ encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/0, /*width=*/1686, /*height=*/1, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/0, /*width=*/1482, /*height=*/113, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/0, /*width=*/881, /*height=*/59, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
+ VPX_DL_REALTIME);
+}
+
+TEST(EncodeAPI, Buganizer329088759RowMT1) {
+ VP9Encoder encoder(8, 1, VPX_BITS_8, VPX_IMG_FMT_I444);
+ encoder.Configure(/*threads=*/8, /*width=*/1686, /*height=*/398, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Encode(/*key_frame=*/false);
+ // Needs to set threads to non-zero to repro the issue.
+ encoder.Configure(/*threads=*/2, /*width=*/1686, /*height=*/1, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/2, /*width=*/1482, /*height=*/113, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/2, /*width=*/881, /*height=*/59, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Configure(/*threads=*/13, /*width=*/1271, /*height=*/385, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/2, /*width=*/1, /*height=*/62, VPX_VBR,
+ VPX_DL_REALTIME);
+}
+
+TEST(EncodeAPI, Buganizer331086799) {
+ VP9Encoder encoder(6, 1, VPX_BITS_8, VPX_IMG_FMT_I420);
+ encoder.Configure(0, 1385, 1, VPX_CBR, VPX_DL_REALTIME);
+ encoder.Configure(0, 1, 1, VPX_VBR, VPX_DL_REALTIME);
+ encoder.Encode(false);
+ encoder.Configure(16, 1385, 1, VPX_VBR, VPX_DL_GOOD_QUALITY);
+ encoder.Encode(false);
+ encoder.Encode(false);
+ encoder.Configure(0, 1, 1, VPX_CBR, VPX_DL_REALTIME);
+ encoder.Encode(true);
+}
+
+TEST(EncodeAPI, Buganizer331108729) {
+ VP9Encoder encoder(1, 1, VPX_BITS_8, VPX_IMG_FMT_I422);
+ encoder.Configure(0, 1919, 260, VPX_VBR, VPX_DL_REALTIME);
+ encoder.Configure(9, 440, 1, VPX_CBR, VPX_DL_GOOD_QUALITY);
+ encoder.Encode(true);
+ encoder.Configure(8, 1919, 260, VPX_VBR, VPX_DL_REALTIME);
+ encoder.Encode(false);
+}
+
+TEST(EncodeAPI, Buganizer331108922BitDepth8) {
+ VP9Encoder encoder(9, 1, VPX_BITS_8, VPX_IMG_FMT_I420);
+ encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1080, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/0, /*width=*/1, /*height=*/1080, VPX_CBR,
+ VPX_DL_GOOD_QUALITY);
+ encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/394, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/798, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+}
+
+#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);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/0, /*width=*/1030, /*height=*/1, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/0, /*width=*/548, /*height=*/322, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/16, /*width=*/24, /*height=*/583, VPX_CBR,
+ VPX_DL_GOOD_QUALITY);
+}
+
+TEST(EncodeAPI, Buganizer329179808RowMT0BitDepth10) {
+ VP9Encoder encoder(4, 0, VPX_BITS_10, VPX_IMG_FMT_I444);
+ encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+}
+
+TEST(EncodeAPI, Buganizer329179808RowMT1BitDepth10) {
+ VP9Encoder encoder(4, 1, VPX_BITS_10, VPX_IMG_FMT_I444);
+ encoder.Configure(/*threads=*/16, /*width=*/1488, /*height=*/5, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/16, /*width=*/839, /*height=*/1, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/11, /*width=*/657, /*height=*/5, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+}
+
+TEST(EncodeAPI, Buganizer331108922BitDepth12) {
+ VP9Encoder encoder(9, 1, VPX_BITS_12, VPX_IMG_FMT_I444);
+ encoder.Configure(/*threads=*/1, /*width=*/1, /*height=*/1080, VPX_VBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Configure(/*threads=*/0, /*width=*/1, /*height=*/1080, VPX_CBR,
+ VPX_DL_GOOD_QUALITY);
+ encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/394, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+ encoder.Encode(/*key_frame=*/true);
+ encoder.Configure(/*threads=*/16, /*width=*/1, /*height=*/798, VPX_CBR,
+ VPX_DL_REALTIME);
+ encoder.Encode(/*key_frame=*/false);
+}
+#endif
+
TEST(EncodeAPI, VP9GlobalHeaders) {
constexpr int kWidth = 320;
constexpr int kHeight = 240;
@@ -1049,6 +1583,78 @@ TEST(EncodeAPI, VP9GlobalHeaders) {
}
}
+TEST(EncodeAPI, AomediaIssue3509VbrMinSection2PercentVP9) {
+ // Initialize libvpx encoder.
+ 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 = 1920;
+ cfg.g_h = 1080;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_target_bitrate = 1000000;
+ // Set this to more than 1 percent to cause a signed integer overflow in the
+ // multiplication rc->avg_frame_bandwidth * oxcf->rc_cfg.vbrmin_section in
+ // vp9_rc_update_framerate() if the multiplication is done in the `int` type.
+ cfg.rc_2pass_vbr_minsection_pct = 2;
+
+ 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 frame.
+ // `duration` can go as high as 300, but the UBSan error is gone if
+ // `duration` is 301 or higher.
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+
+ // Free resources.
+ vpx_img_free(image);
+ ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
+
+TEST(EncodeAPI, AomediaIssue3509VbrMinSection101PercentVP9) {
+ // Initialize libvpx encoder.
+ 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 = 1920;
+ cfg.g_h = 1080;
+ cfg.g_lag_in_frames = 0;
+ cfg.rc_target_bitrate = 1000000;
+ // Set this to more than 100 percent to cause an error when vbr_min_bits is
+ // cast to `int` in vp9_rc_update_framerate() if vbr_min_bits is not clamped
+ // to INT_MAX.
+ cfg.rc_2pass_vbr_minsection_pct = 101;
+
+ 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 frame.
+ // `duration` can go as high as 300, but the UBSan error is gone if
+ // `duration` is 301 or higher.
+ ASSERT_EQ(
+ vpx_codec_encode(&enc, image, 0, /*duration=*/300, 0, VPX_DL_REALTIME),
+ VPX_CODEC_OK);
+
+ // Free resources.
+ vpx_img_free(image);
+ ASSERT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK);
+}
+
#endif // CONFIG_VP9_ENCODER
} // namespace
diff --git a/test/sum_squares_test.cc b/test/sum_squares_test.cc
index 725d5eb85..d3c76a34d 100644
--- a/test/sum_squares_test.cc
+++ b/test/sum_squares_test.cc
@@ -9,6 +9,7 @@
*/
#include <cmath>
+#include <cstdint>
#include <cstdlib>
#include <string>
#include <tuple>
diff --git a/test/test.mk b/test/test.mk
index d4521f08b..fa5bf5633 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -21,6 +21,7 @@ LIBVPX_TEST_SRCS-yes += video_source.h
## Black box tests only use the public API.
##
LIBVPX_TEST_SRCS-yes += ../md5_utils.h ../md5_utils.c
+LIBVPX_TEST_SRCS-yes += vpx_image_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += ../y4minput.h ../y4minput.c
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += altref_test.cc
diff --git a/test/video_source.h b/test/video_source.h
index 2194126f1..2c035910d 100644
--- a/test/video_source.h
+++ b/test/video_source.h
@@ -236,7 +236,6 @@ class RandomVideoSource : public DummyVideoSource {
RandomVideoSource(int seed = ACMRandom::DeterministicSeed())
: rnd_(seed), seed_(seed) {}
- protected:
// Reset the RNG to get a matching stream for the second pass
void Begin() override {
frame_ = 0;
@@ -244,6 +243,7 @@ class RandomVideoSource : public DummyVideoSource {
FillFrame();
}
+ protected:
// 15 frames of noise, followed by 15 static frames. Reset to 0 rather
// than holding previous frames to encourage keyframes to be thrown.
void FillFrame() override {
diff --git a/test/vp8_datarate_test.cc b/test/vp8_datarate_test.cc
index aee27af66..f7225bb3d 100644
--- a/test/vp8_datarate_test.cc
+++ b/test/vp8_datarate_test.cc
@@ -260,6 +260,27 @@ class DatarateTestLarge
<< " 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;
+ init_flags_ = VPX_CODEC_USE_PSNR;
+
+ ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
+ 1280, 720, 30, 1, 0, 30);
+ cfg_.rc_target_bitrate = 1000;
+ ResetModel();
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.5)
+ << " The datarate for the file exceeds the target!";
+
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 2.0)
+ << " The datarate for the file missed the target!";
+ }
+
vpx_codec_pts_t last_pts_;
int64_t bits_in_buffer_model_;
double timebase_;
@@ -324,6 +345,8 @@ TEST_P(DatarateTestRealTime, DropFramesMultiThreads) {
DropFramesMultiThreadsTest();
}
+TEST_P(DatarateTestRealTime, MultiThreadsPSNR) { MultiThreadsPSNRTest(); }
+
TEST_P(DatarateTestRealTime, RegionOfInterest) {
denoiser_on_ = 0;
cfg_.rc_buf_initial_sz = 500;
diff --git a/test/vp9_boolcoder_test.cc b/test/vp9_boolcoder_test.cc
index 6ba171a00..aeff0d7a5 100644
--- a/test/vp9_boolcoder_test.cc
+++ b/test/vp9_boolcoder_test.cc
@@ -53,7 +53,7 @@ TEST(VP9, TestBitIO) {
ACMRandom bit_rnd(random_seed);
vpx_writer bw;
uint8_t bw_buffer[kBufferSize];
- vpx_start_encode(&bw, bw_buffer);
+ vpx_start_encode(&bw, bw_buffer, sizeof(bw_buffer));
int bit = (bit_method == 0) ? 0 : (bit_method == 1) ? 1 : 0;
for (int i = 0; i < kBitsToTest; ++i) {
@@ -65,7 +65,7 @@ TEST(VP9, TestBitIO) {
vpx_write(&bw, bit, static_cast<int>(probas[i]));
}
- vpx_stop_encode(&bw);
+ GTEST_ASSERT_EQ(vpx_stop_encode(&bw), 0);
// vpx_reader_fill() may read into uninitialized data that
// isn't used meaningfully, but may trigger an MSan warning.
memset(bw_buffer + bw.pos, 0, sizeof(BD_VALUE) - 1);
@@ -90,3 +90,24 @@ TEST(VP9, TestBitIO) {
}
}
}
+
+TEST(VP9, TestBitIOBufferSize0) {
+ vpx_writer bw;
+ uint8_t bw_buffer[1];
+ vpx_start_encode(&bw, bw_buffer, 0);
+ GTEST_ASSERT_EQ(vpx_stop_encode(&bw), -1);
+}
+
+TEST(VP9, TestBitIOBufferSize1) {
+ vpx_writer bw;
+ uint8_t bw_buffer[1];
+ vpx_start_encode(&bw, bw_buffer, sizeof(bw_buffer));
+ GTEST_ASSERT_EQ(vpx_stop_encode(&bw), -1);
+}
+
+TEST(VP9, TestBitIOBufferSize2) {
+ vpx_writer bw;
+ uint8_t bw_buffer[2];
+ vpx_start_encode(&bw, bw_buffer, sizeof(bw_buffer));
+ GTEST_ASSERT_EQ(vpx_stop_encode(&bw), 0);
+}
diff --git a/test/vp9_scale_test.cc b/test/vp9_scale_test.cc
index 049a10a61..a5a18a7e9 100644
--- a/test/vp9_scale_test.cc
+++ b/test/vp9_scale_test.cc
@@ -48,12 +48,11 @@ class ScaleTest : public VpxScaleBase,
}
void RunTest(INTERP_FILTER filter_type) {
- static const int kNumSizesToTest = 20;
+ static const int kNumSizesToTest = 22;
static const int kNumScaleFactorsToTest = 4;
- static const int kSizesToTest[] = {
- 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
- 22, 24, 26, 28, 30, 32, 34, 68, 128, 134
- };
+ static const int kSizesToTest[] = { 1, 2, 3, 4, 6, 8, 10, 12,
+ 14, 16, 18, 20, 22, 24, 26, 28,
+ 30, 32, 34, 68, 128, 134 };
static const int kScaleFactors[] = { 1, 2, 3, 4 };
for (int phase_scaler = 0; phase_scaler < 16; ++phase_scaler) {
for (int h = 0; h < kNumSizesToTest; ++h) {
diff --git a/test/vpx_image_test.cc b/test/vpx_image_test.cc
new file mode 100644
index 000000000..3d24b239a
--- /dev/null
+++ b/test/vpx_image_test.cc
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2024 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 <climits>
+
+#include "vpx/vpx_image.h"
+#include "third_party/googletest/src/include/gtest/gtest.h"
+
+TEST(VpxImageTest, VpxImgWrapInvalidAlign) {
+ const int kWidth = 128;
+ const int kHeight = 128;
+ unsigned char buf[kWidth * kHeight * 3];
+
+ vpx_image_t img;
+ // Set img_data and img_data_owner to junk values. vpx_img_wrap() should
+ // not read these values on failure.
+ unsigned char empty[] = "";
+ img.img_data = empty;
+ img.img_data_owner = 1;
+
+ vpx_img_fmt_t format = VPX_IMG_FMT_I444;
+ // 'align' must be a power of 2 but is not. This causes the vpx_img_wrap()
+ // call to fail. The test verifies we do not read the junk values in 'img'.
+ unsigned int align = 31;
+ EXPECT_EQ(vpx_img_wrap(&img, format, kWidth, kHeight, align, buf), nullptr);
+}
+
+TEST(VpxImageTest, VpxImgSetRectOverflow) {
+ const int kWidth = 128;
+ const int kHeight = 128;
+ unsigned char buf[kWidth * kHeight * 3];
+
+ vpx_image_t img;
+ vpx_img_fmt_t format = VPX_IMG_FMT_I444;
+ unsigned int align = 32;
+ EXPECT_EQ(vpx_img_wrap(&img, format, kWidth, kHeight, align, buf), &img);
+
+ EXPECT_EQ(vpx_img_set_rect(&img, 0, 0, kWidth, kHeight), 0);
+ // This would result in overflow because -1 is cast to UINT_MAX.
+ EXPECT_NE(vpx_img_set_rect(&img, static_cast<unsigned int>(-1),
+ static_cast<unsigned int>(-1), kWidth, kHeight),
+ 0);
+}
+
+TEST(VpxImageTest, VpxImgAllocNone) {
+ const int kWidth = 128;
+ const int kHeight = 128;
+
+ vpx_image_t img;
+ vpx_img_fmt_t format = VPX_IMG_FMT_NONE;
+ unsigned int align = 32;
+ ASSERT_EQ(vpx_img_alloc(&img, format, kWidth, kHeight, align), nullptr);
+}
+
+TEST(VpxImageTest, VpxImgAllocNv12) {
+ const int kWidth = 128;
+ const int kHeight = 128;
+
+ vpx_image_t img;
+ vpx_img_fmt_t format = VPX_IMG_FMT_NV12;
+ unsigned int align = 32;
+ EXPECT_EQ(vpx_img_alloc(&img, format, kWidth, kHeight, align), &img);
+ EXPECT_EQ(img.stride[VPX_PLANE_U], img.stride[VPX_PLANE_Y]);
+ EXPECT_EQ(img.stride[VPX_PLANE_V], img.stride[VPX_PLANE_U]);
+ EXPECT_EQ(img.planes[VPX_PLANE_V], img.planes[VPX_PLANE_U] + 1);
+ vpx_img_free(&img);
+}
+
+TEST(VpxImageTest, VpxImgAllocHugeWidth) {
+ // The stride (0x80000000 * 2) would overflow unsigned int.
+ vpx_image_t *image =
+ vpx_img_alloc(nullptr, VPX_IMG_FMT_I42016, 0x80000000, 1, 1);
+ ASSERT_EQ(image, nullptr);
+
+ // The stride (0x80000000) would overflow int.
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, 0x80000000, 1, 1);
+ ASSERT_EQ(image, nullptr);
+
+ // The aligned width (UINT_MAX + 1) would overflow unsigned int.
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, UINT_MAX, 1, 1);
+ ASSERT_EQ(image, nullptr);
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, 0x7ffffffe, 1, 1);
+ if (image) {
+ vpx_img_free(image);
+ }
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, 285245883, 64, 1);
+ if (image) {
+ vpx_img_free(image);
+ }
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_NV12, 285245883, 64, 1);
+ if (image) {
+ vpx_img_free(image);
+ }
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_YV12, 285245883, 64, 1);
+ if (image) {
+ vpx_img_free(image);
+ }
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I42016, 65536, 2, 1);
+ if (image) {
+ uint16_t *y_plane =
+ reinterpret_cast<uint16_t *>(image->planes[VPX_PLANE_Y]);
+ y_plane[0] = 0;
+ y_plane[image->d_w - 1] = 0;
+ vpx_img_free(image);
+ }
+
+ image = vpx_img_alloc(nullptr, VPX_IMG_FMT_I42016, 285245883, 2, 1);
+ if (image) {
+ uint16_t *y_plane =
+ reinterpret_cast<uint16_t *>(image->planes[VPX_PLANE_Y]);
+ y_plane[0] = 0;
+ y_plane[image->d_w - 1] = 0;
+ vpx_img_free(image);
+ }
+}
diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c
index 6ccb080cf..f7f5ebea8 100644
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <errno.h>
+
#include "vpx_config.h"
#include "vp8_rtcd.h"
#if !defined(_WIN32) && CONFIG_OS_SUPPORT == 1
@@ -892,16 +894,23 @@ int vp8mt_decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd) {
// Wait for other threads to finish. This prevents other threads decoding
// the current frame while the main thread starts decoding the next frame,
// which causes a data race.
- for (i = 0; i < pbi->decoding_thread_count; ++i)
- sem_wait(&pbi->h_event_end_decoding);
+ for (i = 0; i < pbi->decoding_thread_count; ++i) {
+ errno = 0;
+ while (sem_wait(&pbi->h_event_end_decoding) != 0 && errno == EINTR) {
+ }
+ }
return -1;
}
xd->error_info.setjmp = 1;
mt_decode_mb_rows(pbi, xd, 0);
- for (i = 0; i < pbi->decoding_thread_count + 1; ++i)
- sem_wait(&pbi->h_event_end_decoding); /* add back for each frame */
+ for (i = 0; i < pbi->decoding_thread_count + 1; ++i) {
+ /* add back for each frame */
+ errno = 0;
+ while (sem_wait(&pbi->h_event_end_decoding) != 0 && errno == EINTR) {
+ }
+ }
return 0;
}
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c
index 5c973940e..e3960de90 100644
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -7,6 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <errno.h>
#include <stdio.h>
#include <limits.h>
@@ -447,13 +448,21 @@ static void encode_mb_row(VP8_COMP *cpi, VP8_COMMON *cm, int mb_row,
x->active_ptr = cpi->active_map + map_index + mb_col;
if (cm->frame_type == KEY_FRAME) {
- *totalrate += vp8cx_encode_intra_macroblock(cpi, x, tp);
+ const int intra_rate_cost = vp8cx_encode_intra_macroblock(cpi, x, tp);
+ if (INT_MAX - *totalrate > intra_rate_cost)
+ *totalrate += intra_rate_cost;
+ else
+ *totalrate = INT_MAX;
#ifdef MODE_STATS
y_modes[xd->mbmi.mode]++;
#endif
} else {
- *totalrate += vp8cx_encode_inter_macroblock(
+ const int inter_rate_cost = vp8cx_encode_inter_macroblock(
cpi, x, tp, recon_yoffset, recon_uvoffset, mb_row, mb_col);
+ if (INT_MAX - *totalrate > inter_rate_cost)
+ *totalrate += inter_rate_cost;
+ else
+ *totalrate = INT_MAX;
#ifdef MODE_STATS
inter_y_modes[xd->mbmi.mode]++;
@@ -798,7 +807,9 @@ void vp8_encode_frame(VP8_COMP *cpi) {
}
/* Wait for all the threads to finish. */
for (i = 0; i < cpi->encoding_thread_count; ++i) {
- sem_wait(&cpi->h_event_end_encoding[i]);
+ errno = 0;
+ while (sem_wait(&cpi->h_event_end_encoding[i]) != 0 && errno == EINTR) {
+ }
}
for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) {
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 4e128e3c4..cb64aca31 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -55,6 +55,7 @@
#endif
#include <assert.h>
+#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <limits.h>
@@ -267,7 +268,11 @@ static int rescale(int val, int num, int denom) {
int64_t llden = denom;
int64_t llval = val;
- return (int)(llval * llnum / llden);
+ int64_t result = (llval * llnum / llden);
+ if (result <= INT_MAX)
+ return (int)result;
+ else
+ return INT_MAX;
}
void vp8_init_temporal_layer_context(VP8_COMP *cpi, const VP8_CONFIG *oxcf,
@@ -276,7 +281,10 @@ void vp8_init_temporal_layer_context(VP8_COMP *cpi, const VP8_CONFIG *oxcf,
LAYER_CONTEXT *lc = &cpi->layer_context[layer];
lc->framerate = cpi->output_framerate / cpi->oxcf.rate_decimator[layer];
- lc->target_bandwidth = cpi->oxcf.target_bitrate[layer] * 1000;
+ if (cpi->oxcf.target_bitrate[layer] > INT_MAX / 1000)
+ lc->target_bandwidth = INT_MAX;
+ else
+ lc->target_bandwidth = cpi->oxcf.target_bitrate[layer] * 1000;
lc->starting_buffer_level_in_ms = oxcf->starting_buffer_level;
lc->optimal_buffer_level_in_ms = oxcf->optimal_buffer_level;
@@ -1259,11 +1267,13 @@ void vp8_new_framerate(VP8_COMP *cpi, double framerate) {
cpi->framerate = framerate;
cpi->output_framerate = framerate;
- cpi->per_frame_bandwidth =
- (int)round(cpi->oxcf.target_bandwidth / cpi->output_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);
cpi->av_per_frame_bandwidth = cpi->per_frame_bandwidth;
- cpi->min_frame_bandwidth = (int)(cpi->av_per_frame_bandwidth *
- cpi->oxcf.two_pass_vbrmin_section / 100);
+ const int64_t vbr_min_bits = (int64_t)cpi->av_per_frame_bandwidth *
+ cpi->oxcf.two_pass_vbrmin_section / 100;
+ cpi->min_frame_bandwidth = (int)VPXMIN(vbr_min_bits, INT_MAX);
/* Set Maximum gf/arf interval */
cpi->max_gf_interval = ((int)(cpi->output_framerate / 2.0) + 2);
@@ -1381,7 +1391,10 @@ void vp8_update_layer_contexts(VP8_COMP *cpi) {
LAYER_CONTEXT *lc = &cpi->layer_context[i];
lc->framerate = cpi->ref_framerate / oxcf->rate_decimator[i];
- lc->target_bandwidth = oxcf->target_bitrate[i] * 1000;
+ if (oxcf->target_bitrate[i] > INT_MAX / 1000)
+ lc->target_bandwidth = INT_MAX;
+ else
+ lc->target_bandwidth = oxcf->target_bitrate[i] * 1000;
lc->starting_buffer_level = rescale(
(int)oxcf->starting_buffer_level_in_ms, lc->target_bandwidth, 1000);
@@ -3339,10 +3352,12 @@ static void encode_frame_to_data_rate(VP8_COMP *cpi, size_t *size,
}
break;
#endif // !CONFIG_REALTIME_ONLY
- default:
- cpi->per_frame_bandwidth =
- (int)round(cpi->target_bandwidth / cpi->output_framerate);
+ default: {
+ const double per_frame_bandwidth =
+ round(cpi->target_bandwidth / cpi->output_framerate);
+ cpi->per_frame_bandwidth = (int)VPXMIN(per_frame_bandwidth, INT_MAX);
break;
+ }
}
/* Default turn off buffer to buffer copying */
@@ -4391,7 +4406,9 @@ static void encode_frame_to_data_rate(VP8_COMP *cpi, size_t *size,
cpi->b_lpf_running = 1;
/* wait for the filter_level to be picked so that we can continue with
* stream packing */
- sem_wait(&cpi->h_event_end_lpf);
+ errno = 0;
+ while (sem_wait(&cpi->h_event_end_lpf) != 0 && errno == EINTR) {
+ }
} else
#endif
{
@@ -5120,6 +5137,16 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags,
vpx_usec_timer_mark(&cmptimer);
cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer);
+#if CONFIG_MULTITHREAD
+ /* wait for the lpf thread done */
+ if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) && cpi->b_lpf_running) {
+ errno = 0;
+ while (sem_wait(&cpi->h_event_end_lpf) != 0 && errno == EINTR) {
+ }
+ cpi->b_lpf_running = 0;
+ }
+#endif
+
if (cpi->b_calculate_psnr && cpi->pass != 1 && cm->show_frame) {
generate_psnr_packet(cpi);
}
@@ -5249,14 +5276,6 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags,
cpi->common.error.setjmp = 0;
-#if CONFIG_MULTITHREAD
- /* wait for the lpf thread done */
- if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) && cpi->b_lpf_running) {
- sem_wait(&cpi->h_event_end_lpf);
- cpi->b_lpf_running = 0;
- }
-#endif
-
return 0;
}
diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c
index fcd4eb04e..7ba7a308a 100644
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -791,8 +791,12 @@ static void calc_pframe_target_size(VP8_COMP *cpi) {
(int)((cpi->buffer_level - cpi->oxcf.optimal_buffer_level) /
one_percent_bits);
} else if (cpi->bits_off_target > cpi->oxcf.optimal_buffer_level) {
- percent_high =
- (int)((100 * cpi->bits_off_target) / (cpi->total_byte_count * 8));
+ if (cpi->total_byte_count > 0) {
+ percent_high = (int)((100 * cpi->bits_off_target) /
+ (cpi->total_byte_count * 8));
+ } else {
+ percent_high = cpi->oxcf.over_shoot_pct;
+ }
}
if (percent_high > cpi->oxcf.over_shoot_pct) {
@@ -1190,10 +1194,13 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) {
/* Calculate required scaling factor based on target frame size and
* size of frame produced using previous Q
*/
- if (target_bits_per_frame >= (INT_MAX >> BPER_MB_NORMBITS)) {
- /* Case where we would overflow int */
- target_bits_per_mb = (target_bits_per_frame / cpi->common.MBs)
- << BPER_MB_NORMBITS;
+ if (target_bits_per_frame > (INT_MAX >> BPER_MB_NORMBITS)) {
+ int temp = target_bits_per_frame / cpi->common.MBs;
+ if (temp > (INT_MAX >> BPER_MB_NORMBITS)) {
+ target_bits_per_mb = INT_MAX;
+ } else {
+ target_bits_per_mb = temp << BPER_MB_NORMBITS;
+ }
} else {
target_bits_per_mb =
(target_bits_per_frame << BPER_MB_NORMBITS) / cpi->common.MBs;
@@ -1534,9 +1541,13 @@ int vp8_drop_encodedframe_overshoot(VP8_COMP *cpi, int Q) {
// undershoots significantly, and then we end up dropping every other
// frame because the QP/rate_correction_factor may have been too low
// before the drop and then takes too long to come up.
- if (target_size >= (INT_MAX >> BPER_MB_NORMBITS)) {
- target_bits_per_mb = (target_size / cpi->common.MBs)
- << BPER_MB_NORMBITS;
+ if (target_size > (INT_MAX >> BPER_MB_NORMBITS)) {
+ int temp = target_size / cpi->common.MBs;
+ if (temp > (INT_MAX >> BPER_MB_NORMBITS)) {
+ target_bits_per_mb = INT_MAX;
+ } else {
+ target_bits_per_mb = temp << BPER_MB_NORMBITS;
+ }
} else {
target_bits_per_mb =
(target_size << BPER_MB_NORMBITS) / cpi->common.MBs;
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index ca56d14aa..1b07b9a34 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -9,6 +9,7 @@
*/
#include <assert.h>
+#include <stdint.h>
#include <stdio.h>
#include <limits.h>
@@ -943,12 +944,11 @@ static int encode_tile_worker(void *arg1, void *arg2) {
VP9BitstreamWorkerData *data = (VP9BitstreamWorkerData *)arg2;
MACROBLOCKD *const xd = &data->xd;
const int tile_row = 0;
- vpx_start_encode(&data->bit_writer, data->dest);
+ vpx_start_encode(&data->bit_writer, data->dest, data->dest_size);
write_modes(cpi, xd, &cpi->tile_data[data->tile_idx].tile_info,
&data->bit_writer, tile_row, data->tile_idx,
&data->max_mv_magnitude, data->interp_filter_selected);
- vpx_stop_encode(&data->bit_writer);
- return 1;
+ return vpx_stop_encode(&data->bit_writer) == 0;
}
void vp9_bitstream_encode_tiles_buffer_dealloc(VP9_COMP *const cpi) {
@@ -962,6 +962,16 @@ void vp9_bitstream_encode_tiles_buffer_dealloc(VP9_COMP *const cpi) {
}
}
+static int encode_tiles_buffer_alloc_size(VP9_COMP *const cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ const int image_bps =
+ (8 + 2 * (8 >> (cm->subsampling_x + cm->subsampling_y))) *
+ (1 + (cm->bit_depth > 8));
+ const int64_t size =
+ (int64_t)cpi->oxcf.width * cpi->oxcf.height * image_bps / 8;
+ return (int)size;
+}
+
static void encode_tiles_buffer_alloc(VP9_COMP *const cpi) {
VP9_COMMON *const cm = &cpi->common;
int i;
@@ -972,23 +982,25 @@ static void encode_tiles_buffer_alloc(VP9_COMP *const cpi) {
memset(cpi->vp9_bitstream_worker_data, 0, worker_data_size);
for (i = 1; i < cpi->num_workers; ++i) {
cpi->vp9_bitstream_worker_data[i].dest_size =
- cpi->oxcf.width * cpi->oxcf.height;
+ encode_tiles_buffer_alloc_size(cpi);
CHECK_MEM_ERROR(&cm->error, cpi->vp9_bitstream_worker_data[i].dest,
vpx_malloc(cpi->vp9_bitstream_worker_data[i].dest_size));
}
}
-static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr) {
+static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr,
+ size_t data_size) {
const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
VP9_COMMON *const cm = &cpi->common;
const int tile_cols = 1 << cm->log2_tile_cols;
const int num_workers = cpi->num_workers;
size_t total_size = 0;
int tile_col = 0;
+ int error = 0;
if (!cpi->vp9_bitstream_worker_data ||
- cpi->vp9_bitstream_worker_data[1].dest_size >
- (cpi->oxcf.width * cpi->oxcf.height)) {
+ cpi->vp9_bitstream_worker_data[1].dest_size !=
+ encode_tiles_buffer_alloc_size(cpi)) {
vp9_bitstream_encode_tiles_buffer_dealloc(cpi);
encode_tiles_buffer_alloc(cpi);
}
@@ -1010,8 +1022,13 @@ static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr) {
if (i == 0) {
// If this worker happens to be for the last tile, then do not offset it
// by 4 for the tile size.
- data->dest =
- data_ptr + total_size + (tile_col == tile_cols - 1 ? 0 : 4);
+ const size_t offset = total_size + (tile_col == tile_cols - 1 ? 0 : 4);
+ if (data_size < offset) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "encode_tiles_mt: output buffer full");
+ }
+ data->dest = data_ptr + offset;
+ data->dest_size = data_size - offset;
}
worker->data1 = cpi;
worker->data2 = data;
@@ -1032,7 +1049,11 @@ static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr) {
uint32_t tile_size;
int k;
- if (!winterface->sync(worker)) return 0;
+ if (!winterface->sync(worker)) {
+ error = 1;
+ continue;
+ }
+
tile_size = data->bit_writer.pos;
// Aggregate per-thread bitstream stats.
@@ -1044,19 +1065,31 @@ static size_t encode_tiles_mt(VP9_COMP *cpi, uint8_t *data_ptr) {
// Prefix the size of the tile on all but the last.
if (tile_col != tile_cols || j < i - 1) {
+ if (data_size - total_size < 4) {
+ error = 1;
+ continue;
+ }
mem_put_be32(data_ptr + total_size, tile_size);
total_size += 4;
}
if (j > 0) {
+ if (data_size - total_size < tile_size) {
+ error = 1;
+ continue;
+ }
memcpy(data_ptr + total_size, data->dest, tile_size);
}
total_size += tile_size;
}
+ if (error) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "encode_tiles_mt: output buffer full");
+ }
}
return total_size;
}
-static size_t encode_tiles(VP9_COMP *cpi, uint8_t *data_ptr) {
+static size_t encode_tiles(VP9_COMP *cpi, uint8_t *data_ptr, size_t data_size) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
vpx_writer residual_bc;
@@ -1073,23 +1106,32 @@ static size_t encode_tiles(VP9_COMP *cpi, uint8_t *data_ptr) {
// that it does not make the overall process worse in any case.
if (cpi->oxcf.mode == REALTIME && cpi->num_workers > 1 && tile_rows == 1 &&
tile_cols > 1) {
- return encode_tiles_mt(cpi, data_ptr);
+ return encode_tiles_mt(cpi, data_ptr, data_size);
}
for (tile_row = 0; tile_row < tile_rows; tile_row++) {
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
int tile_idx = tile_row * tile_cols + tile_col;
+ size_t offset;
if (tile_col < tile_cols - 1 || tile_row < tile_rows - 1)
- vpx_start_encode(&residual_bc, data_ptr + total_size + 4);
+ offset = total_size + 4;
else
- vpx_start_encode(&residual_bc, data_ptr + total_size);
+ offset = total_size;
+ if (data_size < offset) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "encode_tiles: output buffer full");
+ }
+ vpx_start_encode(&residual_bc, data_ptr + offset, data_size - offset);
write_modes(cpi, xd, &cpi->tile_data[tile_idx].tile_info, &residual_bc,
tile_row, tile_col, &cpi->max_mv_magnitude,
cpi->interp_filter_selected);
- vpx_stop_encode(&residual_bc);
+ if (vpx_stop_encode(&residual_bc)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "encode_tiles: output buffer full");
+ }
if (tile_col < tile_cols - 1 || tile_row < tile_rows - 1) {
// size of this tile
mem_put_be32(data_ptr + total_size, residual_bc.pos);
@@ -1271,14 +1313,15 @@ static void write_uncompressed_header(VP9_COMP *cpi,
write_tile_info(cm, wb);
}
-static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) {
+static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data,
+ size_t data_size) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
FRAME_CONTEXT *const fc = cm->fc;
FRAME_COUNTS *counts = cpi->td.counts;
vpx_writer header_bc;
- vpx_start_encode(&header_bc, data);
+ vpx_start_encode(&header_bc, data, data_size);
if (xd->lossless)
cm->tx_mode = ONLY_4X4;
@@ -1342,26 +1385,36 @@ static size_t write_compressed_header(VP9_COMP *cpi, uint8_t *data) {
&counts->mv);
}
- vpx_stop_encode(&header_bc);
- assert(header_bc.pos <= 0xffff);
+ if (vpx_stop_encode(&header_bc)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "write_compressed_header: output buffer full");
+ }
return header_bc.pos;
}
-void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size) {
+void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t dest_size,
+ size_t *size) {
+ VP9_COMMON *const cm = &cpi->common;
uint8_t *data = dest;
- size_t first_part_size, uncompressed_hdr_size;
- struct vpx_write_bit_buffer wb = { data, 0 };
+ size_t data_size = dest_size;
+ size_t uncompressed_hdr_size, compressed_hdr_size;
+ struct vpx_write_bit_buffer wb;
struct vpx_write_bit_buffer saved_wb;
#if CONFIG_BITSTREAM_DEBUG
bitstream_queue_reset_write();
#endif
+ vpx_wb_init(&wb, data, data_size);
write_uncompressed_header(cpi, &wb);
+ if (vpx_wb_has_error(&wb)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "vp9_pack_bitstream: output buffer full");
+ }
// Skip the rest coding process if use show existing frame.
- if (cpi->common.show_existing_frame) {
+ if (cm->show_existing_frame) {
uncompressed_hdr_size = vpx_wb_bytes_written(&wb);
data += uncompressed_hdr_size;
*size = data - dest;
@@ -1369,19 +1422,30 @@ void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size) {
}
saved_wb = wb;
- vpx_wb_write_literal(&wb, 0, 16); // don't know in advance first part. size
+ // don't know in advance compressed header size
+ vpx_wb_write_literal(&wb, 0, 16);
+ if (vpx_wb_has_error(&wb)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "vp9_pack_bitstream: output buffer full");
+ }
uncompressed_hdr_size = vpx_wb_bytes_written(&wb);
data += uncompressed_hdr_size;
+ data_size -= uncompressed_hdr_size;
vpx_clear_system_state();
- first_part_size = write_compressed_header(cpi, data);
- data += first_part_size;
- // TODO(jbb): Figure out what to do if first_part_size > 16 bits.
- vpx_wb_write_literal(&saved_wb, (int)first_part_size, 16);
+ compressed_hdr_size = write_compressed_header(cpi, data, data_size);
+ data += compressed_hdr_size;
+ data_size -= compressed_hdr_size;
+ if (compressed_hdr_size > UINT16_MAX) {
+ vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
+ "compressed_hdr_size > 16 bits");
+ }
+ vpx_wb_write_literal(&saved_wb, (int)compressed_hdr_size, 16);
+ assert(!vpx_wb_has_error(&saved_wb));
- data += encode_tiles(cpi, data);
+ data += encode_tiles(cpi, data, data_size);
*size = data - dest;
}
diff --git a/vp9/encoder/vp9_bitstream.h b/vp9/encoder/vp9_bitstream.h
index 208651dc2..e367abc30 100644
--- a/vp9/encoder/vp9_bitstream.h
+++ b/vp9/encoder/vp9_bitstream.h
@@ -35,7 +35,8 @@ int vp9_get_refresh_mask(VP9_COMP *cpi);
void vp9_bitstream_encode_tiles_buffer_dealloc(VP9_COMP *const cpi);
-void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t *size);
+void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, size_t dest_size,
+ size_t *size);
static INLINE int vp9_preserve_existing_gf(VP9_COMP *cpi) {
return cpi->refresh_golden_frame && cpi->rc.is_src_frame_alt_ref &&
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 7ff5f00ed..e8f29d5d2 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -48,6 +48,7 @@
#include "vp9/encoder/vp9_encodeframe.h"
#include "vp9/encoder/vp9_encodemb.h"
#include "vp9/encoder/vp9_encodemv.h"
+#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_ethread.h"
#include "vp9/encoder/vp9_extend.h"
#include "vp9/encoder/vp9_multi_thread.h"
@@ -5851,7 +5852,12 @@ void vp9_init_tile_data(VP9_COMP *cpi) {
int tplist_count = 0;
if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) {
- if (cpi->tile_data != NULL) vpx_free(cpi->tile_data);
+ if (cpi->tile_data != NULL) {
+ // Free the row mt memory in cpi->tile_data first.
+ vp9_row_mt_mem_dealloc(cpi);
+ vpx_free(cpi->tile_data);
+ }
+ cpi->allocated_tiles = 0;
CHECK_MEM_ERROR(
&cm->error, cpi->tile_data,
vpx_malloc(tile_cols * tile_rows * sizeof(*cpi->tile_data)));
@@ -5881,9 +5887,9 @@ void vp9_init_tile_data(VP9_COMP *cpi) {
for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
TileInfo *tile_info = &this_tile->tile_info;
- if (cpi->sf.adaptive_rd_thresh_row_mt &&
- this_tile->row_base_thresh_freq_fact == NULL)
+ if (cpi->sf.adaptive_rd_thresh_row_mt) {
vp9_row_mt_alloc_rd_thresh(cpi, this_tile);
+ }
vp9_tile_init(tile_info, cm, tile_row, tile_col);
cpi->tile_tok[tile_row][tile_col] = pre_tok + tile_tok;
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 152d42bc9..42a2770d1 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -2134,24 +2134,22 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
cpi->external_resize = 1;
}
- if (cpi->initial_width) {
- int new_mi_size = 0;
- vp9_set_mb_mi(cm, cm->width, cm->height);
- new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows);
- if (cm->mi_alloc_size < new_mi_size) {
- vp9_free_context_buffers(cm);
- vp9_free_pc_tree(&cpi->td);
- vpx_free(cpi->mbmi_ext_base);
- alloc_compressor_data(cpi);
- realloc_segmentation_maps(cpi);
- cpi->initial_width = cpi->initial_height = 0;
- cpi->external_resize = 0;
- } else if (cm->mi_alloc_size == new_mi_size &&
- (cpi->oxcf.width > last_w || cpi->oxcf.height > last_h)) {
- if (vp9_alloc_loop_filter(cm)) {
- vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
- "Failed to allocate loop filter data");
- }
+ int new_mi_size = 0;
+ vp9_set_mb_mi(cm, cm->width, cm->height);
+ new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows);
+ if (cm->mi_alloc_size < new_mi_size) {
+ vp9_free_context_buffers(cm);
+ vp9_free_pc_tree(&cpi->td);
+ vpx_free(cpi->mbmi_ext_base);
+ alloc_compressor_data(cpi);
+ realloc_segmentation_maps(cpi);
+ cpi->initial_width = cpi->initial_height = 0;
+ cpi->external_resize = 0;
+ } else if (cm->mi_alloc_size == new_mi_size &&
+ (cpi->oxcf.width > last_w || cpi->oxcf.height > last_h)) {
+ if (vp9_alloc_loop_filter(cm)) {
+ vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+ "Failed to allocate loop filter data");
}
}
@@ -3958,7 +3956,7 @@ static INLINE void set_raw_source_frame(VP9_COMP *cpi) {
}
static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
- uint8_t *dest) {
+ uint8_t *dest, size_t dest_size) {
VP9_COMMON *const cm = &cpi->common;
SVC *const svc = &cpi->svc;
int q = 0, bottom_index = 0, top_index = 0;
@@ -4254,7 +4252,7 @@ static int encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
int frame_size = 0;
// Get an estimate of the encoded frame size.
save_coding_context(cpi);
- vp9_pack_bitstream(cpi, dest, size);
+ vp9_pack_bitstream(cpi, dest, dest_size, size);
restore_coding_context(cpi);
frame_size = (int)(*size) << 3;
// Check if encoded frame will overshoot too much, and if so, set the q and
@@ -4457,7 +4455,8 @@ static void rq_model_update(const RATE_QINDEX_HISTORY *rq_history,
}
#endif // CONFIG_RATE_CTRL
-static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
+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
@@ -4680,7 +4679,8 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
// to recode.
if (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF) {
save_coding_context(cpi);
- if (!cpi->sf.use_nonrd_pick_mode) vp9_pack_bitstream(cpi, dest, size);
+ if (!cpi->sf.use_nonrd_pick_mode)
+ vp9_pack_bitstream(cpi, dest, dest_size, size);
rc->projected_frame_size = (int)(*size) << 3;
@@ -5231,7 +5231,7 @@ static void spatial_denoise_frame(VP9_COMP *cpi) {
#if !CONFIG_REALTIME_ONLY
static void vp9_try_disable_lookahead_aq(VP9_COMP *cpi, size_t *size,
- uint8_t *dest) {
+ uint8_t *dest, size_t dest_size) {
if (cpi->common.seg.enabled)
if (ALT_REF_AQ_PROTECT_GAIN) {
size_t nsize = *size;
@@ -5242,7 +5242,7 @@ static void vp9_try_disable_lookahead_aq(VP9_COMP *cpi, size_t *size,
save_coding_context(cpi);
vp9_disable_segmentation(&cpi->common.seg);
- vp9_pack_bitstream(cpi, dest, &nsize);
+ vp9_pack_bitstream(cpi, dest, dest_size, &nsize);
restore_coding_context(cpi);
overhead = (int)*size - (int)nsize;
@@ -5535,8 +5535,8 @@ static void update_encode_frame_result_simple_encode(
#endif // !CONFIG_REALTIME_ONLY
static void encode_frame_to_data_rate(
- VP9_COMP *cpi, size_t *size, uint8_t *dest, unsigned int *frame_flags,
- ENCODE_FRAME_RESULT *encode_frame_result) {
+ VP9_COMP *cpi, size_t *size, uint8_t *dest, size_t dest_size,
+ unsigned int *frame_flags, ENCODE_FRAME_RESULT *encode_frame_result) {
VP9_COMMON *const cm = &cpi->common;
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
struct segmentation *const seg = &cm->seg;
@@ -5643,16 +5643,17 @@ static void encode_frame_to_data_rate(
}
if (cpi->sf.recode_loop == DISALLOW_RECODE) {
- if (!encode_without_recode_loop(cpi, size, dest)) return;
+ 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, &encode_frame_result->rq_history);
+ 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);
+ encode_with_recode_loop(cpi, size, dest, dest_size);
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, encode_with_recode_loop_time);
#endif
@@ -5672,7 +5673,7 @@ static void encode_frame_to_data_rate(
#if !CONFIG_REALTIME_ONLY
// Disable segmentation if it decrease rate/distortion ratio
if (cpi->oxcf.aq_mode == LOOKAHEAD_AQ)
- vp9_try_disable_lookahead_aq(cpi, size, dest);
+ vp9_try_disable_lookahead_aq(cpi, size, dest, dest_size);
#endif
#if CONFIG_VP9_TEMPORAL_DENOISING
@@ -5729,7 +5730,7 @@ static void encode_frame_to_data_rate(
start_timing(cpi, vp9_pack_bitstream_time);
#endif
// build the bitstream
- vp9_pack_bitstream(cpi, dest, size);
+ vp9_pack_bitstream(cpi, dest, dest_size, size);
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, vp9_pack_bitstream_time);
#endif
@@ -5920,32 +5921,33 @@ static void encode_frame_to_data_rate(
}
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags) {
+ size_t dest_size, unsigned int *frame_flags) {
vp9_rc_get_svc_params(cpi);
- encode_frame_to_data_rate(cpi, size, dest, frame_flags,
+ encode_frame_to_data_rate(cpi, size, dest, dest_size, frame_flags,
/*encode_frame_result = */ NULL);
}
static void Pass0Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags) {
+ size_t dest_size, unsigned int *frame_flags) {
if (cpi->oxcf.rc_mode == VPX_CBR) {
vp9_rc_get_one_pass_cbr_params(cpi);
} else {
vp9_rc_get_one_pass_vbr_params(cpi);
}
- encode_frame_to_data_rate(cpi, size, dest, frame_flags,
+ encode_frame_to_data_rate(cpi, size, dest, dest_size, frame_flags,
/*encode_frame_result = */ NULL);
}
#if !CONFIG_REALTIME_ONLY
static void Pass2Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
- unsigned int *frame_flags,
+ size_t dest_size, unsigned int *frame_flags,
ENCODE_FRAME_RESULT *encode_frame_result) {
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
#if CONFIG_MISMATCH_DEBUG
mismatch_move_frame_idx_w();
#endif
- encode_frame_to_data_rate(cpi, size, dest, frame_flags, encode_frame_result);
+ encode_frame_to_data_rate(cpi, size, dest, dest_size, frame_flags,
+ encode_frame_result);
}
#endif // !CONFIG_REALTIME_ONLY
@@ -6358,8 +6360,8 @@ void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
}
int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
- size_t *size, uint8_t *dest, int64_t *time_stamp,
- int64_t *time_end, int flush,
+ size_t *size, uint8_t *dest, size_t dest_size,
+ int64_t *time_stamp, int64_t *time_end, int flush,
ENCODE_FRAME_RESULT *encode_frame_result) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf;
VP9_COMMON *const cm = &cpi->common;
@@ -6636,10 +6638,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
#if CONFIG_REALTIME_ONLY
(void)encode_frame_result;
if (cpi->use_svc) {
- SvcEncode(cpi, size, dest, frame_flags);
+ SvcEncode(cpi, size, dest, dest_size, frame_flags);
} else {
// One pass encode
- Pass0Encode(cpi, size, dest, frame_flags);
+ Pass0Encode(cpi, size, dest, dest_size, frame_flags);
}
#else // !CONFIG_REALTIME_ONLY
if (oxcf->pass == 1 && !cpi->use_svc) {
@@ -6662,16 +6664,16 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
// Accumulate 2nd pass time in 2-pass case.
start_timing(cpi, Pass2Encode_time);
#endif
- Pass2Encode(cpi, size, dest, frame_flags, encode_frame_result);
+ Pass2Encode(cpi, size, dest, dest_size, frame_flags, encode_frame_result);
vp9_twopass_postencode_update(cpi);
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, Pass2Encode_time);
#endif
} else if (cpi->use_svc) {
- SvcEncode(cpi, size, dest, frame_flags);
+ SvcEncode(cpi, size, dest, dest_size, frame_flags);
} else {
// One pass encode
- Pass0Encode(cpi, size, dest, frame_flags);
+ Pass0Encode(cpi, size, dest, dest_size, frame_flags);
}
#endif // CONFIG_REALTIME_ONLY
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index 7136f7faa..141f3429c 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -338,6 +338,10 @@ typedef struct TileDataEnc {
// Used for adaptive_rd_thresh with row multithreading
int *row_base_thresh_freq_fact;
+ // The value of sb_rows when row_base_thresh_freq_fact is allocated.
+ // The row_base_thresh_freq_fact array has sb_rows * BLOCK_SIZES * MAX_MODES
+ // elements.
+ int sb_rows;
MV firstpass_top_mv;
} TileDataEnc;
@@ -1218,8 +1222,8 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, vpx_enc_frame_flags_t frame_flags,
int64_t end_time);
int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
- size_t *size, uint8_t *dest, int64_t *time_stamp,
- int64_t *time_end, int flush,
+ size_t *size, uint8_t *dest, size_t dest_size,
+ int64_t *time_stamp, int64_t *time_end, int flush,
ENCODE_FRAME_RESULT *encode_frame_result);
int vp9_get_preview_raw_frame(VP9_COMP *cpi, YV12_BUFFER_CONFIG *dest,
diff --git a/vp9/encoder/vp9_multi_thread.c b/vp9/encoder/vp9_multi_thread.c
index 0843cd97e..10fbc927c 100644
--- a/vp9/encoder/vp9_multi_thread.c
+++ b/vp9/encoder/vp9_multi_thread.c
@@ -54,16 +54,23 @@ void *vp9_enc_grp_get_next_job(MultiThreadHandle *multi_thread_ctxt,
void vp9_row_mt_alloc_rd_thresh(VP9_COMP *const cpi,
TileDataEnc *const this_tile) {
VP9_COMMON *const cm = &cpi->common;
- const int sb_rows =
- (mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2) + 1;
+ const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
int i;
+ if (this_tile->row_base_thresh_freq_fact != NULL) {
+ if (sb_rows <= this_tile->sb_rows) {
+ return;
+ }
+ vpx_free(this_tile->row_base_thresh_freq_fact);
+ this_tile->row_base_thresh_freq_fact = NULL;
+ }
CHECK_MEM_ERROR(
&cm->error, this_tile->row_base_thresh_freq_fact,
(int *)vpx_calloc(sb_rows * BLOCK_SIZES * MAX_MODES,
sizeof(*(this_tile->row_base_thresh_freq_fact))));
for (i = 0; i < sb_rows * BLOCK_SIZES * MAX_MODES; i++)
this_tile->row_base_thresh_freq_fact[i] = RD_THRESH_INIT_FACT;
+ this_tile->sb_rows = sb_rows;
}
void vp9_row_mt_mem_alloc(VP9_COMP *cpi) {
@@ -100,13 +107,6 @@ void vp9_row_mt_mem_alloc(VP9_COMP *cpi) {
for (tile_col = 0; tile_col < tile_cols; tile_col++) {
TileDataEnc *this_tile = &cpi->tile_data[tile_col];
vp9_row_mt_sync_mem_alloc(&this_tile->row_mt_sync, cm, jobs_per_tile_col);
- if (cpi->sf.adaptive_rd_thresh_row_mt) {
- if (this_tile->row_base_thresh_freq_fact != NULL) {
- vpx_free(this_tile->row_base_thresh_freq_fact);
- this_tile->row_base_thresh_freq_fact = NULL;
- }
- vp9_row_mt_alloc_rd_thresh(cpi, this_tile);
- }
}
// Assign the sync pointer of tile row zero for every tile row > 0
@@ -135,14 +135,17 @@ void vp9_row_mt_mem_dealloc(VP9_COMP *cpi) {
#endif
// Deallocate memory for job queue
- if (multi_thread_ctxt->job_queue) vpx_free(multi_thread_ctxt->job_queue);
+ if (multi_thread_ctxt->job_queue) {
+ vpx_free(multi_thread_ctxt->job_queue);
+ multi_thread_ctxt->job_queue = NULL;
+ }
#if CONFIG_MULTITHREAD
// Destroy mutex for each tile
for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
tile_col++) {
RowMTInfo *row_mt_info = &multi_thread_ctxt->row_mt_info[tile_col];
- if (row_mt_info) pthread_mutex_destroy(&row_mt_info->job_mutex);
+ pthread_mutex_destroy(&row_mt_info->job_mutex);
}
#endif
@@ -168,6 +171,10 @@ void vp9_row_mt_mem_dealloc(VP9_COMP *cpi) {
}
}
#endif
+
+ multi_thread_ctxt->allocated_tile_cols = 0;
+ multi_thread_ctxt->allocated_tile_rows = 0;
+ multi_thread_ctxt->allocated_vert_unit_rows = 0;
}
void vp9_multi_thread_tile_init(VP9_COMP *cpi) {
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 6452e349d..44f52f96b 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -2651,11 +2651,12 @@ void vp9_rc_update_framerate(VP9_COMP *cpi) {
rc->avg_frame_bandwidth =
(int)VPXMIN(oxcf->target_bandwidth / cpi->framerate, INT_MAX);
- rc->min_frame_bandwidth =
- (int)(rc->avg_frame_bandwidth * oxcf->two_pass_vbrmin_section / 100);
- rc->min_frame_bandwidth =
- VPXMAX(rc->min_frame_bandwidth, FRAME_OVERHEAD_BITS);
+ int64_t vbr_min_bits =
+ (int64_t)rc->avg_frame_bandwidth * oxcf->two_pass_vbrmin_section / 100;
+ vbr_min_bits = VPXMIN(vbr_min_bits, INT_MAX);
+
+ rc->min_frame_bandwidth = VPXMAX((int)vbr_min_bits, FRAME_OVERHEAD_BITS);
// A maximum bitrate for a frame is defined.
// However this limit is extended if a very high rate is given on the command
diff --git a/vp9/encoder/x86/vp9_frame_scale_ssse3.c b/vp9/encoder/x86/vp9_frame_scale_ssse3.c
index 94506aad0..628dc4fea 100644
--- a/vp9/encoder/x86/vp9_frame_scale_ssse3.c
+++ b/vp9/encoder/x86/vp9_frame_scale_ssse3.c
@@ -886,14 +886,14 @@ void vp9_scale_and_extend_frame_ssse3(const YV12_BUFFER_CONFIG *src,
scale_plane_1_to_2_phase_0(
src->y_buffer, src->y_stride, dst->y_buffer, dst->y_stride, src_w,
src_h, vp9_filter_kernels[filter_type][8], temp_buffer);
- scale_plane_1_to_2_phase_0(src->u_buffer, src->uv_stride, dst->u_buffer,
- dst->uv_stride, src_w / 2, src_h / 2,
- vp9_filter_kernels[filter_type][8],
- temp_buffer);
- scale_plane_1_to_2_phase_0(src->v_buffer, src->uv_stride, dst->v_buffer,
- dst->uv_stride, src_w / 2, src_h / 2,
- vp9_filter_kernels[filter_type][8],
- temp_buffer);
+ const int src_uv_w = src->uv_crop_width;
+ const int src_uv_h = src->uv_crop_height;
+ scale_plane_1_to_2_phase_0(
+ src->u_buffer, src->uv_stride, dst->u_buffer, dst->uv_stride,
+ src_uv_w, src_uv_h, vp9_filter_kernels[filter_type][8], temp_buffer);
+ scale_plane_1_to_2_phase_0(
+ src->v_buffer, src->uv_stride, dst->v_buffer, dst->uv_stride,
+ src_uv_w, src_uv_h, vp9_filter_kernels[filter_type][8], temp_buffer);
free(temp_buffer);
}
}
diff --git a/vp9/ratectrl_rtc.cc b/vp9/ratectrl_rtc.cc
index fd81bce7b..316205f21 100644
--- a/vp9/ratectrl_rtc.cc
+++ b/vp9/ratectrl_rtc.cc
@@ -303,7 +303,9 @@ int VP9RateControlRTC::GetLoopfilterLevel() const {
bool VP9RateControlRTC::GetSegmentationData(
VP9SegmentationData *segmentation_data) const {
- if (!cpi_->cyclic_refresh->apply_cyclic_refresh) return false;
+ if (!cpi_->cyclic_refresh || !cpi_->cyclic_refresh->apply_cyclic_refresh) {
+ return false;
+ }
segmentation_data->segmentation_map = cpi_->segmentation_map;
segmentation_data->segmentation_map_size =
diff --git a/vp9/simple_encode.cc b/vp9/simple_encode.cc
index 2e6f9a451..9b78891c9 100644
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -498,6 +498,7 @@ static bool init_encode_frame_result(EncodeFrameResult *encode_frame_result,
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);
@@ -508,6 +509,7 @@ static bool init_encode_frame_result(EncodeFrameResult *encode_frame_result,
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,
@@ -911,7 +913,7 @@ void SimpleEncode::ComputeFirstPassStats() {
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,
+ 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
@@ -1193,8 +1195,9 @@ void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
&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(), &time_stamp,
- &time_end, flush, &encode_frame_info);
+ 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);
@@ -1208,10 +1211,8 @@ void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
fprintf(stderr, "Coding data size <= 0\n");
abort();
}
- const size_t max_coding_data_byte_size =
- get_max_coding_data_byte_size(frame_width_, frame_height_);
if (encode_frame_result->coding_data_byte_size >
- max_coding_data_byte_size) {
+ encode_frame_result->max_coding_data_byte_size) {
fprintf(stderr, "Coding data size exceeds the maximum.\n");
abort();
}
diff --git a/vp9/simple_encode.h b/vp9/simple_encode.h
index d610a5e15..94ecbf284 100644
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -263,6 +263,7 @@ struct EncodeFrameResult {
// 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<unsigned char[]> coding_data;
+ size_t max_coding_data_byte_size;
double psnr;
uint64_t sse;
int quantize_index;
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 3a462c372..9532dffa6 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -1434,8 +1434,8 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
cx_data += ctx->pending_cx_data_sz;
cx_data_sz -= ctx->pending_cx_data_sz;
- /* TODO: this is a minimal check, the underlying codec doesn't respect
- * the buffer size anyway.
+ /* TODO(webm:1844): this is a minimal check, the underlying codec doesn't
+ * respect the buffer size anyway.
*/
if (cx_data_sz < ctx->cx_data_sz / 2) {
vpx_internal_error(&cpi->common.error, VPX_CODEC_ERROR,
@@ -1454,9 +1454,9 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
ENCODE_FRAME_RESULT encode_frame_result;
vp9_init_encode_frame_result(&encode_frame_result);
// TODO(angiebird): Call vp9_first_pass directly
- ret = vp9_get_compressed_data(cpi, &lib_flags, &size, cx_data,
- &dst_time_stamp, &dst_end_time_stamp,
- !img, &encode_frame_result);
+ ret = vp9_get_compressed_data(
+ cpi, &lib_flags, &size, cx_data, cx_data_sz, &dst_time_stamp,
+ &dst_end_time_stamp, !img, &encode_frame_result);
assert(size == 0); // There is no compressed data in the first pass
(void)ret;
assert(ret == 0);
@@ -1479,8 +1479,9 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
vp9_init_encode_frame_result(&encode_frame_result);
while (cx_data_sz >= ctx->cx_data_sz / 2 &&
-1 != vp9_get_compressed_data(cpi, &lib_flags, &size, cx_data,
- &dst_time_stamp, &dst_end_time_stamp,
- !img, &encode_frame_result)) {
+ 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
diff --git a/vpx/src/vpx_image.c b/vpx/src/vpx_image.c
index f9f0dd602..9a42c3f91 100644
--- a/vpx/src/vpx_image.c
+++ b/vpx/src/vpx_image.c
@@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -21,12 +22,23 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_img_fmt_t fmt,
unsigned int buf_align,
unsigned int stride_align,
unsigned char *img_data) {
- unsigned int h, w, s, xcs, ycs, bps;
- unsigned int stride_in_bytes;
+ unsigned int h, w, xcs, ycs, bps;
+ uint64_t s;
+ int stride_in_bytes;
unsigned int align;
if (img != NULL) memset(img, 0, sizeof(vpx_image_t));
+ if (fmt == VPX_IMG_FMT_NONE) goto fail;
+
+ /* Impose maximum values on input parameters so that this function can
+ * perform arithmetic operations without worrying about overflows.
+ */
+ if (d_w > 0x08000000 || d_h > 0x08000000 || buf_align > 65536 ||
+ stride_align > 65536) {
+ goto fail;
+ }
+
/* Treat align==0 like align==1 */
if (!buf_align) buf_align = 1;
@@ -76,13 +88,28 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_img_fmt_t fmt,
default: ycs = 0; break;
}
- /* Calculate storage sizes. If the buffer was allocated externally, the width
- * and height shouldn't be adjusted. */
- w = d_w;
- h = d_h;
- s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
- s = (s + stride_align - 1) & ~(stride_align - 1);
- stride_in_bytes = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s * 2 : s;
+ /* Calculate storage sizes. */
+ if (img_data) {
+ /* If the buffer was allocated externally, the width and height shouldn't
+ * be adjusted. */
+ w = d_w;
+ h = d_h;
+ } else {
+ /* Calculate storage sizes given the chroma subsampling */
+ align = (1 << xcs) - 1;
+ w = (d_w + align) & ~align;
+ assert(d_w <= w);
+ align = (1 << ycs) - 1;
+ h = (d_h + align) & ~align;
+ assert(d_h <= h);
+ }
+
+ 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);
+ if (s > INT_MAX) goto fail;
+ stride_in_bytes = (int)s;
+ s = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? s / 2 : s;
/* Allocate the new image */
if (!img) {
@@ -97,15 +124,6 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, vpx_img_fmt_t fmt,
if (!img_data) {
uint64_t alloc_size;
- /* Calculate storage sizes given the chroma subsampling */
- align = (1 << xcs) - 1;
- w = (d_w + align) & ~align;
- align = (1 << ycs) - 1;
- h = (d_h + align) & ~align;
-
- s = (fmt & VPX_IMG_FMT_PLANAR) ? w : bps * w / 8;
- s = (s + stride_align - 1) & ~(stride_align - 1);
- stride_in_bytes = (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;
@@ -170,12 +188,12 @@ int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y,
if (img->fmt & VPX_IMG_FMT_HAS_ALPHA) {
img->planes[VPX_PLANE_ALPHA] =
data + x * bytes_per_sample + y * img->stride[VPX_PLANE_ALPHA];
- data += img->h * img->stride[VPX_PLANE_ALPHA];
+ data += (size_t)img->h * img->stride[VPX_PLANE_ALPHA];
}
img->planes[VPX_PLANE_Y] =
data + x * bytes_per_sample + y * img->stride[VPX_PLANE_Y];
- data += img->h * img->stride[VPX_PLANE_Y];
+ data += (size_t)img->h * img->stride[VPX_PLANE_Y];
if (img->fmt == VPX_IMG_FMT_NV12) {
img->planes[VPX_PLANE_U] =
@@ -186,7 +204,8 @@ int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y,
img->planes[VPX_PLANE_U] =
data + (x >> img->x_chroma_shift) * bytes_per_sample +
(y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
- data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
+ data +=
+ (size_t)(img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
img->planes[VPX_PLANE_V] =
data + (x >> img->x_chroma_shift) * bytes_per_sample +
(y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
@@ -194,7 +213,8 @@ int vpx_img_set_rect(vpx_image_t *img, unsigned int x, unsigned int y,
img->planes[VPX_PLANE_V] =
data + (x >> img->x_chroma_shift) * bytes_per_sample +
(y >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
- data += (img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
+ data +=
+ (size_t)(img->h >> img->y_chroma_shift) * img->stride[VPX_PLANE_V];
img->planes[VPX_PLANE_U] =
data + (x >> img->x_chroma_shift) * bytes_per_sample +
(y >> img->y_chroma_shift) * img->stride[VPX_PLANE_U];
diff --git a/vpx/vpx_image.h b/vpx/vpx_image.h
index 1adc9b9d9..a0c16c346 100644
--- a/vpx/vpx_image.h
+++ b/vpx/vpx_image.h
@@ -132,10 +132,13 @@ typedef struct vpx_image_rect {
* is NULL, the storage for the descriptor will be
* allocated on the heap.
* \param[in] fmt Format for the image
- * \param[in] d_w Width of the image
- * \param[in] d_h Height of the image
+ * \param[in] d_w Width of the image. Must not exceed 0x08000000
+ * (2^27).
+ * \param[in] d_h Height of the image. Must not exceed 0x08000000
+ * (2^27).
* \param[in] align Alignment, in bytes, of the image buffer and
- * each row in the image(stride).
+ * each row in the image (stride). Must not exceed
+ * 65536.
*
* \return Returns a pointer to the initialized image descriptor. If the img
* parameter is non-null, the value of the img parameter will be
@@ -155,9 +158,12 @@ vpx_image_t *vpx_img_alloc(vpx_image_t *img, vpx_img_fmt_t fmt,
* parameter is NULL, the storage for the descriptor
* will be allocated on the heap.
* \param[in] fmt Format for the image
- * \param[in] d_w Width of the image
- * \param[in] d_h Height of the image
- * \param[in] stride_align Alignment, in bytes, of each row in the image.
+ * \param[in] d_w Width of the image. Must not exceed 0x08000000
+ * (2^27).
+ * \param[in] d_h Height of the image. Must not exceed 0x08000000
+ * (2^27).
+ * \param[in] stride_align Alignment, in bytes, of each row in the image
+ * (stride). Must not exceed 65536.
* \param[in] img_data Storage to use for the image
*
* \return Returns a pointer to the initialized image descriptor. If the img
diff --git a/vpx_dsp/arm/highbd_sse_neon.c b/vpx_dsp/arm/highbd_sse_neon.c
index ee76bed58..91dfebf90 100644
--- a/vpx_dsp/arm/highbd_sse_neon.c
+++ b/vpx_dsp/arm/highbd_sse_neon.c
@@ -9,6 +9,7 @@
*/
#include <arm_neon.h>
+#include <stdint.h>
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/sum_neon.h"
diff --git a/vpx_dsp/arm/sse_neon.c b/vpx_dsp/arm/sse_neon.c
index f686dc350..2dd57e596 100644
--- a/vpx_dsp/arm/sse_neon.c
+++ b/vpx_dsp/arm/sse_neon.c
@@ -9,7 +9,9 @@
*/
#include <arm_neon.h>
+#include <stdint.h>
+#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx_dsp/arm/mem_neon.h"
#include "vpx_dsp/arm/sum_neon.h"
diff --git a/vpx_dsp/bitwriter.c b/vpx_dsp/bitwriter.c
index 5b41aa54d..d3ef9bd89 100644
--- a/vpx_dsp/bitwriter.c
+++ b/vpx_dsp/bitwriter.c
@@ -9,6 +9,7 @@
*/
#include <assert.h>
+#include <limits.h>
#include "./bitwriter.h"
@@ -16,16 +17,20 @@
#include "vpx_util/vpx_debug_util.h"
#endif
-void vpx_start_encode(vpx_writer *br, uint8_t *source) {
+void vpx_start_encode(vpx_writer *br, uint8_t *source, size_t size) {
br->lowvalue = 0;
br->range = 255;
br->count = -24;
- br->buffer = source;
+ br->error = 0;
br->pos = 0;
+ // Make sure it is safe to cast br->pos to int in vpx_write().
+ if (size > INT_MAX) size = INT_MAX;
+ br->size = (unsigned int)size;
+ br->buffer = source;
vpx_write_bit(br, 0);
}
-void vpx_stop_encode(vpx_writer *br) {
+int vpx_stop_encode(vpx_writer *br) {
int i;
#if CONFIG_BITSTREAM_DEBUG
@@ -34,9 +39,17 @@ void vpx_stop_encode(vpx_writer *br) {
for (i = 0; i < 32; i++) vpx_write_bit(br, 0);
// Ensure there's no ambigous collision with any index marker bytes
- if ((br->buffer[br->pos - 1] & 0xe0) == 0xc0) br->buffer[br->pos++] = 0;
+ if (!br->error && (br->buffer[br->pos - 1] & 0xe0) == 0xc0) {
+ if (br->pos < br->size) {
+ br->buffer[br->pos++] = 0;
+ } else {
+ br->error = 1;
+ }
+ }
#if CONFIG_BITSTREAM_DEBUG
bitstream_queue_set_skip_write(0);
#endif
+
+ return br->error ? -1 : 0;
}
diff --git a/vpx_dsp/bitwriter.h b/vpx_dsp/bitwriter.h
index 5f1ee69ec..daff331da 100644
--- a/vpx_dsp/bitwriter.h
+++ b/vpx_dsp/bitwriter.h
@@ -29,12 +29,19 @@ typedef struct vpx_writer {
unsigned int lowvalue;
unsigned int range;
int count;
+ // Whether there has been an error.
+ int error;
+ // We maintain the invariant that pos <= size, i.e., we never write beyond
+ // the end of the buffer. If pos would be incremented to be greater than
+ // size, leave pos unchanged and set error to 1.
unsigned int pos;
+ unsigned int size;
uint8_t *buffer;
} vpx_writer;
-void vpx_start_encode(vpx_writer *br, uint8_t *source);
-void vpx_stop_encode(vpx_writer *br);
+void vpx_start_encode(vpx_writer *br, uint8_t *source, size_t size);
+// Returns 0 on success and returns -1 in case of error.
+int vpx_stop_encode(vpx_writer *br);
static INLINE VPX_NO_UNSIGNED_SHIFT_CHECK void vpx_write(vpx_writer *br,
int bit,
@@ -77,18 +84,25 @@ static INLINE VPX_NO_UNSIGNED_SHIFT_CHECK void vpx_write(vpx_writer *br,
if (count >= 0) {
int offset = shift - count;
- if ((lowvalue << (offset - 1)) & 0x80000000) {
- int x = br->pos - 1;
+ if (!br->error) {
+ if ((lowvalue << (offset - 1)) & 0x80000000) {
+ int x = (int)br->pos - 1;
- while (x >= 0 && br->buffer[x] == 0xff) {
- br->buffer[x] = 0;
- x--;
+ while (x >= 0 && br->buffer[x] == 0xff) {
+ br->buffer[x] = 0;
+ x--;
+ }
+
+ // TODO(wtc): How to prove x >= 0?
+ br->buffer[x] += 1;
}
- br->buffer[x] += 1;
+ if (br->pos < br->size) {
+ br->buffer[br->pos++] = (lowvalue >> (24 - offset)) & 0xff;
+ } else {
+ br->error = 1;
+ }
}
-
- br->buffer[br->pos++] = (lowvalue >> (24 - offset)) & 0xff;
lowvalue <<= offset;
shift = count;
lowvalue &= 0xffffff;
diff --git a/vpx_dsp/bitwriter_buffer.c b/vpx_dsp/bitwriter_buffer.c
index 7a7e96f02..b3a2490f2 100644
--- a/vpx_dsp/bitwriter_buffer.c
+++ b/vpx_dsp/bitwriter_buffer.c
@@ -8,24 +8,43 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include "./vpx_config.h"
#include "./bitwriter_buffer.h"
+void vpx_wb_init(struct vpx_write_bit_buffer *wb, uint8_t *bit_buffer,
+ size_t size) {
+ wb->error = 0;
+ wb->bit_offset = 0;
+ wb->size = size;
+ wb->bit_buffer = bit_buffer;
+}
+
+int vpx_wb_has_error(const struct vpx_write_bit_buffer *wb) {
+ return wb->error;
+}
+
size_t vpx_wb_bytes_written(const struct vpx_write_bit_buffer *wb) {
+ assert(!wb->error);
return wb->bit_offset / CHAR_BIT + (wb->bit_offset % CHAR_BIT > 0);
}
void vpx_wb_write_bit(struct vpx_write_bit_buffer *wb, int bit) {
+ if (wb->error) return;
const int off = (int)wb->bit_offset;
const int p = off / CHAR_BIT;
const int q = CHAR_BIT - 1 - off % CHAR_BIT;
+ if ((size_t)p >= wb->size) {
+ wb->error = 1;
+ return;
+ }
if (q == CHAR_BIT - 1) {
wb->bit_buffer[p] = bit << q;
} else {
- wb->bit_buffer[p] &= ~(1 << q);
+ assert((wb->bit_buffer[p] & (1 << q)) == 0);
wb->bit_buffer[p] |= bit << q;
}
wb->bit_offset = off + 1;
diff --git a/vpx_dsp/bitwriter_buffer.h b/vpx_dsp/bitwriter_buffer.h
index 3662cb64d..3ee0e9658 100644
--- a/vpx_dsp/bitwriter_buffer.h
+++ b/vpx_dsp/bitwriter_buffer.h
@@ -18,10 +18,24 @@ extern "C" {
#endif
struct vpx_write_bit_buffer {
- uint8_t *bit_buffer;
+ // Whether there has been an error.
+ int error;
+ // We maintain the invariant that bit_offset <= size * CHAR_BIT, i.e., we
+ // never write beyond the end of bit_buffer. If bit_offset would be
+ // incremented to be greater than size * CHAR_BIT, leave bit_offset unchanged
+ // and set error to 1.
size_t bit_offset;
+ // Size of bit_buffer in bytes.
+ size_t size;
+ uint8_t *bit_buffer;
};
+void vpx_wb_init(struct vpx_write_bit_buffer *wb, uint8_t *bit_buffer,
+ size_t size);
+
+int vpx_wb_has_error(const struct vpx_write_bit_buffer *wb);
+
+// Must not be called if vpx_wb_has_error(wb) returns true.
size_t vpx_wb_bytes_written(const struct vpx_write_bit_buffer *wb);
void vpx_wb_write_bit(struct vpx_write_bit_buffer *wb, int bit);
diff --git a/vpx_dsp/sse.c b/vpx_dsp/sse.c
index 6cb4b705f..c9d751859 100644
--- a/vpx_dsp/sse.c
+++ b/vpx_dsp/sse.c
@@ -19,6 +19,7 @@
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
+#include "vpx_ports/mem.h"
int64_t vpx_sse_c(const uint8_t *a, int a_stride, const uint8_t *b,
int b_stride, int width, int height) {
diff --git a/vpx_dsp/vpx_dsp_rtcd_defs.pl b/vpx_dsp/vpx_dsp_rtcd_defs.pl
index e9d63f6ef..18087e25d 100644
--- a/vpx_dsp/vpx_dsp_rtcd_defs.pl
+++ b/vpx_dsp/vpx_dsp_rtcd_defs.pl
@@ -744,7 +744,7 @@ if (vpx_config("CONFIG_ENCODERS") eq "yes") {
add_proto qw/void vpx_subtract_block/, "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";
specialize qw/vpx_subtract_block neon msa mmi sse2 avx2 vsx lsx/;
-add_proto qw/int64_t/, "vpx_sse", "const uint8_t *a, int a_stride, const uint8_t *b,int b_stride, int width, int height";
+add_proto qw/int64_t/, "vpx_sse", "const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int width, int height";
specialize qw/vpx_sse sse4_1 avx2 neon neon_dotprod/;
#
diff --git a/vpx_dsp/x86/sse_avx2.c b/vpx_dsp/x86/sse_avx2.c
index 917ff0ef1..dfe45b611 100644
--- a/vpx_dsp/x86/sse_avx2.c
+++ b/vpx_dsp/x86/sse_avx2.c
@@ -8,8 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <smmintrin.h>
#include <immintrin.h>
+#include <smmintrin.h>
+#include <stdint.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"