Merge "Merge tag 'v1.14.1' into aosp/main" into main am: 38a9a33e46 am: 110de86c54

Original change: https://android-review.googlesource.com/c/platform/external/libvpx/+/3112265

Change-Id: I884fd1754af7d88f44d240b2c958b93037ba6c02
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/AUTHORS b/AUTHORS
index 5515e26..a98d0d8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -76,6 +76,7 @@
 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 6e39ca0..9d3d0fa 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 08199cc..2ad1ff1 100644
--- a/METADATA
+++ b/METADATA
@@ -11,12 +11,12 @@
   }
   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 5706119..7a01a00 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/build/make/configure.sh b/build/make/configure.sh
index b645a66..93643f3 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -429,6 +429,40 @@
   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 @@
   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
+
+      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 @@
           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 578f1c5..f0800ab 100644
--- a/config/arm-neon/vpx_dsp_rtcd.h
+++ b/config/arm-neon/vpx_dsp_rtcd.h
@@ -1968,8 +1968,8 @@
 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 00ab40f..a06c0a0 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 578f1c5..f0800ab 100644
--- a/config/arm64/vpx_dsp_rtcd.h
+++ b/config/arm64/vpx_dsp_rtcd.h
@@ -1968,8 +1968,8 @@
 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 00ab40f..a06c0a0 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 256cbdf..7f8cc7b 100644
--- a/config/generic/vpx_dsp_rtcd.h
+++ b/config/generic/vpx_dsp_rtcd.h
@@ -1492,7 +1492,7 @@
 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 00ab40f..a06c0a0 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 67c1504..5c6993a 100644
--- a/config/x86/vpx_dsp_rtcd.h
+++ b/config/x86/vpx_dsp_rtcd.h
@@ -1931,7 +1931,7 @@
 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 00ab40f..a06c0a0 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 5eb5121..134856f 100644
--- a/config/x86_64/vpx_dsp_rtcd.h
+++ b/config/x86_64/vpx_dsp_rtcd.h
@@ -1938,7 +1938,7 @@
 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 00ab40f..a06c0a0 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 5964386..70207a4 100644
--- a/libs.mk
+++ b/libs.mk
@@ -315,7 +315,7 @@
 # (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 a25dbc6..3bc38c5 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 @@
          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 @@
   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 @@
   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, 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 @@
 }
 #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 @@
 
  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 @@
   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 @@
     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::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 @@
   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, 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 725d5eb..d3c76a3 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 d4521f0..fa5bf56 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -21,6 +21,7 @@
 ## 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 2194126..2c03591 100644
--- a/test/video_source.h
+++ b/test/video_source.h
@@ -236,7 +236,6 @@
   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 @@
     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 aee27af..f7225bb 100644
--- a/test/vp8_datarate_test.cc
+++ b/test/vp8_datarate_test.cc
@@ -260,6 +260,27 @@
         << " 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 @@
   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 6ba171a..aeff0d7 100644
--- a/test/vp9_boolcoder_test.cc
+++ b/test/vp9_boolcoder_test.cc
@@ -53,7 +53,7 @@
         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 @@
           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, 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 049a10a..a5a18a7 100644
--- a/test/vp9_scale_test.cc
+++ b/test/vp9_scale_test.cc
@@ -48,12 +48,11 @@
   }
 
   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 0000000..3d24b23
--- /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 6ccb080..f7f5ebe 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 @@
     // 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 5c97394..e3960de 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 @@
     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 @@
       }
       /* 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 4e128e3..cb64aca 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 @@
   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 @@
   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 @@
 
   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 @@
       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 @@
       }
       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 @@
     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 @@
   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 @@
 
   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 fcd4eb0..7ba7a30 100644
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -791,8 +791,12 @@
               (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 @@
     /* 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 @@
       // 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 ca56d14..1b07b9a 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 @@
   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 @@
   }
 }
 
+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 @@
   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 @@
       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 @@
       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 @@
 
       // 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 @@
   // 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 @@
   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 @@
                         &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 @@
   }
 
   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 208651d..e367abc 100644
--- a/vp9/encoder/vp9_bitstream.h
+++ b/vp9/encoder/vp9_bitstream.h
@@ -35,7 +35,8 @@
 
 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 7ff5f00..e8f29d5 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 @@
   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 @@
     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 152d42b..42a2770 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -2134,24 +2134,22 @@
     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 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 @@
     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 @@
 }
 #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 @@
     // 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 @@
 
 #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 @@
 
       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 @@
 #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 @@
   }
 
   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 @@
 #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 @@
   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 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 @@
 }
 
 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 @@
 #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 @@
     // 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 7136f7f..141f342 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -338,6 +338,10 @@
 
   // 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 @@
                           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 0843cd9..10fbc92 100644
--- a/vp9/encoder/vp9_multi_thread.c
+++ b/vp9/encoder/vp9_multi_thread.c
@@ -54,16 +54,23 @@
 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 @@
   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 @@
 #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 @@
     }
   }
 #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 6452e34..44f52f9 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -2651,11 +2651,12 @@
 
   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 94506aa..628dc4f 100644
--- a/vp9/encoder/x86/vp9_frame_scale_ssse3.c
+++ b/vp9/encoder/x86/vp9_frame_scale_ssse3.c
@@ -886,14 +886,14 @@
       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 fd81bce..316205f 100644
--- a/vp9/ratectrl_rtc.cc
+++ b/vp9/ratectrl_rtc.cc
@@ -303,7 +303,9 @@
 
 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 2e6f9a4..9b78891 100644
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -498,6 +498,7 @@
 
   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 @@
   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 @@
         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 @@
                                 &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 @@
       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 d610a5e..94ecbf2 100644
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -263,6 +263,7 @@
   // 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 3a462c3..9532dff 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -1434,8 +1434,8 @@
       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 @@
         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 @@
       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 f9f0dd6..9a42c3f 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 @@
                                      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 @@
     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 @@
 
   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 @@
       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 @@
         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 @@
         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 1adc9b9..a0c16c3 100644
--- a/vpx/vpx_image.h
+++ b/vpx/vpx_image.h
@@ -132,10 +132,13 @@
  *                         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 @@
  *                             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 ee76bed..91dfebf 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 f686dc3..2dd57e5 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 5b41aa5..d3ef9bd 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 @@
   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 5f1ee69..daff331 100644
--- a/vpx_dsp/bitwriter.h
+++ b/vpx_dsp/bitwriter.h
@@ -29,12 +29,19 @@
   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 @@
   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 7a7e96f..b3a2490 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 3662cb6..3ee0e96 100644
--- a/vpx_dsp/bitwriter_buffer.h
+++ b/vpx_dsp/bitwriter_buffer.h
@@ -18,10 +18,24 @@
 #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 6cb4b70..c9d7518 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 e9d63f6..18087e2 100644
--- a/vpx_dsp/vpx_dsp_rtcd_defs.pl
+++ b/vpx_dsp/vpx_dsp_rtcd_defs.pl
@@ -744,7 +744,7 @@
 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 917ff0e..dfe45b6 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"